diff --git a/src/Cube.m b/src/Cube.m index de4f665..ac74a4f 100644 --- a/src/Cube.m +++ b/src/Cube.m @@ -3,7 +3,7 @@ #include "cube.h" #import "Command.h" -#import "DynamicEntity.h" +#import "Player.h" OF_APPLICATION_DELEGATE(Cube) @@ -216,6 +216,8 @@ VARP(minmillis, 0, 5, 1000); @autoreleasepool { [OFRunLoop.mainRunLoop runUntilDate:past]; + Player *player1 = Player.player1; + int millis = SDL_GetTicks() * gamespeed / 100; if (millis - lastmillis > 200) lastmillis = millis - 200; diff --git a/src/DynamicEntity.h b/src/DynamicEntity.h index ab28f79..270a19e 100644 --- a/src/DynamicEntity.h +++ b/src/DynamicEntity.h @@ -21,11 +21,8 @@ // bounding box size @property (nonatomic) float radius, eyeHeight, aboveEye; @property (nonatomic) int lastUpdate, lag, ping; -// sequence id for each respawn, used in damage test -@property (nonatomic) int lifeSequence; // one of CS_* below @property (nonatomic) int state; -@property (nonatomic) int frags; @property (nonatomic) int health, armour, armourType, quadMillis; @property (nonatomic) int gunSelect, gunWait; @property (nonatomic) int lastAction, lastAttackGun, lastMove; @@ -33,7 +30,7 @@ @property (nonatomic) bool attacking; // used by physics to signal ai @property (nonatomic) bool blocked, moving; -@property (copy, nonatomic) OFString *name, *team; +@property (copy, nonatomic) OFString *name; + (instancetype)entity; - (OFData *)dataBySerializing; diff --git a/src/DynamicEntity.m b/src/DynamicEntity.m index e335ba9..2d26fdd 100644 --- a/src/DynamicEntity.m +++ b/src/DynamicEntity.m @@ -3,6 +3,7 @@ #include "cube.h" #import "Monster.h" +#import "Player.h" struct dynent { OFVector3D origin, velocity; @@ -58,7 +59,7 @@ struct dynent { _eyeHeight = 3.2f; _aboveEye = 0.7f; _lastUpdate = lastmillis; - _name = _team = @""; + _name = @""; _state = CS_ALIVE; [self resetToSpawnState]; @@ -98,9 +99,7 @@ struct dynent { copy->_lastUpdate = _lastUpdate; copy->_lag = _lag; copy->_ping = _ping; - copy->_lifeSequence = _lifeSequence; copy->_state = _state; - copy->_frags = _frags; copy->_health = _health; copy->_armour = _armour; copy->_armourType = _armourType; @@ -118,7 +117,6 @@ struct dynent { copy->_blocked = _blocked; copy->_moving = _moving; copy->_name = [_name copy]; - copy->_team = [_team copy]; return copy; } @@ -150,9 +148,7 @@ struct dynent { .lastUpdate = _lastUpdate, .lag = _lag, .ping = _ping, - .lifeSequence = _lifeSequence, .state = _state, - .frags = _frags, .health = _health, .armour = _armour, .armourType = _armourType, @@ -166,6 +162,19 @@ struct dynent { .blocked = _blocked, .moving = _moving }; + for (int i = 0; i < NUMGUNS; i++) + data.ammo[i] = _ammo[i]; + + memcpy(data.name, _name.UTF8String, min(_name.UTF8StringLength, 259)); + + if ([self isKindOfClass:Player.class]) { + Player *player = (Player *)self; + data.lifeSequence = player.lifeSequence, + data.frags = player.frags; + memcpy(data.team, player.team.UTF8String, + min(player.team.UTF8StringLength, 259)); + } + if ([self isKindOfClass:Monster.class]) { Monster *monster = (Monster *)self; data.monsterState = monster.monsterState; @@ -176,12 +185,6 @@ struct dynent { data.anger = monster.anger; } - for (int i = 0; i < NUMGUNS; i++) - data.ammo[i] = _ammo[i]; - - memcpy(data.name, _name.UTF8String, min(_name.UTF8StringLength, 259)); - memcpy(data.team, _team.UTF8String, min(_team.UTF8StringLength, 259)); - return [OFData dataWithItems:&data count:sizeof(data)]; } @@ -217,9 +220,8 @@ struct dynent { _lastUpdate = d.lastUpdate; _lag = d.lag; _ping = d.ping; - _lifeSequence = d.lifeSequence; _state = d.state; - _frags = d.frags; + _health = d.health; _armour = d.armour; _armourType = d.armourType; @@ -237,6 +239,15 @@ struct dynent { _blocked = d.blocked; _moving = d.moving; + _name = [[OFString alloc] initWithUTF8String:d.name]; + + if ([self isKindOfClass:Player.class]) { + Player *player = (Player *)self; + player.lifeSequence = d.lifeSequence; + player.frags = d.frags; + player.team = @(d.team); + } + if ([self isKindOfClass:Monster.class]) { Monster *monster = (Monster *)self; monster.monsterState = d.monsterState; @@ -246,9 +257,6 @@ struct dynent { monster.attackTarget = d.attackTarget; monster.anger = d.anger; } - - _name = [[OFString alloc] initWithUTF8String:d.name]; - _team = [[OFString alloc] initWithUTF8String:d.team]; } - (void)resetMovement diff --git a/src/Monster.m b/src/Monster.m index 6f5562b..0b4ce02 100644 --- a/src/Monster.m +++ b/src/Monster.m @@ -4,8 +4,8 @@ #include "cube.h" -#import "DynamicEntity.h" #import "Entity.h" +#import "Player.h" static OFMutableArray *monsters; static int nextmonster, spawnremain, numkilled, monstertotal, mtimestart; @@ -101,7 +101,7 @@ monstertypes[NUMMONSTERTYPES] = { self.trigger = lastmillis + trigger; self.targetYaw = self.yaw = (float)yaw; self.move = move; - self.enemy = player1; + self.enemy = Player.player1; self.gunSelect = t->gun; self.maxSpeed = (float)t->speed; self.health = t->health; @@ -256,7 +256,7 @@ enemylos(Monster *m, OFVector3D *v) - (void)performAction { if (self.enemy.state == CS_DEAD) { - self.enemy = player1; + self.enemy = Player.player1; self.anger = 0; } [self normalizeWithAngle:self.targetYaw]; @@ -417,7 +417,7 @@ enemylos(Monster *m, OFVector3D *v) self.state = CS_DEAD; self.lastAction = lastmillis; numkilled++; - player1.frags = numkilled; + Player.player1.frags = numkilled; OFVector3D loc = self.origin; playsound(monstertypes[self.monsterType].diesound, &loc); int remain = monstertotal - numkilled; diff --git a/src/clientextras.m b/src/clientextras.m index c85dd56..0573d2b 100644 --- a/src/clientextras.m +++ b/src/clientextras.m @@ -3,8 +3,8 @@ #include "cube.h" #import "Command.h" -#import "DynamicEntity.h" #import "Monster.h" +#import "Player.h" // render players & monsters // very messy ad-hoc handling of animation frames, should be made more @@ -90,7 +90,7 @@ renderclients() if (player != [OFNull null] && (!demoplayback || i != democlientnum)) renderclient(player, - isteam(player1.team, [player team]), + isteam(Player.player1.team, [player team]), @"monster/ogro", false, 1.0f); }]; } @@ -108,8 +108,8 @@ showscores(bool on) static OFMutableArray *scoreLines; -void -renderscore(DynamicEntity *d) +static void +renderscore(Player *d) { OFString *lag = [OFString stringWithFormat:@"%d", d.lag]; OFString *name = [OFString stringWithFormat:@"(%@)", d.name]; @@ -131,8 +131,8 @@ static OFString *teamName[maxTeams]; static int teamScore[maxTeams]; static size_t teamsUsed; -void -addteamscore(DynamicEntity *d) +static void +addteamscore(Player *d) { for (size_t i = 0; i < teamsUsed; i++) { if ([teamName[i] isEqual:d.team]) { @@ -155,18 +155,18 @@ renderscores() return; [scoreLines removeAllObjects]; if (!demoplayback) - renderscore(player1); - for (id player in players) - if (player != [OFNull null]) + renderscore(Player.player1); + for (Player *player in players) + if ([player isKindOfClass:Player.class]) renderscore(player); sortmenu(); if (m_teammode) { teamsUsed = 0; - for (id player in players) - if (player != [OFNull null]) + for (Player *player in players) + if ([player isKindOfClass:Player.class]) addteamscore(player); if (!demoplayback) - addteamscore(player1); + addteamscore(Player.player1); OFMutableString *teamScores = [OFMutableString string]; for (size_t j = 0; j < teamsUsed; j++) [teamScores appendFormat:@"[ %@: %d ]", teamName[j], diff --git a/src/clientgame.m b/src/clientgame.m index 99ee8c5..30ed77e 100644 --- a/src/clientgame.m +++ b/src/clientgame.m @@ -7,6 +7,7 @@ #import "Entity.h" #import "Monster.h" #import "OFString+Cube.h" +#import "Player.h" int nextmode = 0; // nextmode becomes gamemode after next map load VAR(gamemode, 1, 0, 0); @@ -17,13 +18,11 @@ COMMAND(mode, ARG_1INT, ^(int n) { bool intermission = false; -DynamicEntity *player1; // our client OFMutableArray *players; // other clients void initPlayers() { - player1 = [[DynamicEntity alloc] init]; players = [[OFMutableArray alloc] init]; } @@ -44,13 +43,12 @@ getclientmap() void respawnself() { - spawnplayer(player1); + spawnplayer(Player.player1); showscores(false); } static void -arenacount( - DynamicEntity *d, int *alive, int *dead, OFString **lastteam, bool *oneteam) +arenacount(Player *d, int *alive, int *dead, OFString **lastteam, bool *oneteam) { if (d.state != CS_DEAD) { (*alive)++; @@ -82,7 +80,7 @@ arenarespawn() if (player != [OFNull null]) arenacount( player, &alive, &dead, &lastteam, &oneteam); - arenacount(player1, &alive, &dead, &lastteam, &oneteam); + arenacount(Player.player1, &alive, &dead, &lastteam, &oneteam); if (dead > 0 && (alive <= 1 || (m_teammode && oneteam))) { conoutf( @"arena round is over! next round in 5 seconds..."); @@ -93,7 +91,7 @@ arenarespawn() conoutf(@"everyone died!"); arenarespawnwait = lastmillis + 5000; arenadetectwait = lastmillis + 10000; - player1.roll = 0; + Player.player1.roll = 0; } } } @@ -103,28 +101,29 @@ extern int democlientnum; void otherplayers() { - [players enumerateObjectsUsingBlock:^(id player, size_t i, bool *stop) { - if (player == [OFNull null]) - return; + [players + enumerateObjectsUsingBlock:^(Player *player, size_t i, bool *stop) { + if ([player isKindOfClass:Player.class]) + return; - const int lagtime = lastmillis - [player lastUpdate]; - if (lagtime > 1000 && [player state] == CS_ALIVE) { - [player setState:CS_LAGGED]; - return; - } + const int lagtime = lastmillis - player.lastUpdate; + if (lagtime > 1000 && player.state == CS_ALIVE) { + player.state = CS_LAGGED; + return; + } - if (lagtime && [player state] != CS_DEAD && - (!demoplayback || i != democlientnum)) - // use physics to extrapolate player position - moveplayer(player, 2, false); - }]; + if (lagtime && player.state != CS_DEAD && + (!demoplayback || i != democlientnum)) + // use physics to extrapolate player position + moveplayer(player, 2, false); + }]; } void respawn() { - if (player1.state == CS_DEAD) { - player1.attacking = false; + if (Player.player1.state == CS_DEAD) { + Player.player1.attacking = false; if (m_arena) { conoutf(@"waiting for new round to start..."); return; @@ -160,6 +159,7 @@ updateworld(int millis) // main game update loop arenarespawn(); moveprojectiles((float)curtime); demoplaybackstep(); + Player *player1 = Player.player1; if (!demoplayback) { if (getclientnum() >= 0) // only shoot when connected to server @@ -171,6 +171,7 @@ updateworld(int millis) // main game update loop otherplayers(); if (!demoplayback) { [Monster thinkAll]; + if (player1.state == CS_DEAD) { if (lastmillis - player1.lastAction < 2000) { player1.move = player1.strafe = 0; @@ -182,6 +183,7 @@ updateworld(int millis) // main game update loop moveplayer(player1, 20, true); checkitems(); } + // do this last, to reduce the effective frame lag c2sinfo(player1); } @@ -213,7 +215,7 @@ int fixspawn = 2; // place at random spawn. also used by monsters! void -spawnplayer(DynamicEntity *d) +spawnplayer(Player *d) { int r = fixspawn-- > 0 ? 4 : rnd(10) + 1; for (int i = 0; i < r; i++) @@ -236,6 +238,7 @@ spawnplayer(DynamicEntity *d) #define dir(name, v, d, s, os) \ COMMAND(name, ARG_DOWN, ^(bool isDown) { \ + Player *player1 = Player.player1; \ player1.s = isDown; \ player1.v = isDown ? d : (player1.os ? -(d) : 0); \ player1.lastMove = lastmillis; \ @@ -251,12 +254,12 @@ COMMAND(attack, ARG_DOWN, ^(bool on) { return; if (editmode) editdrag(on); - else if ((player1.attacking = on)) + else if ((Player.player1.attacking = on)) respawn(); }) COMMAND(jump, ARG_DOWN, ^(bool on) { - if (!intermission && (player1.jumpNext = on)) + if (!intermission && (Player.player1.jumpNext = on)) respawn(); }) @@ -268,6 +271,7 @@ void fixplayer1range() { const float MAXPITCH = 90.0f; + Player *player1 = Player.player1; if (player1.pitch > MAXPITCH) player1.pitch = MAXPITCH; if (player1.pitch < -MAXPITCH) @@ -281,6 +285,7 @@ fixplayer1range() void mousemove(int dx, int dy) { + Player *player1 = Player.player1; if (player1.state == CS_DEAD || intermission) return; const float SENSF = 33.0f; // try match quake sens @@ -295,14 +300,15 @@ mousemove(int dx, int dy) void selfdamage(int damage, int actor, DynamicEntity *act) { + Player *player1 = Player.player1; if (player1.state != CS_ALIVE || editmode || intermission) return; damageblend(damage); demoblend(damage); // let armour absorb when possible int ad = damage * (player1.armourType + 1) * 20 / 100; - if (ad > player1.armour) - ad = player1.armour; + if (ad > Player.player1.armour) + ad = Player.player1.armour; player1.armour -= ad; damage -= ad; float droll = damage / 0.5f; @@ -321,7 +327,7 @@ selfdamage(int damage, int actor, DynamicEntity *act) conoutf(@"you suicided!"); addmsg(1, 2, SV_FRAGS, --player1.frags); } else { - DynamicEntity *a = getclient(actor); + Player *a = getclient(actor); if (a != nil) { if (isteam(a.team, player1.team)) conoutf(@"you got fragged by a " @@ -351,7 +357,7 @@ timeupdate(int timeremain) { if (!timeremain) { intermission = true; - player1.attacking = false; + Player.player1.attacking = false; conoutf(@"intermission:"); conoutf(@"game has ended!"); showscores(true); @@ -360,7 +366,7 @@ timeupdate(int timeremain) } } -DynamicEntity * +Player * getclient(int cn) // ensure valid entity { if (cn < 0 || cn >= MAXCLIENTS) { @@ -373,7 +379,7 @@ getclient(int cn) // ensure valid entity id player = players[cn]; if (player == [OFNull null]) { - player = [DynamicEntity entity]; + player = [Player player]; players[cn] = player; } @@ -408,8 +414,8 @@ startmap(OFString *name) // called just after a map load [Monster resetAll]; projreset(); spawncycle = -1; - spawnplayer(player1); - player1.frags = 0; + spawnplayer(Player.player1); + Player.player1.frags = 0; for (id player in players) if (player != [OFNull null]) [player setFrags:0]; diff --git a/src/clients.m b/src/clients.m index f52e08c..e6bd9bf 100644 --- a/src/clients.m +++ b/src/clients.m @@ -3,7 +3,7 @@ #include "cube.h" #import "Command.h" -#import "DynamicEntity.h" +#import "Player.h" static ENetHost *clienthost = NULL; static int connecting = 0; @@ -69,7 +69,7 @@ newname(OFString *name) if (name.length > 16) name = [name substringToIndex:16]; - player1.name = name; + Player.player1.name = name; } COMMAND(name, ARG_1STR, ^(OFString *name) { @@ -84,7 +84,7 @@ newteam(OFString *name) if (name.length > 5) name = [name substringToIndex:5]; - player1.team = name; + Player.player1.team = name; } COMMAND(team, ARG_1STR, ^(OFString *name) { @@ -94,8 +94,8 @@ COMMAND(team, ARG_1STR, ^(OFString *name) { void writeclientinfo(OFStream *stream) { - [stream writeFormat:@"name \"%@\"\nteam \"%@\"\n", player1.name, - player1.team]; + [stream writeFormat:@"name \"%@\"\nteam \"%@\"\n", Player.player1.name, + Player.player1.team]; } void @@ -149,7 +149,7 @@ disconnect(bool onlyclean, bool async) disconnecting = 0; clientnum = -1; c2sinit = false; - player1.lifeSequence = 0; + Player.player1.lifeSequence = 0; [players removeAllObjects]; localdisconnect(); @@ -180,7 +180,7 @@ static OFString *ctext; void toserver(OFString *text) { - conoutf(@"%@:\f %@", player1.name, text); + conoutf(@"%@:\f %@", Player.player1.name, text); ctext = text; } @@ -281,7 +281,7 @@ sendpackettoserv(void *packet) // send update to the server void -c2sinfo(DynamicEntity *d) +c2sinfo(Player *d) { if (clientnum < 0) return; // we haven't had a welcome message from the server yet @@ -342,9 +342,9 @@ c2sinfo(DynamicEntity *d) packet->flags = ENET_PACKET_FLAG_RELIABLE; c2sinit = true; putint(&p, SV_INITC2S); - sendstring(player1.name, &p); - sendstring(player1.team, &p); - putint(&p, player1.lifeSequence); + sendstring(Player.player1.name, &p); + sendstring(Player.player1.team, &p); + putint(&p, Player.player1.lifeSequence); } for (OFData *msg in messages) { // send messages collected during the previous frames diff --git a/src/clients2c.m b/src/clients2c.m index 5671d7b..d08e1a9 100644 --- a/src/clients2c.m +++ b/src/clients2c.m @@ -4,6 +4,7 @@ #import "DynamicEntity.h" #import "Entity.h" +#import "Player.h" extern int clientnum; extern bool c2sinit, senditemstoserver; @@ -37,6 +38,7 @@ changemap(OFString *name) // request map change, server may ignore void updatepos(DynamicEntity *d) { + Player *player1 = Player.player1; const float r = player1.radius + d.radius; const float dx = player1.origin.x - d.origin.x; const float dy = player1.origin.y - d.origin.y; @@ -182,12 +184,13 @@ localservertoclient(unsigned char *buf, int len) // another client either connected or changed name/team case SV_INITC2S: { + Player *d_ = (Player *)d; sgetstr(); - if (d.name.length > 0) { + if (d_.name.length > 0) { // already connected - if (![d.name isEqual:@(text)]) + if (![d_.name isEqual:@(text)]) conoutf(@"%@ is now known as %s", - d.name, text); + d_.name, text); } else { // new client @@ -195,10 +198,10 @@ localservertoclient(unsigned char *buf, int len) c2sinit = false; conoutf(@"connected: %s", text); } - d.name = @(text); + d_.name = @(text); sgetstr(); - d.team = @(text); - d.lifeSequence = getint(&p); + d_.team = @(text); + d_.lifeSequence = getint(&p); break; } @@ -231,7 +234,7 @@ localservertoclient(unsigned char *buf, int len) int damage = getint(&p); int ls = getint(&p); if (target == clientnum) { - if (ls == player1.lifeSequence) + if (ls == Player.player1.lifeSequence) selfdamage(damage, cn, d); } else { OFVector3D loc = getclient(target).origin; @@ -241,23 +244,24 @@ localservertoclient(unsigned char *buf, int len) } case SV_DIED: { + Player *d_ = (Player *)d; int actor = getint(&p); if (actor == cn) { - conoutf(@"%@ suicided", d.name); + conoutf(@"%@ suicided", d_.name); } else if (actor == clientnum) { int frags; - if (isteam(player1.team, d.team)) { + if (isteam(Player.player1.team, d_.team)) { frags = -1; conoutf(@"you fragged a teammate (%@)", - d.name); + d_.name); } else { frags = 1; - conoutf(@"you fragged %@", d.name); + conoutf(@"you fragged %@", d_.name); } - addmsg( - 1, 2, SV_FRAGS, (player1.frags += frags)); + addmsg(1, 2, SV_FRAGS, + (Player.player1.frags += frags)); } else { - DynamicEntity *a = getclient(actor); + Player *a = getclient(actor); if (a != nil) { if (isteam(a.team, d.name)) conoutf(@"%@ fragged his " @@ -268,9 +272,9 @@ localservertoclient(unsigned char *buf, int len) a.name, d.name); } } - OFVector3D loc = d.origin; + OFVector3D loc = d_.origin; playsound(S_DIE1 + rnd(2), &loc); - d.lifeSequence++; + d_.lifeSequence++; break; } @@ -295,7 +299,7 @@ localservertoclient(unsigned char *buf, int len) } // server acknowledges that I picked up this item case SV_ITEMACC: - realpickup(getint(&p), player1); + realpickup(getint(&p), Player.player1); break; case SV_EDITH: // coop editing messages, should be extended to @@ -361,8 +365,8 @@ localservertoclient(unsigned char *buf, int len) case SV_PONG: addmsg(0, 2, SV_CLIENTPING, - player1.ping = - (player1.ping * 5 + lastmillis - getint(&p)) / + Player.player1.ping = (Player.player1.ping * 5 + + lastmillis - getint(&p)) / 6); break; diff --git a/src/cube.h b/src/cube.h index 6c7d618..8adaf64 100644 --- a/src/cube.h +++ b/src/cube.h @@ -8,8 +8,9 @@ #define _MAXDEFSTR 260 -@class Entity; @class DynamicEntity; +@class Entity; +@class Player; @interface Cube: OFObject @property (class, readonly, nonatomic) Cube *sharedInstance; @@ -256,8 +257,6 @@ extern struct sqr *world, *wmip[]; extern struct header hdr; // current map header extern int sfactor, ssize; // ssize = 2^sfactor extern int cubicsize, mipsize; // cubicsize = ssize^2 -// special client ent that receives input and acts as camera -extern DynamicEntity *player1; // all the other clients (in multiplayer) extern OFMutableArray *players; extern bool editmode; diff --git a/src/editing.m b/src/editing.m index 52df707..5a69c6d 100644 --- a/src/editing.m +++ b/src/editing.m @@ -7,6 +7,7 @@ #import "DynamicEntity.h" #import "Monster.h" #import "OFString+Cube.h" +#import "Player.h" bool editmode = false; @@ -58,6 +59,7 @@ VAR(editing, 0, 0, 1); void toggleedit() { + Player *player1 = Player.player1; if (player1.state == CS_DEAD) return; // do not allow dead players to edit to avoid state // confusion @@ -157,6 +159,7 @@ sheight(struct sqr *s, struct sqr *t, float z) void cursorupdate() // called every frame from hud { + Player *player1 = Player.player1; flrceil = ((int)(player1.pitch >= 0)) * 2; volatile float x = @@ -626,7 +629,7 @@ COMMAND(newent, ARG_5STR, ^(OFString *what, OFString *a1, OFString *a2, OFString *a3, OFString *a4) { EDITSEL; - newentity(sel.x, sel.y, (int)player1.origin.z, what, + newentity(sel.x, sel.y, (int)Player.player1.origin.z, what, [a1 cube_intValueWithBase:0], [a2 cube_intValueWithBase:0], [a3 cube_intValueWithBase:0], [a4 cube_intValueWithBase:0]); }) diff --git a/src/entities.m b/src/entities.m index d17ac1a..0f4cbcf 100644 --- a/src/entities.m +++ b/src/entities.m @@ -5,6 +5,7 @@ #import "DynamicEntity.h" #import "Entity.h" #import "MapModelInfo.h" +#import "Player.h" OFMutableArray *ents; @@ -128,7 +129,7 @@ struct itemstat { void baseammo(int gun) { - player1.ammo[gun] = itemstats[gun - 1].add * 2; + Player.player1.ammo[gun] = itemstats[gun - 1].add * 2; } // these two functions are called when the server acknowledges that you really @@ -147,7 +148,7 @@ radditem(int i, int v) } void -realpickup(int n, DynamicEntity *d) +realpickup(int n, Player *d) { switch (ents[n].type) { case I_SHELLS: @@ -294,6 +295,7 @@ pickup(int n, DynamicEntity *d) lastjumppad = lastmillis; OFVector3D v = OFMakeVector3D((int)(char)ents[n].attr3 / 10.0f, (int)(char)ents[n].attr2 / 10.0f, ents[n].attr1 / 10.0f); + Player *player1 = Player.player1; player1.velocity = OFAddVectors3D( OFMakeVector3D(player1.velocity.x, player1.velocity.y, 0), v); @@ -306,6 +308,8 @@ pickup(int n, DynamicEntity *d) void checkitems() { + Player *player1 = Player.player1; + if (editmode) return; @@ -331,6 +335,8 @@ checkitems() void checkquad(int time) { + Player *player1 = Player.player1; + if (player1.quadMillis && (player1.quadMillis -= time) < 0) { player1.quadMillis = 0; playsoundc(S_PUPOUT); diff --git a/src/menus.m b/src/menus.m index 5fe141a..0c7a2c9 100644 --- a/src/menus.m +++ b/src/menus.m @@ -5,8 +5,8 @@ #import "Menu.h" #import "Command.h" -#import "DynamicEntity.h" #import "MenuItem.h" +#import "Player.h" static OFMutableArray *menuStack; static OFMutableArray *menus; @@ -16,7 +16,7 @@ void menuset(int menu) { if ((vmenu = menu) >= 1) - [player1 resetMovement]; + [Player.player1 resetMovement]; if (vmenu == 1) menus[1].menusel = 0; } diff --git a/src/meson.build b/src/meson.build index bb4cc62..41af4e3 100644 --- a/src/meson.build +++ b/src/meson.build @@ -15,6 +15,7 @@ executable('client', 'MenuItem.m', 'Monster.m', 'OFString+Cube.m', + 'Player.m', 'Projectile.m', 'ResolverResult.m', 'ResolverThread.m', diff --git a/src/physics.m b/src/physics.m index c20069f..1db3d84 100644 --- a/src/physics.m +++ b/src/physics.m @@ -10,6 +10,7 @@ #import "Entity.h" #import "MapModelInfo.h" #import "Monster.h" +#import "Player.h" // collide with player or monster static bool @@ -179,8 +180,8 @@ collide(DynamicEntity *d, bool spawn, float drop, float rise) return false; } - if (d != player1) - if (!plcollide(d, player1, &headspace, &hi, &lo)) + if (d != Player.player1) + if (!plcollide(d, Player.player1, &headspace, &hi, &lo)) return false; // this loop can be a performance bottleneck with many monster on a slow diff --git a/src/protos.h b/src/protos.h index 872098e..a786c88 100644 --- a/src/protos.h +++ b/src/protos.h @@ -82,7 +82,7 @@ extern bool multiplayer(); extern bool allowedittoggle(); extern void sendpackettoserv(void *packet); extern void gets2c(); -extern void c2sinfo(DynamicEntity *d); +extern void c2sinfo(Player *d); extern void neterr(OFString *s); extern void initclientnet(); extern bool netmapstart(); @@ -101,7 +101,7 @@ extern void spawnplayer(DynamicEntity *d); extern void selfdamage(int damage, int actor, DynamicEntity *act); extern OFString *getclientmap(); extern OFString *modestr(int n); -extern DynamicEntity *getclient(int cn); +extern Player *getclient(int cn); extern void setclient(int cn, id client); extern void timeupdate(int timeremain); extern void fixplayer1range(); @@ -255,7 +255,7 @@ extern void renderents(); extern void putitems(unsigned char **p); extern void checkquad(int time); extern void checkitems(); -extern void realpickup(int n, DynamicEntity *d); +extern void realpickup(int n, Player *d); extern void renderentities(); extern void resetspawns(); extern void setspawn(size_t i, bool on); diff --git a/src/renderextras.m b/src/renderextras.m index 25cf542..55e4af1 100644 --- a/src/renderextras.m +++ b/src/renderextras.m @@ -3,8 +3,8 @@ #include "cube.h" #import "Command.h" -#import "DynamicEntity.h" #import "Entity.h" +#import "Player.h" void line(int x1, int y1, float z1, int x2, int y2, float z2) @@ -327,6 +327,8 @@ VARP(crosshairfx, 0, 1, 1); void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwater) { + Player *player1 = Player.player1; + readmatrices(); if (editmode) { if (cursordepth == 1.0f) diff --git a/src/rendergl.m b/src/rendergl.m index 1e65b73..b9c001a 100644 --- a/src/rendergl.m +++ b/src/rendergl.m @@ -5,9 +5,9 @@ #include "cube.h" #import "Command.h" -#import "DynamicEntity.h" #import "Monster.h" #import "OFString+Cube.h" +#import "Player.h" #ifdef DARWIN # define GL_COMBINE_EXT GL_COMBINE_ARB @@ -345,6 +345,8 @@ VARFP(gamma, 30, 100, 300, { void transplayer() { + Player *player1 = Player.player1; + glLoadIdentity(); glRotated(player1.roll, 0.0, 0.0, 1.0); @@ -372,6 +374,8 @@ OFString *hudgunnames[] = { @"hudguns/fist", @"hudguns/shotg", void drawhudmodel(int start, int end, float speed, int base) { + Player *player1 = Player.player1; + rendermodel(hudgunnames[player1.gunSelect], start, end, 0, 1.0f, OFMakeVector3D( player1.origin.x, player1.origin.z, player1.origin.y), @@ -381,6 +385,8 @@ drawhudmodel(int start, int end, float speed, int base) void drawhudgun(float fovy, float aspect, int farplane) { + Player *player1 = Player.player1; + if (!hudgun /*|| !player1.gunSelect*/) return; @@ -410,6 +416,7 @@ drawhudgun(float fovy, float aspect, int farplane) void gl_drawframe(int w, int h, float curfps) { + Player *player1 = Player.player1; float hf = hdr.waterlevel - 0.3f; float fovy = (float)fov * h / w; float aspect = w / (float)h; diff --git a/src/rendermd2.m b/src/rendermd2.m index 7297fc7..217559b 100644 --- a/src/rendermd2.m +++ b/src/rendermd2.m @@ -3,10 +3,10 @@ #include "cube.h" #import "Command.h" -#import "DynamicEntity.h" #import "MD2.h" #import "MapModelInfo.h" #import "OFString+Cube.h" +#import "Player.h" static OFMutableDictionary *mdllookup = nil; static OFMutableArray *mapmodels = nil; @@ -90,8 +90,8 @@ rendermodel(OFString *mdl, int frame, int range, int tex, float rad, { MD2 *m = loadmodel(mdl); - if (isoccluded(player1.origin.x, player1.origin.y, position.x - rad, - position.z - rad, rad * 2)) + if (isoccluded(Player.player1.origin.x, Player.player1.origin.y, + position.x - rad, position.z - rad, rad * 2)) return; delayedload(m); diff --git a/src/renderparticles.m b/src/renderparticles.m index 7b0f17c..55b18e7 100644 --- a/src/renderparticles.m +++ b/src/renderparticles.m @@ -2,7 +2,7 @@ #include "cube.h" -#import "DynamicEntity.h" +#import "Player.h" #define MAXPARTICLES 10500 const int NUMPARTCUTOFF = 20; @@ -56,8 +56,8 @@ void render_particles(int time) { if (demoplayback && demotracking) - newparticle( - player1.origin, OFMakeVector3D(0, 0, 0), 100000000, 8); + newparticle(Player.player1.origin, OFMakeVector3D(0, 0, 0), + 100000000, 8); glDepthMask(GL_FALSE); glEnable(GL_BLEND); diff --git a/src/savegamedemo.m b/src/savegamedemo.m index 2cce810..75f7272 100644 --- a/src/savegamedemo.m +++ b/src/savegamedemo.m @@ -4,9 +4,9 @@ #include "cube.h" #import "Command.h" -#import "DynamicEntity.h" #import "Entity.h" #import "Monster.h" +#import "Player.h" #ifdef OF_BIG_ENDIAN static const int islittleendian = 0; @@ -18,7 +18,7 @@ static gzFile f = NULL; bool demorecording = false; bool demoplayback = false; bool demoloading = false; -static OFMutableArray *playerhistory; +static OFMutableArray *playerhistory; int democlientnum = 0; extern void startdemo(); @@ -105,7 +105,7 @@ savestate(OFIRI *IRI) gzwrite(f, (void *)"CUBESAVE", 8); gzputc(f, islittleendian); gzputi(SAVEGAMEVERSION); - OFData *data = [player1 dataBySerializing]; + OFData *data = [Player.player1 dataBySerializing]; gzputi(data.count); char map[_MAXDEFSTR] = { 0 }; memcpy(map, getclientmap().UTF8String, @@ -219,8 +219,8 @@ loadgamerest() [OFMutableData dataWithCapacity:DynamicEntity.serializedSize]; [data increaseCountBy:DynamicEntity.serializedSize]; gzread(f, data.mutableItems, data.count); - [player1 setFromSerializedData:data]; - player1.lastAction = lastmillis; + [Player.player1 setFromSerializedData:data]; + Player.player1.lastAction = lastmillis; int nmonsters = gzgeti(); OFArray *monsters = Monster.monsters; @@ -231,7 +231,7 @@ loadgamerest() gzread(f, data.mutableItems, data.count); [monster setFromSerializedData:data]; // lazy, could save id of enemy instead - monster.enemy = player1; + monster.enemy = Player.player1; // also lazy, but no real noticable effect on game monster.lastAction = monster.trigger = lastmillis + 500; if (monster.state == CS_DEAD) @@ -242,7 +242,7 @@ loadgamerest() int nplayers = gzgeti(); for (int i = 0; i < nplayers; i++) { if (!gzget()) { - DynamicEntity *d = getclient(i); + Player *d = getclient(i); assert(d); gzread(f, data.mutableItems, data.count); [d setFromSerializedData:data]; @@ -300,8 +300,11 @@ demoblend(int damage) void incomingdemodata(unsigned char *buf, int len, bool extras) { + Player *player1 = Player.player1; + if (!demorecording) return; + gzputi(lastmillis - starttime); gzputi(len); gzwrite(f, buf, len); @@ -370,7 +373,7 @@ startdemo() demoplayback = true; starttime = lastmillis; conoutf(@"now playing demo"); - setclient(democlientnum, [player1 copy]); + setclient(democlientnum, [Player.player1 copy]); readdemotime(); } @@ -421,7 +424,7 @@ demoplaybackstep() gzread(f, buf, len); localservertoclient(buf, len); // update game state - DynamicEntity *target = players[democlientnum]; + Player *target = players[democlientnum]; assert(target); int extras; @@ -452,7 +455,7 @@ demoplaybackstep() if (extras && (playerhistory.count == 0 || playerhistory.lastObject.lastUpdate != playbacktime)) { - DynamicEntity *d = [target copy]; + Player *d = [target copy]; d.lastUpdate = playbacktime; if (playerhistory == nil) @@ -475,13 +478,13 @@ demoplaybackstep() size_t count = playerhistory.count; for (ssize_t i = count - 1; i >= 0; i--) { if (playerhistory[i].lastUpdate < itime) { - DynamicEntity *a = playerhistory[i]; - DynamicEntity *b = a; + Player *a = playerhistory[i]; + Player *b = a; if (i + 1 < playerhistory.count) b = playerhistory[i + 1]; - player1 = b; + Player.player1 = b; // interpolate pos & angles if (a != b) { DynamicEntity *c = b; @@ -494,15 +497,15 @@ demoplaybackstep() // printf("* %d\n", lastmillis); float bf = (itime - a.lastUpdate) / (float)(b.lastUpdate - a.lastUpdate); - fixwrap(a, player1); - fixwrap(c, player1); - fixwrap(z, player1); + fixwrap(a, b); + fixwrap(c, b); + fixwrap(z, b); float dist = OFDistanceOfVectors3D(c.origin, z.origin); // if teleport or spawn, don't interpolate if (dist < 16) { catmulrom(z.origin, a.origin, b.origin, - c.origin, bf, player1.origin); + c.origin, bf, b.origin); OFVector3D vz = OFMakeVector3D( z.yaw, z.pitch, z.roll); OFVector3D va = OFMakeVector3D( @@ -511,9 +514,8 @@ demoplaybackstep() b.yaw, b.pitch, b.roll); OFVector3D vc = OFMakeVector3D( c.yaw, c.pitch, c.roll); - OFVector3D vp1 = - OFMakeVector3D(player1.yaw, - player1.pitch, player1.roll); + OFVector3D vp1 = OFMakeVector3D( + b.yaw, b.pitch, b.roll); catmulrom(vz, va, vb, vc, bf, vp1); z.yaw = vz.x; z.pitch = vz.y; @@ -527,9 +529,9 @@ demoplaybackstep() c.yaw = vc.x; c.pitch = vc.y; c.roll = vc.z; - player1.yaw = vp1.x; - player1.pitch = vp1.y; - player1.roll = vp1.z; + b.yaw = vp1.x; + b.pitch = vp1.y; + b.roll = vp1.z; } fixplayer1range(); } diff --git a/src/sound.m b/src/sound.m index a86b217..03ff3dc 100644 --- a/src/sound.m +++ b/src/sound.m @@ -1,7 +1,7 @@ #include "cube.h" #import "Command.h" -#import "DynamicEntity.h" +#import "Player.h" #include @@ -113,7 +113,7 @@ updatechanvol(int chan, const OFVector3D *loc) int vol = soundvol, pan = 255 / 2; if (loc) { - OFVector3D origin = player1.origin; + OFVector3D origin = Player.player1.origin; float dist = OFDistanceOfVectors3D(origin, *loc); OFVector3D v = OFSubtractVectors3D(origin, *loc); @@ -122,8 +122,8 @@ updatechanvol(int chan, const OFVector3D *loc) if (stereo && (v.x != 0 || v.y != 0)) { // relative angle of sound along X-Y axis - float yaw = - -atan2(v.x, v.y) - player1.yaw * (PI / 180.0f); + float yaw = -atan2(v.x, v.y) - + Player.player1.yaw * (PI / 180.0f); // range is from 0 (left) to 255 (right) pan = (int)(255.9f * (0.5 * sin(yaw) + 0.5f)); } diff --git a/src/weapon.m b/src/weapon.m index a3f6382..ffc9375 100644 --- a/src/weapon.m +++ b/src/weapon.m @@ -6,6 +6,7 @@ #import "DynamicEntity.h" #import "Monster.h" #import "OFString+Cube.h" +#import "Player.h" #import "Projectile.h" static const int MONSTERDAMAGEFACTOR = 4; @@ -34,6 +35,8 @@ selectgun(int a, int b, int c) if (a < -1 || b < -1 || c < -1 || a >= NUMGUNS || b >= NUMGUNS || c >= NUMGUNS) return; + + Player *player1 = Player.player1; int s = player1.gunSelect; if (a >= 0 && s != a && player1.ammo[a]) s = a; @@ -112,11 +115,11 @@ playerincrosshair() if (demoplayback) return NULL; - for (id player in players) { - if (player == [OFNull null]) + OFVector3D o = Player.player1.origin; + for (Player *player in players) { + if (![Player isKindOfClass:Player.class]) continue; - OFVector3D o = player1.origin; if (intersect(player, o, worldpos)) return [player name]; } @@ -162,12 +165,13 @@ static void hit(int target, int damage, __kindof DynamicEntity *d, DynamicEntity *at) { OFVector3D o = d.origin; - if (d == player1) - selfdamage(damage, at == player1 ? -1 : -2, at); + if (d == Player.player1) + selfdamage(damage, (at == Player.player1) ? -1 : -2, at); else if ([d isKindOfClass:Monster.class]) [d incurDamage:damage fromEntity:at]; - else { - addmsg(1, 4, SV_DAMAGE, target, damage, d.lifeSequence); + else if ([d isKindOfClass:Player.class]) { + addmsg(1, 4, SV_DAMAGE, target, damage, + ((Player *)d).lifeSequence); playsound(S_PAIN1 + rnd(5), &o); } particle_splash(3, damage, 1000, o); @@ -219,7 +223,7 @@ splash(Projectile *p, OFVector3D v, OFVector3D vold, int notthisplayer, if (!p.local) return; - radialeffect(player1, v, -1, qdam, p.owner); + radialeffect(Player.player1, v, -1, qdam, p.owner); [players enumerateObjectsUsingBlock:^( id player, size_t i, bool *stop) { @@ -279,8 +283,8 @@ moveprojectiles(float time) if (player != [OFNull null]) projdamage(player, p, v, i, -1, qdam); - if (p.owner != player1) - projdamage(player1, p, v, -1, -1, qdam); + if (p.owner != Player.player1) + projdamage(Player.player1, p, v, -1, -1, qdam); for (Monster *monster in Monster.monsters) if (!vreject(monster.origin, v, 10.0f) && @@ -310,7 +314,7 @@ void shootv(int gun, OFVector3D from, OFVector3D to, DynamicEntity *d, bool local) { OFVector3D loc = d.origin; - playsound(guns[gun].sound, d == player1 ? NULL : &loc); + playsound(guns[gun].sound, (d == Player.player1) ? NULL : &loc); int pspeed = 25; switch (gun) { case GUN_FIST: @@ -438,5 +442,5 @@ shoot(DynamicEntity *d, OFVector3D targ) raydamage(monster, from, to, d, -2); if ([d isKindOfClass:Monster.class]) - raydamage(player1, from, to, d, -1); + raydamage(Player.player1, from, to, d, -1); } diff --git a/src/world.m b/src/world.m index f336ed3..592efc7 100644 --- a/src/world.m +++ b/src/world.m @@ -3,9 +3,9 @@ #include "cube.h" #import "Command.h" -#import "DynamicEntity.h" #import "Entity.h" #import "Monster.h" +#import "Player.h" extern OFString *entnames[]; // lookup from map entities above to strings @@ -298,7 +298,7 @@ closestent() // used for delent and edit mode ent display return; OFVector3D v = OFMakeVector3D(e.x, e.y, e.z); - float dist = OFDistanceOfVectors3D(v, player1.origin); + float dist = OFDistanceOfVectors3D(v, Player.player1.origin); if (dist < bdist) { best = i; bdist = dist; @@ -383,7 +383,7 @@ newentity(int x, int y, int z, OFString *what, int v1, int v2, int v3, int v4) case TELEDEST: e.attr2 = (unsigned char)e.attr1; case PLAYERSTART: - e.attr1 = (int)player1.yaw; + e.attr1 = (int)Player.player1.yaw; break; } addmsg(1, 10, SV_EDITENT, ents.count, type, e.x, e.y, e.z, e.attr1, diff --git a/src/worldocull.m b/src/worldocull.m index 3e0f6b9..0ef69fa 100644 --- a/src/worldocull.m +++ b/src/worldocull.m @@ -3,7 +3,7 @@ #include "cube.h" #import "Command.h" -#import "DynamicEntity.h" +#import "Player.h" #define NUMRAYS 512 @@ -21,6 +21,8 @@ COMMAND(toggleocull, ARG_NONE, ^{ void computeraytable(float vx, float vy) { + Player *player1 = Player.player1; + if (!ocull) return; diff --git a/src/worldrender.m b/src/worldrender.m index 3dd2089..69d87b1 100644 --- a/src/worldrender.m +++ b/src/worldrender.m @@ -4,7 +4,7 @@ #include "cube.h" -#import "DynamicEntity.h" +#import "Player.h" void render_wall(struct sqr *o, struct sqr *s, int x1, int y1, int x2, int y2, @@ -133,6 +133,7 @@ render_seg_new( int ry = vyy + lodbot; float fsize = (float)(1 << mip); + Player *player1 = Player.player1; for (int ox = x; ox < xs; ox++) { // first collect occlusion information for this block for (int oy = y; oy < ys; oy++) {