Index: src/Cube.m ================================================================== --- src/Cube.m +++ src/Cube.m @@ -1,11 +1,11 @@ // main.cpp: initialisation & main loop #include "cube.h" #import "Command.h" -#import "DynamicEntity.h" +#import "Player.h" OF_APPLICATION_DELEGATE(Cube) VARF(gamespeed, 10, 100, 1000, if (multiplayer()) gamespeed = 100); VARP(minmillis, 0, 5, 1000); @@ -213,10 +213,12 @@ OFDate *past = [OFDate date]; int ignore = 5; for (;;) { @autoreleasepool { [OFRunLoop.mainRunLoop runUntilDate:past]; + + Player *player1 = Player.player1; int millis = SDL_GetTicks() * gamespeed / 100; if (millis - lastmillis > 200) lastmillis = millis - 200; else if (millis - lastmillis < 1) Index: src/DynamicEntity.h ================================================================== --- src/DynamicEntity.h +++ src/DynamicEntity.h @@ -19,23 +19,20 @@ // used for fake gravity @property (nonatomic) int timeInAir; // 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; @property (readonly, nonatomic) int *ammo; @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; - (void)setFromSerializedData:(OFData *)data; - (void)resetMovement; Index: src/DynamicEntity.m ================================================================== --- src/DynamicEntity.m +++ src/DynamicEntity.m @@ -1,10 +1,11 @@ #import "DynamicEntity.h" #include "cube.h" #import "Monster.h" +#import "Player.h" struct dynent { OFVector3D origin, velocity; float yaw, pitch, roll; float maxSpeed; @@ -56,11 +57,11 @@ _maxSpeed = 22; _radius = 1.1f; _eyeHeight = 3.2f; _aboveEye = 0.7f; _lastUpdate = lastmillis; - _name = _team = @""; + _name = @""; _state = CS_ALIVE; [self resetToSpawnState]; return self; @@ -96,13 +97,11 @@ copy->_eyeHeight = _eyeHeight; copy->_aboveEye = _aboveEye; 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; copy->_quadMillis = _quadMillis; copy->_gunSelect = _gunSelect; @@ -116,11 +115,10 @@ copy->_ammo[i] = _ammo[i]; copy->_blocked = _blocked; copy->_moving = _moving; copy->_name = [_name copy]; - copy->_team = [_team copy]; return copy; } - (OFData *)dataBySerializing @@ -148,13 +146,11 @@ .eyeHeight = _eyeHeight, .aboveEye = _aboveEye, .lastUpdate = _lastUpdate, .lag = _lag, .ping = _ping, - .lifeSequence = _lifeSequence, .state = _state, - .frags = _frags, .health = _health, .armour = _armour, .armourType = _armourType, .quadMillis = _quadMillis, .gunSelect = _gunSelect, @@ -163,10 +159,23 @@ .lastAttackGun = _lastAttackGun, .lastMove = _lastMove, .attacking = _attacking, .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; data.monsterType = monster.monsterType; @@ -174,16 +183,10 @@ data.trigger = monster.trigger; data.attackTarget = monster.attackTarget; 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)]; } - (void)setFromSerializedData:(OFData *)data { @@ -215,13 +218,12 @@ _eyeHeight = d.eyeHeight; _aboveEye = d.aboveEye; _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; _quadMillis = d.quadMillis; _gunSelect = d.gunSelect; @@ -234,10 +236,19 @@ for (int i = 0; i < NUMGUNS; i++) _ammo[i] = d.ammo[i]; _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; monster.monsterType = d.monsterType; @@ -244,13 +255,10 @@ monster.targetYaw = d.targetYaw; monster.trigger = d.trigger; monster.attackTarget = d.attackTarget; monster.anger = d.anger; } - - _name = [[OFString alloc] initWithUTF8String:d.name]; - _team = [[OFString alloc] initWithUTF8String:d.team]; } - (void)resetMovement { _k_left = false; Index: src/Monster.m ================================================================== --- src/Monster.m +++ src/Monster.m @@ -2,12 +2,12 @@ #import "Monster.h" #include "cube.h" -#import "DynamicEntity.h" #import "Entity.h" +#import "Player.h" static OFMutableArray *monsters; static int nextmonster, spawnremain, numkilled, monstertotal, mtimestart; @implementation Monster @@ -99,11 +99,11 @@ spawnplayer(self); 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; self.armour = 0; @@ -254,11 +254,11 @@ // main AI thinking routine, called every frame for every monster - (void)performAction { if (self.enemy.state == CS_DEAD) { - self.enemy = player1; + self.enemy = Player.player1; self.anger = 0; } [self normalizeWithAngle:self.targetYaw]; // slowly turn monster towards his target if (self.targetYaw > self.yaw) { @@ -415,11 +415,11 @@ if ((self.health -= damage) <= 0) { 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; if (remain > 0 && remain <= 5) conoutf(@"only %d monster(s) remaining", remain); Index: src/clientextras.m ================================================================== --- src/clientextras.m +++ src/clientextras.m @@ -1,12 +1,12 @@ // clientextras.cpp: stuff that didn't fit in client.cpp or clientgame.cpp :) #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 // configurable @@ -88,11 +88,11 @@ { [players enumerateObjectsUsingBlock:^(id player, size_t i, bool *stop) { 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); }]; } // creation of scoreboard pseudo-menu @@ -106,12 +106,12 @@ menuset(((int)on) - 1); } 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]; OFString *line = [OFString stringWithFormat:@"%d\t%@\t%d\t%@\t%@", d.frags, @@ -129,12 +129,12 @@ #define maxTeams 4 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]) { teamScore[i] += d.frags; return; @@ -153,22 +153,22 @@ { if (!scoreson) 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], teamScore[j]]; menumanual(0, scoreLines.count, @""); Index: src/clientgame.m ================================================================== --- src/clientgame.m +++ src/clientgame.m @@ -5,10 +5,11 @@ #import "Command.h" #import "DynamicEntity.h" #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); COMMAND(mode, ARG_1INT, ^(int n) { @@ -15,17 +16,15 @@ addmsg(1, 2, SV_GAMEMODE, nextmode = n); }) bool intermission = false; -DynamicEntity *player1; // our client OFMutableArray *players; // other clients void initPlayers() { - player1 = [[DynamicEntity alloc] init]; players = [[OFMutableArray alloc] init]; } VARP(sensitivity, 0, 10, 10000); VARP(sensitivityscale, 1, 1, 10000); @@ -42,17 +41,16 @@ } 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)++; if (![*lastteam isEqual:d.team]) *oneteam = false; @@ -80,11 +78,11 @@ bool oneteam = true; for (id player in players) 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..."); if (alive) conoutf( @@ -91,42 +89,43 @@ @"team %s is last man standing", lastteam); else conoutf(@"everyone died!"); arenarespawnwait = lastmillis + 5000; arenadetectwait = lastmillis + 10000; - player1.roll = 0; + Player.player1.roll = 0; } } } extern int democlientnum; void otherplayers() { - [players enumerateObjectsUsingBlock:^(id player, size_t i, bool *stop) { - if (player == [OFNull null]) - return; - - const int lagtime = lastmillis - [player lastUpdate]; - if (lagtime > 1000 && [player state] == CS_ALIVE) { - [player setState:CS_LAGGED]; - return; - } - - if (lagtime && [player state] != CS_DEAD && - (!demoplayback || i != democlientnum)) - // use physics to extrapolate player position - moveplayer(player, 2, false); - }]; + [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.state = CS_LAGGED; + return; + } + + 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; } if (m_sp) { @@ -158,10 +157,11 @@ checkquad(curtime); if (m_arena) arenarespawn(); moveprojectiles((float)curtime); demoplaybackstep(); + Player *player1 = Player.player1; if (!demoplayback) { if (getclientnum() >= 0) // only shoot when connected to server shoot(player1, worldpos); // do this first, so we have most accurate information @@ -169,10 +169,11 @@ gets2c(); } otherplayers(); if (!demoplayback) { [Monster thinkAll]; + if (player1.state == CS_DEAD) { if (lastmillis - player1.lastAction < 2000) { player1.move = player1.strafe = 0; moveplayer(player1, 10, false); } else if (!m_arena && !m_sp && @@ -180,10 +181,11 @@ respawn(); } else if (!intermission) { moveplayer(player1, 20, true); checkitems(); } + // do this last, to reduce the effective frame lag c2sinfo(player1); } } lastmillis = millis; @@ -211,11 +213,11 @@ int spawncycle = -1; 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++) spawncycle = findentity(PLAYERSTART, spawncycle + 1); if (spawncycle != -1) { @@ -234,10 +236,11 @@ // movement input code #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; \ }) @@ -249,16 +252,16 @@ COMMAND(attack, ARG_DOWN, ^(bool on) { if (intermission) 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(); }) COMMAND(showscores, ARG_DOWN, ^(bool isDown) { showscores(isDown); @@ -266,10 +269,11 @@ void fixplayer1range() { const float MAXPITCH = 90.0f; + Player *player1 = Player.player1; if (player1.pitch > MAXPITCH) player1.pitch = MAXPITCH; if (player1.pitch < -MAXPITCH) player1.pitch = -MAXPITCH; while (player1.yaw < 0.0f) @@ -279,10 +283,11 @@ } 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 player1.yaw += (dx / SENSF) * (sensitivity / (float)sensitivityscale); player1.pitch -= (dy / SENSF) * @@ -293,18 +298,19 @@ // damage arriving from the network, monsters, yourself, all ends up here. 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; player1.roll += player1.roll > 0 ? droll @@ -319,11 +325,11 @@ } else if (actor == -1) { actor = getclientnum(); 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 " @"teammate (%@)", a.name); @@ -349,20 +355,20 @@ void timeupdate(int timeremain) { if (!timeremain) { intermission = true; - player1.attacking = false; + Player.player1.attacking = false; conoutf(@"intermission:"); conoutf(@"game has ended!"); showscores(true); } else { conoutf(@"time remaining: %d minutes", timeremain); } } -DynamicEntity * +Player * getclient(int cn) // ensure valid entity { if (cn < 0 || cn >= MAXCLIENTS) { neterr(@"clientnum"); return nil; @@ -371,11 +377,11 @@ while (cn >= players.count) [players addObject:[OFNull null]]; id player = players[cn]; if (player == [OFNull null]) { - player = [DynamicEntity entity]; + player = [Player player]; players[cn] = player; } return player; } @@ -406,12 +412,12 @@ } sleepwait = 0; [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]; resetspawns(); clientmap = name; Index: src/clients.m ================================================================== --- src/clients.m +++ src/clients.m @@ -1,11 +1,11 @@ // client.cpp, mostly network related client game code #include "cube.h" #import "Command.h" -#import "DynamicEntity.h" +#import "Player.h" static ENetHost *clienthost = NULL; static int connecting = 0; static int connattempts = 0; static int disconnecting = 0; @@ -67,11 +67,11 @@ c2sinit = false; if (name.length > 16) name = [name substringToIndex:16]; - player1.name = name; + Player.player1.name = name; } COMMAND(name, ARG_1STR, ^(OFString *name) { newname(name); }) @@ -82,22 +82,22 @@ c2sinit = false; if (name.length > 5) name = [name substringToIndex:5]; - player1.team = name; + Player.player1.team = name; } COMMAND(team, ARG_1STR, ^(OFString *name) { newteam(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 connects(OFString *servername) { @@ -147,11 +147,11 @@ connecting = 0; connattempts = 0; disconnecting = 0; clientnum = -1; c2sinit = false; - player1.lifeSequence = 0; + Player.player1.lifeSequence = 0; [players removeAllObjects]; localdisconnect(); if (!onlyclean) { @@ -178,11 +178,11 @@ static OFString *ctext; void toserver(OFString *text) { - conoutf(@"%@:\f %@", player1.name, text); + conoutf(@"%@:\f %@", Player.player1.name, text); ctext = text; } COMMAND(echo, ARG_VARI, ^(OFString *text) { conoutf(@"%@", text); @@ -279,11 +279,11 @@ localclienttoserver((ENetPacket *)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 if (lastmillis - lastupdate < 40) return; // don't update faster than 25fps @@ -340,13 +340,13 @@ // tell other clients who I am if (!c2sinit) { 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 if (*(int *)[msg itemAtIndex:1]) packet->flags = ENET_PACKET_FLAG_RELIABLE; Index: src/clients2c.m ================================================================== --- src/clients2c.m +++ src/clients2c.m @@ -2,10 +2,11 @@ #include "cube.h" #import "DynamicEntity.h" #import "Entity.h" +#import "Player.h" extern int clientnum; extern bool c2sinit, senditemstoserver; extern OFString *toservermap; extern OFString *clientpassword; @@ -35,10 +36,11 @@ // just don't overlap with our client 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; const float dz = player1.origin.z - d.origin.z; const float rz = player1.aboveEye + d.eyeHeight; @@ -180,27 +182,28 @@ break; } // 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 // send new players my info again 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; } case SV_CDIS: cn = getint(&p); @@ -229,37 +232,38 @@ case SV_DAMAGE: { int target = getint(&p); 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; playsound(S_PAIN1 + rnd(5), &loc); } break; } 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 " @"teammate (%@)", a.name, d.name); @@ -266,13 +270,13 @@ else conoutf(@"%@ fragged %@", a.name, d.name); } } - OFVector3D loc = d.origin; + OFVector3D loc = d_.origin; playsound(S_DIE1 + rnd(2), &loc); - d.lifeSequence++; + d_.lifeSequence++; break; } case SV_FRAGS: [players[cn] setFrags:getint(&p)]; @@ -293,11 +297,11 @@ playsound(S_ITEMSPAWN, &v); break; } // 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 // include all possible editing ops case SV_EDITT: @@ -359,12 +363,12 @@ getint(&p); break; 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; case SV_CLIENTPING: [players[cn] setPing:getint(&p)]; Index: src/cube.h ================================================================== --- src/cube.h +++ src/cube.h @@ -6,12 +6,13 @@ #include "tools.h" #define _MAXDEFSTR 260 -@class Entity; @class DynamicEntity; +@class Entity; +@class Player; @interface Cube: OFObject @property (class, readonly, nonatomic) Cube *sharedInstance; @property (readonly, nonatomic) SDL_Window *window; @property (readonly, nonatomic) OFIRI *gameDataIRI, *userDataIRI; @@ -254,12 +255,10 @@ // map data, the mips are sequential 2D arrays in memory 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; extern OFMutableArray *ents; // map entities extern OFVector3D worldpos; // current target of the crosshair in the world Index: src/editing.m ================================================================== --- src/editing.m +++ src/editing.m @@ -5,10 +5,11 @@ #import "Command.h" #import "DynamicEntity.h" #import "Monster.h" #import "OFString+Cube.h" +#import "Player.h" bool editmode = false; // the current selection, used by almost all editing commands // invariant: all code assumes that these are kept inside MINBORD distance of @@ -56,10 +57,11 @@ 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 if (!editmode && !allowedittoggle()) return; // not in most multiplayer modes @@ -155,10 +157,11 @@ } void cursorupdate() // called every frame from hud { + Player *player1 = Player.player1; flrceil = ((int)(player1.pitch >= 0)) * 2; volatile float x = worldpos.x; // volatile needed to prevent msvc7 optimizer bug? volatile float y = worldpos.y; @@ -624,9 +627,9 @@ 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]); }) Index: src/entities.m ================================================================== --- src/entities.m +++ src/entities.m @@ -3,10 +3,11 @@ #include "cube.h" #import "DynamicEntity.h" #import "Entity.h" #import "MapModelInfo.h" +#import "Player.h" OFMutableArray *ents; static OFString *entmdlnames[] = { @"shells", @@ -126,11 +127,11 @@ }; 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 // picked up the item (in multiplayer someone may grab it before you). @@ -145,11 +146,11 @@ playsoundc(is->sound); return v; } void -realpickup(int n, DynamicEntity *d) +realpickup(int n, Player *d) { switch (ents[n].type) { case I_SHELLS: d.ammo[1] = radditem(n, d.ammo[1]); break; @@ -292,10 +293,11 @@ if (lastmillis - lastjumppad < 300) break; 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); playsoundc(S_JUMPPAD); break; @@ -304,10 +306,12 @@ } void checkitems() { + Player *player1 = Player.player1; + if (editmode) return; [ents enumerateObjectsUsingBlock:^(Entity *e, size_t i, bool *stop) { if (e.type == NOTUSED) @@ -329,10 +333,12 @@ } void checkquad(int time) { + Player *player1 = Player.player1; + if (player1.quadMillis && (player1.quadMillis -= time) < 0) { player1.quadMillis = 0; playsoundc(S_PUPOUT); conoutf(@"quad damage is over"); } Index: src/menus.m ================================================================== --- src/menus.m +++ src/menus.m @@ -3,22 +3,22 @@ #include "cube.h" #import "Menu.h" #import "Command.h" -#import "DynamicEntity.h" #import "MenuItem.h" +#import "Player.h" static OFMutableArray *menuStack; static OFMutableArray *menus; static int vmenu = -1; void menuset(int menu) { if ((vmenu = menu) >= 1) - [player1 resetMovement]; + [Player.player1 resetMovement]; if (vmenu == 1) menus[1].menusel = 0; } COMMAND(showmenu, ARG_1STR, ^(OFString *name) { Index: src/meson.build ================================================================== --- src/meson.build +++ src/meson.build @@ -13,10 +13,11 @@ 'MapModelInfo.m', 'Menu.m', 'MenuItem.m', 'Monster.m', 'OFString+Cube.m', + 'Player.m', 'Projectile.m', 'ResolverResult.m', 'ResolverThread.m', 'ServerEntity.m', 'ServerInfo.m', Index: src/physics.m ================================================================== --- src/physics.m +++ src/physics.m @@ -8,10 +8,11 @@ #import "DynamicEntity.h" #import "Entity.h" #import "MapModelInfo.h" #import "Monster.h" +#import "Player.h" // collide with player or monster static bool plcollide( DynamicEntity *d, DynamicEntity *o, float *headspace, float *hi, float *lo) @@ -177,12 +178,12 @@ continue; if (!plcollide(d, player, &headspace, &hi, &lo)) 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 // cpu, should replace with a blockmap but seems mostly fast enough for (Monster *monster in Monster.monsters) Index: src/protos.h ================================================================== --- src/protos.h +++ src/protos.h @@ -80,11 +80,11 @@ extern void addmsg(int rel, int num, int type, ...); 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(); extern int getclientnum(); extern void changemapserv(OFString *name, int mode); @@ -99,11 +99,11 @@ extern void initclient(); 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(); // clientextras @@ -253,11 +253,11 @@ extern void initEntities(); 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); extern void teleport(int n, DynamicEntity *d); extern void baseammo(int gun); Index: src/renderextras.m ================================================================== --- src/renderextras.m +++ src/renderextras.m @@ -1,12 +1,12 @@ // renderextras.cpp: misc gl render code and the HUD #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) { glBegin(GL_POLYGON); @@ -325,10 +325,12 @@ 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) worldpos = player1.origin; glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); Index: src/rendergl.m ================================================================== --- src/rendergl.m +++ src/rendergl.m @@ -3,13 +3,13 @@ #define gamma math_gamma #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 # define GL_COMBINE_RGB_EXT GL_COMBINE_RGB_ARB # define GL_SOURCE0_RBG_EXT GL_SOURCE0_RGB_ARB @@ -343,10 +343,12 @@ }) void transplayer() { + Player *player1 = Player.player1; + glLoadIdentity(); glRotated(player1.roll, 0.0, 0.0, 1.0); glRotated(player1.pitch, -1.0, 0.0, 0.0); glRotated(player1.yaw, 0.0, 1.0, 0.0); @@ -370,19 +372,23 @@ @"hudguns/chaing", @"hudguns/rocket", @"hudguns/rifle" }; 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), player1.yaw + 90, player1.pitch, false, 1.0f, speed, 0, base); } void drawhudgun(float fovy, float aspect, int farplane) { + Player *player1 = Player.player1; + if (!hudgun /*|| !player1.gunSelect*/) return; glEnable(GL_CULL_FACE); @@ -408,10 +414,11 @@ } 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; bool underwater = (player1.origin.z < hf); Index: src/rendermd2.m ================================================================== --- src/rendermd2.m +++ src/rendermd2.m @@ -1,14 +1,14 @@ // rendermd2.cpp: loader code adapted from a nehe tutorial #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; static const int FIRSTMDL = 20; @@ -88,12 +88,12 @@ OFVector3D position, float yaw, float pitch, bool teammate, float scale, float speed, int snap, int basetime) { 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); int xs, ys; Index: src/renderparticles.m ================================================================== --- src/renderparticles.m +++ src/renderparticles.m @@ -1,10 +1,10 @@ // renderparticles.cpp #include "cube.h" -#import "DynamicEntity.h" +#import "Player.h" #define MAXPARTICLES 10500 const int NUMPARTCUTOFF = 20; struct particle { OFVector3D o, d; @@ -54,12 +54,12 @@ 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); glBlendFunc(GL_SRC_ALPHA, GL_SRC_ALPHA); glDisable(GL_FOG); Index: src/savegamedemo.m ================================================================== --- src/savegamedemo.m +++ src/savegamedemo.m @@ -2,13 +2,13 @@ // mapents, the full state of all dynents (monsters + player) #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; #else static const int islittleendian = 1; @@ -16,11 +16,11 @@ 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(); static void @@ -103,11 +103,11 @@ return; } 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, min(getclientmap().UTF8StringLength, _MAXDEFSTR - 1)); gzwrite(f, map, _MAXDEFSTR); @@ -217,12 +217,12 @@ OFMutableData *data = [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; if (nmonsters != monsters.count) return loadgameout(); @@ -229,11 +229,11 @@ for (Monster *monster in monsters) { 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) monster.lastAction = 0; } @@ -240,11 +240,11 @@ [Monster restoreAll]; 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]; } } @@ -298,12 +298,15 @@ } 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); gzput(extras); if (extras) { @@ -368,11 +371,11 @@ { democlientnum = gzgeti(); demoplayback = true; starttime = lastmillis; conoutf(@"now playing demo"); - setclient(democlientnum, [player1 copy]); + setclient(democlientnum, [Player.player1 copy]); readdemotime(); } VAR(demodelaymsec, 0, 120, 500); @@ -419,11 +422,11 @@ } unsigned char buf[MAXTRANS]; gzread(f, buf, len); localservertoclient(buf, len); // update game state - DynamicEntity *target = players[democlientnum]; + Player *target = players[democlientnum]; assert(target); int extras; // read additional client side state not present in normal // network stream @@ -450,11 +453,11 @@ // insert latest copy of player into history if (extras && (playerhistory.count == 0 || playerhistory.lastObject.lastUpdate != playbacktime)) { - DynamicEntity *d = [target copy]; + Player *d = [target copy]; d.lastUpdate = playbacktime; if (playerhistory == nil) playerhistory = [[OFMutableArray alloc] init]; @@ -473,17 +476,17 @@ int itime = lastmillis - demodelaymsec; // find 2 positions in history that surround interpolation time point 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; if (i + 2 < playerhistory.count) c = playerhistory[i + 2]; @@ -492,30 +495,29 @@ z = playerhistory[i - 1]; // if(a==z || b==c) // 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( a.yaw, a.pitch, a.roll); OFVector3D vb = OFMakeVector3D( 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; z.roll = vz.z; a.yaw = va.x; @@ -525,13 +527,13 @@ b.pitch = vb.y; b.roll = vb.z; 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(); } break; } Index: src/sound.m ================================================================== --- src/sound.m +++ src/sound.m @@ -1,9 +1,9 @@ #include "cube.h" #import "Command.h" -#import "DynamicEntity.h" +#import "Player.h" #include VARP(soundvol, 0, 255, 255); VARP(musicvol, 0, 128, 255); @@ -111,21 +111,21 @@ 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); // simple mono distance attenuation vol -= (int)(dist * 3 * soundvol / 255); 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)); } } Index: src/weapon.m ================================================================== --- src/weapon.m +++ src/weapon.m @@ -4,10 +4,11 @@ #import "Command.h" #import "DynamicEntity.h" #import "Monster.h" #import "OFString+Cube.h" +#import "Player.h" #import "Projectile.h" static const int MONSTERDAMAGEFACTOR = 4; #define SGRAYS 20 static const float SGSPREAD = 2; @@ -32,10 +33,12 @@ 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; else if (b >= 0 && s != b && player1.ammo[b]) s = b; @@ -110,15 +113,15 @@ 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]; } return nil; @@ -160,16 +163,17 @@ 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); demodamage(damage, o); } @@ -217,11 +221,11 @@ dodynlight(vold, v, 0, 0, p.owner); 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) { if (i == notthisplayer) return; @@ -277,12 +281,12 @@ if (p.local) { for (id player in players) 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) && monster != p.owner) projdamage(monster, p, v, -1, i, qdam); @@ -308,11 +312,11 @@ // create visual effect from a shot 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: break; @@ -436,7 +440,7 @@ for (Monster *monster in Monster.monsters) if (monster != d) raydamage(monster, from, to, d, -2); if ([d isKindOfClass:Monster.class]) - raydamage(player1, from, to, d, -1); + raydamage(Player.player1, from, to, d, -1); } Index: src/world.m ================================================================== --- src/world.m +++ src/world.m @@ -1,13 +1,13 @@ // world.cpp: core map management stuff #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 struct sqr *world = NULL; int sfactor, ssize, cubicsize, mipsize; @@ -296,11 +296,11 @@ [ents enumerateObjectsUsingBlock:^(Entity *e, size_t i, bool *stop) { if (e.type == NOTUSED) 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; } }]; @@ -381,11 +381,11 @@ e.attr3 = e.attr2; case MONSTER: 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, e.attr2, e.attr3, e.attr4); Index: src/worldocull.m ================================================================== --- src/worldocull.m +++ src/worldocull.m @@ -1,11 +1,11 @@ // worldocull.cpp: occlusion map and occlusion test #include "cube.h" #import "Command.h" -#import "DynamicEntity.h" +#import "Player.h" #define NUMRAYS 512 float rdist[NUMRAYS]; bool ocull = true; @@ -19,10 +19,12 @@ // record distance. done exactly once per frame. void computeraytable(float vx, float vy) { + Player *player1 = Player.player1; + if (!ocull) return; odist = getvar(@"fog") * 1.5f; Index: src/worldrender.m ================================================================== --- src/worldrender.m +++ src/worldrender.m @@ -2,11 +2,11 @@ // determines what has to be rendered and how (depending on neighbouring cubes), // then calls functions in rendercubes.cpp #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, int mip, struct sqr *d1, struct sqr *d2, bool topleft) { @@ -131,10 +131,11 @@ int ly = vyy - lodtop; int rx = vxx + lodright; 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++) { SWS(w, ox, oy, sz)->occluded = isoccluded(player1.origin.x, player1.origin.y,