Convert player into a class

FossilOrigin-Name: 5b7b7d2fc5af4d512db195c4fbfb2aff01436db9bc1345d62263609ac129aa02
This commit is contained in:
Jonathan Schleifer 2025-03-24 22:14:24 +00:00
parent 4596a656dc
commit 5835957d74
25 changed files with 211 additions and 166 deletions

View file

@ -3,7 +3,7 @@
#include "cube.h" #include "cube.h"
#import "Command.h" #import "Command.h"
#import "DynamicEntity.h" #import "Player.h"
OF_APPLICATION_DELEGATE(Cube) OF_APPLICATION_DELEGATE(Cube)
@ -216,6 +216,8 @@ VARP(minmillis, 0, 5, 1000);
@autoreleasepool { @autoreleasepool {
[OFRunLoop.mainRunLoop runUntilDate:past]; [OFRunLoop.mainRunLoop runUntilDate:past];
Player *player1 = Player.player1;
int millis = SDL_GetTicks() * gamespeed / 100; int millis = SDL_GetTicks() * gamespeed / 100;
if (millis - lastmillis > 200) if (millis - lastmillis > 200)
lastmillis = millis - 200; lastmillis = millis - 200;

View file

@ -21,11 +21,8 @@
// bounding box size // bounding box size
@property (nonatomic) float radius, eyeHeight, aboveEye; @property (nonatomic) float radius, eyeHeight, aboveEye;
@property (nonatomic) int lastUpdate, lag, ping; @property (nonatomic) int lastUpdate, lag, ping;
// sequence id for each respawn, used in damage test
@property (nonatomic) int lifeSequence;
// one of CS_* below // one of CS_* below
@property (nonatomic) int state; @property (nonatomic) int state;
@property (nonatomic) int frags;
@property (nonatomic) int health, armour, armourType, quadMillis; @property (nonatomic) int health, armour, armourType, quadMillis;
@property (nonatomic) int gunSelect, gunWait; @property (nonatomic) int gunSelect, gunWait;
@property (nonatomic) int lastAction, lastAttackGun, lastMove; @property (nonatomic) int lastAction, lastAttackGun, lastMove;
@ -33,7 +30,7 @@
@property (nonatomic) bool attacking; @property (nonatomic) bool attacking;
// used by physics to signal ai // used by physics to signal ai
@property (nonatomic) bool blocked, moving; @property (nonatomic) bool blocked, moving;
@property (copy, nonatomic) OFString *name, *team; @property (copy, nonatomic) OFString *name;
+ (instancetype)entity; + (instancetype)entity;
- (OFData *)dataBySerializing; - (OFData *)dataBySerializing;

View file

@ -3,6 +3,7 @@
#include "cube.h" #include "cube.h"
#import "Monster.h" #import "Monster.h"
#import "Player.h"
struct dynent { struct dynent {
OFVector3D origin, velocity; OFVector3D origin, velocity;
@ -58,7 +59,7 @@ struct dynent {
_eyeHeight = 3.2f; _eyeHeight = 3.2f;
_aboveEye = 0.7f; _aboveEye = 0.7f;
_lastUpdate = lastmillis; _lastUpdate = lastmillis;
_name = _team = @""; _name = @"";
_state = CS_ALIVE; _state = CS_ALIVE;
[self resetToSpawnState]; [self resetToSpawnState];
@ -98,9 +99,7 @@ struct dynent {
copy->_lastUpdate = _lastUpdate; copy->_lastUpdate = _lastUpdate;
copy->_lag = _lag; copy->_lag = _lag;
copy->_ping = _ping; copy->_ping = _ping;
copy->_lifeSequence = _lifeSequence;
copy->_state = _state; copy->_state = _state;
copy->_frags = _frags;
copy->_health = _health; copy->_health = _health;
copy->_armour = _armour; copy->_armour = _armour;
copy->_armourType = _armourType; copy->_armourType = _armourType;
@ -118,7 +117,6 @@ struct dynent {
copy->_blocked = _blocked; copy->_blocked = _blocked;
copy->_moving = _moving; copy->_moving = _moving;
copy->_name = [_name copy]; copy->_name = [_name copy];
copy->_team = [_team copy];
return copy; return copy;
} }
@ -150,9 +148,7 @@ struct dynent {
.lastUpdate = _lastUpdate, .lastUpdate = _lastUpdate,
.lag = _lag, .lag = _lag,
.ping = _ping, .ping = _ping,
.lifeSequence = _lifeSequence,
.state = _state, .state = _state,
.frags = _frags,
.health = _health, .health = _health,
.armour = _armour, .armour = _armour,
.armourType = _armourType, .armourType = _armourType,
@ -166,6 +162,19 @@ struct dynent {
.blocked = _blocked, .blocked = _blocked,
.moving = _moving }; .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]) { if ([self isKindOfClass:Monster.class]) {
Monster *monster = (Monster *)self; Monster *monster = (Monster *)self;
data.monsterState = monster.monsterState; data.monsterState = monster.monsterState;
@ -176,12 +185,6 @@ struct dynent {
data.anger = monster.anger; 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)]; return [OFData dataWithItems:&data count:sizeof(data)];
} }
@ -217,9 +220,8 @@ struct dynent {
_lastUpdate = d.lastUpdate; _lastUpdate = d.lastUpdate;
_lag = d.lag; _lag = d.lag;
_ping = d.ping; _ping = d.ping;
_lifeSequence = d.lifeSequence;
_state = d.state; _state = d.state;
_frags = d.frags;
_health = d.health; _health = d.health;
_armour = d.armour; _armour = d.armour;
_armourType = d.armourType; _armourType = d.armourType;
@ -237,6 +239,15 @@ struct dynent {
_blocked = d.blocked; _blocked = d.blocked;
_moving = d.moving; _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]) { if ([self isKindOfClass:Monster.class]) {
Monster *monster = (Monster *)self; Monster *monster = (Monster *)self;
monster.monsterState = d.monsterState; monster.monsterState = d.monsterState;
@ -246,9 +257,6 @@ struct dynent {
monster.attackTarget = d.attackTarget; monster.attackTarget = d.attackTarget;
monster.anger = d.anger; monster.anger = d.anger;
} }
_name = [[OFString alloc] initWithUTF8String:d.name];
_team = [[OFString alloc] initWithUTF8String:d.team];
} }
- (void)resetMovement - (void)resetMovement

View file

@ -4,8 +4,8 @@
#include "cube.h" #include "cube.h"
#import "DynamicEntity.h"
#import "Entity.h" #import "Entity.h"
#import "Player.h"
static OFMutableArray<Monster *> *monsters; static OFMutableArray<Monster *> *monsters;
static int nextmonster, spawnremain, numkilled, monstertotal, mtimestart; static int nextmonster, spawnremain, numkilled, monstertotal, mtimestart;
@ -101,7 +101,7 @@ monstertypes[NUMMONSTERTYPES] = {
self.trigger = lastmillis + trigger; self.trigger = lastmillis + trigger;
self.targetYaw = self.yaw = (float)yaw; self.targetYaw = self.yaw = (float)yaw;
self.move = move; self.move = move;
self.enemy = player1; self.enemy = Player.player1;
self.gunSelect = t->gun; self.gunSelect = t->gun;
self.maxSpeed = (float)t->speed; self.maxSpeed = (float)t->speed;
self.health = t->health; self.health = t->health;
@ -256,7 +256,7 @@ enemylos(Monster *m, OFVector3D *v)
- (void)performAction - (void)performAction
{ {
if (self.enemy.state == CS_DEAD) { if (self.enemy.state == CS_DEAD) {
self.enemy = player1; self.enemy = Player.player1;
self.anger = 0; self.anger = 0;
} }
[self normalizeWithAngle:self.targetYaw]; [self normalizeWithAngle:self.targetYaw];
@ -417,7 +417,7 @@ enemylos(Monster *m, OFVector3D *v)
self.state = CS_DEAD; self.state = CS_DEAD;
self.lastAction = lastmillis; self.lastAction = lastmillis;
numkilled++; numkilled++;
player1.frags = numkilled; Player.player1.frags = numkilled;
OFVector3D loc = self.origin; OFVector3D loc = self.origin;
playsound(monstertypes[self.monsterType].diesound, &loc); playsound(monstertypes[self.monsterType].diesound, &loc);
int remain = monstertotal - numkilled; int remain = monstertotal - numkilled;

View file

@ -3,8 +3,8 @@
#include "cube.h" #include "cube.h"
#import "Command.h" #import "Command.h"
#import "DynamicEntity.h"
#import "Monster.h" #import "Monster.h"
#import "Player.h"
// render players & monsters // render players & monsters
// very messy ad-hoc handling of animation frames, should be made more // very messy ad-hoc handling of animation frames, should be made more
@ -90,7 +90,7 @@ renderclients()
if (player != [OFNull null] && if (player != [OFNull null] &&
(!demoplayback || i != democlientnum)) (!demoplayback || i != democlientnum))
renderclient(player, renderclient(player,
isteam(player1.team, [player team]), isteam(Player.player1.team, [player team]),
@"monster/ogro", false, 1.0f); @"monster/ogro", false, 1.0f);
}]; }];
} }
@ -108,8 +108,8 @@ showscores(bool on)
static OFMutableArray<OFString *> *scoreLines; static OFMutableArray<OFString *> *scoreLines;
void static void
renderscore(DynamicEntity *d) renderscore(Player *d)
{ {
OFString *lag = [OFString stringWithFormat:@"%d", d.lag]; OFString *lag = [OFString stringWithFormat:@"%d", d.lag];
OFString *name = [OFString stringWithFormat:@"(%@)", d.name]; OFString *name = [OFString stringWithFormat:@"(%@)", d.name];
@ -131,8 +131,8 @@ static OFString *teamName[maxTeams];
static int teamScore[maxTeams]; static int teamScore[maxTeams];
static size_t teamsUsed; static size_t teamsUsed;
void static void
addteamscore(DynamicEntity *d) addteamscore(Player *d)
{ {
for (size_t i = 0; i < teamsUsed; i++) { for (size_t i = 0; i < teamsUsed; i++) {
if ([teamName[i] isEqual:d.team]) { if ([teamName[i] isEqual:d.team]) {
@ -155,18 +155,18 @@ renderscores()
return; return;
[scoreLines removeAllObjects]; [scoreLines removeAllObjects];
if (!demoplayback) if (!demoplayback)
renderscore(player1); renderscore(Player.player1);
for (id player in players) for (Player *player in players)
if (player != [OFNull null]) if ([player isKindOfClass:Player.class])
renderscore(player); renderscore(player);
sortmenu(); sortmenu();
if (m_teammode) { if (m_teammode) {
teamsUsed = 0; teamsUsed = 0;
for (id player in players) for (Player *player in players)
if (player != [OFNull null]) if ([player isKindOfClass:Player.class])
addteamscore(player); addteamscore(player);
if (!demoplayback) if (!demoplayback)
addteamscore(player1); addteamscore(Player.player1);
OFMutableString *teamScores = [OFMutableString string]; OFMutableString *teamScores = [OFMutableString string];
for (size_t j = 0; j < teamsUsed; j++) for (size_t j = 0; j < teamsUsed; j++)
[teamScores appendFormat:@"[ %@: %d ]", teamName[j], [teamScores appendFormat:@"[ %@: %d ]", teamName[j],

View file

@ -7,6 +7,7 @@
#import "Entity.h" #import "Entity.h"
#import "Monster.h" #import "Monster.h"
#import "OFString+Cube.h" #import "OFString+Cube.h"
#import "Player.h"
int nextmode = 0; // nextmode becomes gamemode after next map load int nextmode = 0; // nextmode becomes gamemode after next map load
VAR(gamemode, 1, 0, 0); VAR(gamemode, 1, 0, 0);
@ -17,13 +18,11 @@ COMMAND(mode, ARG_1INT, ^(int n) {
bool intermission = false; bool intermission = false;
DynamicEntity *player1; // our client
OFMutableArray *players; // other clients OFMutableArray *players; // other clients
void void
initPlayers() initPlayers()
{ {
player1 = [[DynamicEntity alloc] init];
players = [[OFMutableArray alloc] init]; players = [[OFMutableArray alloc] init];
} }
@ -44,13 +43,12 @@ getclientmap()
void void
respawnself() respawnself()
{ {
spawnplayer(player1); spawnplayer(Player.player1);
showscores(false); showscores(false);
} }
static void static void
arenacount( arenacount(Player *d, int *alive, int *dead, OFString **lastteam, bool *oneteam)
DynamicEntity *d, int *alive, int *dead, OFString **lastteam, bool *oneteam)
{ {
if (d.state != CS_DEAD) { if (d.state != CS_DEAD) {
(*alive)++; (*alive)++;
@ -82,7 +80,7 @@ arenarespawn()
if (player != [OFNull null]) if (player != [OFNull null])
arenacount( arenacount(
player, &alive, &dead, &lastteam, &oneteam); 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))) { if (dead > 0 && (alive <= 1 || (m_teammode && oneteam))) {
conoutf( conoutf(
@"arena round is over! next round in 5 seconds..."); @"arena round is over! next round in 5 seconds...");
@ -93,7 +91,7 @@ arenarespawn()
conoutf(@"everyone died!"); conoutf(@"everyone died!");
arenarespawnwait = lastmillis + 5000; arenarespawnwait = lastmillis + 5000;
arenadetectwait = lastmillis + 10000; arenadetectwait = lastmillis + 10000;
player1.roll = 0; Player.player1.roll = 0;
} }
} }
} }
@ -103,28 +101,29 @@ extern int democlientnum;
void void
otherplayers() otherplayers()
{ {
[players enumerateObjectsUsingBlock:^(id player, size_t i, bool *stop) { [players
if (player == [OFNull null]) enumerateObjectsUsingBlock:^(Player *player, size_t i, bool *stop) {
return; if ([player isKindOfClass:Player.class])
return;
const int lagtime = lastmillis - [player lastUpdate]; const int lagtime = lastmillis - player.lastUpdate;
if (lagtime > 1000 && [player state] == CS_ALIVE) { if (lagtime > 1000 && player.state == CS_ALIVE) {
[player setState:CS_LAGGED]; player.state = CS_LAGGED;
return; return;
} }
if (lagtime && [player state] != CS_DEAD && if (lagtime && player.state != CS_DEAD &&
(!demoplayback || i != democlientnum)) (!demoplayback || i != democlientnum))
// use physics to extrapolate player position // use physics to extrapolate player position
moveplayer(player, 2, false); moveplayer(player, 2, false);
}]; }];
} }
void void
respawn() respawn()
{ {
if (player1.state == CS_DEAD) { if (Player.player1.state == CS_DEAD) {
player1.attacking = false; Player.player1.attacking = false;
if (m_arena) { if (m_arena) {
conoutf(@"waiting for new round to start..."); conoutf(@"waiting for new round to start...");
return; return;
@ -160,6 +159,7 @@ updateworld(int millis) // main game update loop
arenarespawn(); arenarespawn();
moveprojectiles((float)curtime); moveprojectiles((float)curtime);
demoplaybackstep(); demoplaybackstep();
Player *player1 = Player.player1;
if (!demoplayback) { if (!demoplayback) {
if (getclientnum() >= 0) if (getclientnum() >= 0)
// only shoot when connected to server // only shoot when connected to server
@ -171,6 +171,7 @@ updateworld(int millis) // main game update loop
otherplayers(); otherplayers();
if (!demoplayback) { if (!demoplayback) {
[Monster thinkAll]; [Monster thinkAll];
if (player1.state == CS_DEAD) { if (player1.state == CS_DEAD) {
if (lastmillis - player1.lastAction < 2000) { if (lastmillis - player1.lastAction < 2000) {
player1.move = player1.strafe = 0; player1.move = player1.strafe = 0;
@ -182,6 +183,7 @@ updateworld(int millis) // main game update loop
moveplayer(player1, 20, true); moveplayer(player1, 20, true);
checkitems(); checkitems();
} }
// do this last, to reduce the effective frame lag // do this last, to reduce the effective frame lag
c2sinfo(player1); c2sinfo(player1);
} }
@ -213,7 +215,7 @@ int fixspawn = 2;
// place at random spawn. also used by monsters! // place at random spawn. also used by monsters!
void void
spawnplayer(DynamicEntity *d) spawnplayer(Player *d)
{ {
int r = fixspawn-- > 0 ? 4 : rnd(10) + 1; int r = fixspawn-- > 0 ? 4 : rnd(10) + 1;
for (int i = 0; i < r; i++) for (int i = 0; i < r; i++)
@ -236,6 +238,7 @@ spawnplayer(DynamicEntity *d)
#define dir(name, v, d, s, os) \ #define dir(name, v, d, s, os) \
COMMAND(name, ARG_DOWN, ^(bool isDown) { \ COMMAND(name, ARG_DOWN, ^(bool isDown) { \
Player *player1 = Player.player1; \
player1.s = isDown; \ player1.s = isDown; \
player1.v = isDown ? d : (player1.os ? -(d) : 0); \ player1.v = isDown ? d : (player1.os ? -(d) : 0); \
player1.lastMove = lastmillis; \ player1.lastMove = lastmillis; \
@ -251,12 +254,12 @@ COMMAND(attack, ARG_DOWN, ^(bool on) {
return; return;
if (editmode) if (editmode)
editdrag(on); editdrag(on);
else if ((player1.attacking = on)) else if ((Player.player1.attacking = on))
respawn(); respawn();
}) })
COMMAND(jump, ARG_DOWN, ^(bool on) { COMMAND(jump, ARG_DOWN, ^(bool on) {
if (!intermission && (player1.jumpNext = on)) if (!intermission && (Player.player1.jumpNext = on))
respawn(); respawn();
}) })
@ -268,6 +271,7 @@ void
fixplayer1range() fixplayer1range()
{ {
const float MAXPITCH = 90.0f; const float MAXPITCH = 90.0f;
Player *player1 = Player.player1;
if (player1.pitch > MAXPITCH) if (player1.pitch > MAXPITCH)
player1.pitch = MAXPITCH; player1.pitch = MAXPITCH;
if (player1.pitch < -MAXPITCH) if (player1.pitch < -MAXPITCH)
@ -281,6 +285,7 @@ fixplayer1range()
void void
mousemove(int dx, int dy) mousemove(int dx, int dy)
{ {
Player *player1 = Player.player1;
if (player1.state == CS_DEAD || intermission) if (player1.state == CS_DEAD || intermission)
return; return;
const float SENSF = 33.0f; // try match quake sens const float SENSF = 33.0f; // try match quake sens
@ -295,14 +300,15 @@ mousemove(int dx, int dy)
void void
selfdamage(int damage, int actor, DynamicEntity *act) selfdamage(int damage, int actor, DynamicEntity *act)
{ {
Player *player1 = Player.player1;
if (player1.state != CS_ALIVE || editmode || intermission) if (player1.state != CS_ALIVE || editmode || intermission)
return; return;
damageblend(damage); damageblend(damage);
demoblend(damage); demoblend(damage);
// let armour absorb when possible // let armour absorb when possible
int ad = damage * (player1.armourType + 1) * 20 / 100; int ad = damage * (player1.armourType + 1) * 20 / 100;
if (ad > player1.armour) if (ad > Player.player1.armour)
ad = player1.armour; ad = Player.player1.armour;
player1.armour -= ad; player1.armour -= ad;
damage -= ad; damage -= ad;
float droll = damage / 0.5f; float droll = damage / 0.5f;
@ -321,7 +327,7 @@ selfdamage(int damage, int actor, DynamicEntity *act)
conoutf(@"you suicided!"); conoutf(@"you suicided!");
addmsg(1, 2, SV_FRAGS, --player1.frags); addmsg(1, 2, SV_FRAGS, --player1.frags);
} else { } else {
DynamicEntity *a = getclient(actor); Player *a = getclient(actor);
if (a != nil) { if (a != nil) {
if (isteam(a.team, player1.team)) if (isteam(a.team, player1.team))
conoutf(@"you got fragged by a " conoutf(@"you got fragged by a "
@ -351,7 +357,7 @@ timeupdate(int timeremain)
{ {
if (!timeremain) { if (!timeremain) {
intermission = true; intermission = true;
player1.attacking = false; Player.player1.attacking = false;
conoutf(@"intermission:"); conoutf(@"intermission:");
conoutf(@"game has ended!"); conoutf(@"game has ended!");
showscores(true); showscores(true);
@ -360,7 +366,7 @@ timeupdate(int timeremain)
} }
} }
DynamicEntity * Player *
getclient(int cn) // ensure valid entity getclient(int cn) // ensure valid entity
{ {
if (cn < 0 || cn >= MAXCLIENTS) { if (cn < 0 || cn >= MAXCLIENTS) {
@ -373,7 +379,7 @@ getclient(int cn) // ensure valid entity
id player = players[cn]; id player = players[cn];
if (player == [OFNull null]) { if (player == [OFNull null]) {
player = [DynamicEntity entity]; player = [Player player];
players[cn] = player; players[cn] = player;
} }
@ -408,8 +414,8 @@ startmap(OFString *name) // called just after a map load
[Monster resetAll]; [Monster resetAll];
projreset(); projreset();
spawncycle = -1; spawncycle = -1;
spawnplayer(player1); spawnplayer(Player.player1);
player1.frags = 0; Player.player1.frags = 0;
for (id player in players) for (id player in players)
if (player != [OFNull null]) if (player != [OFNull null])
[player setFrags:0]; [player setFrags:0];

View file

@ -3,7 +3,7 @@
#include "cube.h" #include "cube.h"
#import "Command.h" #import "Command.h"
#import "DynamicEntity.h" #import "Player.h"
static ENetHost *clienthost = NULL; static ENetHost *clienthost = NULL;
static int connecting = 0; static int connecting = 0;
@ -69,7 +69,7 @@ newname(OFString *name)
if (name.length > 16) if (name.length > 16)
name = [name substringToIndex:16]; name = [name substringToIndex:16];
player1.name = name; Player.player1.name = name;
} }
COMMAND(name, ARG_1STR, ^(OFString *name) { COMMAND(name, ARG_1STR, ^(OFString *name) {
@ -84,7 +84,7 @@ newteam(OFString *name)
if (name.length > 5) if (name.length > 5)
name = [name substringToIndex:5]; name = [name substringToIndex:5];
player1.team = name; Player.player1.team = name;
} }
COMMAND(team, ARG_1STR, ^(OFString *name) { COMMAND(team, ARG_1STR, ^(OFString *name) {
@ -94,8 +94,8 @@ COMMAND(team, ARG_1STR, ^(OFString *name) {
void void
writeclientinfo(OFStream *stream) writeclientinfo(OFStream *stream)
{ {
[stream writeFormat:@"name \"%@\"\nteam \"%@\"\n", player1.name, [stream writeFormat:@"name \"%@\"\nteam \"%@\"\n", Player.player1.name,
player1.team]; Player.player1.team];
} }
void void
@ -149,7 +149,7 @@ disconnect(bool onlyclean, bool async)
disconnecting = 0; disconnecting = 0;
clientnum = -1; clientnum = -1;
c2sinit = false; c2sinit = false;
player1.lifeSequence = 0; Player.player1.lifeSequence = 0;
[players removeAllObjects]; [players removeAllObjects];
localdisconnect(); localdisconnect();
@ -180,7 +180,7 @@ static OFString *ctext;
void void
toserver(OFString *text) toserver(OFString *text)
{ {
conoutf(@"%@:\f %@", player1.name, text); conoutf(@"%@:\f %@", Player.player1.name, text);
ctext = text; ctext = text;
} }
@ -281,7 +281,7 @@ sendpackettoserv(void *packet)
// send update to the server // send update to the server
void void
c2sinfo(DynamicEntity *d) c2sinfo(Player *d)
{ {
if (clientnum < 0) if (clientnum < 0)
return; // we haven't had a welcome message from the server yet 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; packet->flags = ENET_PACKET_FLAG_RELIABLE;
c2sinit = true; c2sinit = true;
putint(&p, SV_INITC2S); putint(&p, SV_INITC2S);
sendstring(player1.name, &p); sendstring(Player.player1.name, &p);
sendstring(player1.team, &p); sendstring(Player.player1.team, &p);
putint(&p, player1.lifeSequence); putint(&p, Player.player1.lifeSequence);
} }
for (OFData *msg in messages) { for (OFData *msg in messages) {
// send messages collected during the previous frames // send messages collected during the previous frames

View file

@ -4,6 +4,7 @@
#import "DynamicEntity.h" #import "DynamicEntity.h"
#import "Entity.h" #import "Entity.h"
#import "Player.h"
extern int clientnum; extern int clientnum;
extern bool c2sinit, senditemstoserver; extern bool c2sinit, senditemstoserver;
@ -37,6 +38,7 @@ changemap(OFString *name) // request map change, server may ignore
void void
updatepos(DynamicEntity *d) updatepos(DynamicEntity *d)
{ {
Player *player1 = Player.player1;
const float r = player1.radius + d.radius; const float r = player1.radius + d.radius;
const float dx = player1.origin.x - d.origin.x; const float dx = player1.origin.x - d.origin.x;
const float dy = player1.origin.y - d.origin.y; 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 // another client either connected or changed name/team
case SV_INITC2S: { case SV_INITC2S: {
Player *d_ = (Player *)d;
sgetstr(); sgetstr();
if (d.name.length > 0) { if (d_.name.length > 0) {
// already connected // already connected
if (![d.name isEqual:@(text)]) if (![d_.name isEqual:@(text)])
conoutf(@"%@ is now known as %s", conoutf(@"%@ is now known as %s",
d.name, text); d_.name, text);
} else { } else {
// new client // new client
@ -195,10 +198,10 @@ localservertoclient(unsigned char *buf, int len)
c2sinit = false; c2sinit = false;
conoutf(@"connected: %s", text); conoutf(@"connected: %s", text);
} }
d.name = @(text); d_.name = @(text);
sgetstr(); sgetstr();
d.team = @(text); d_.team = @(text);
d.lifeSequence = getint(&p); d_.lifeSequence = getint(&p);
break; break;
} }
@ -231,7 +234,7 @@ localservertoclient(unsigned char *buf, int len)
int damage = getint(&p); int damage = getint(&p);
int ls = getint(&p); int ls = getint(&p);
if (target == clientnum) { if (target == clientnum) {
if (ls == player1.lifeSequence) if (ls == Player.player1.lifeSequence)
selfdamage(damage, cn, d); selfdamage(damage, cn, d);
} else { } else {
OFVector3D loc = getclient(target).origin; OFVector3D loc = getclient(target).origin;
@ -241,23 +244,24 @@ localservertoclient(unsigned char *buf, int len)
} }
case SV_DIED: { case SV_DIED: {
Player *d_ = (Player *)d;
int actor = getint(&p); int actor = getint(&p);
if (actor == cn) { if (actor == cn) {
conoutf(@"%@ suicided", d.name); conoutf(@"%@ suicided", d_.name);
} else if (actor == clientnum) { } else if (actor == clientnum) {
int frags; int frags;
if (isteam(player1.team, d.team)) { if (isteam(Player.player1.team, d_.team)) {
frags = -1; frags = -1;
conoutf(@"you fragged a teammate (%@)", conoutf(@"you fragged a teammate (%@)",
d.name); d_.name);
} else { } else {
frags = 1; frags = 1;
conoutf(@"you fragged %@", d.name); conoutf(@"you fragged %@", d_.name);
} }
addmsg( addmsg(1, 2, SV_FRAGS,
1, 2, SV_FRAGS, (player1.frags += frags)); (Player.player1.frags += frags));
} else { } else {
DynamicEntity *a = getclient(actor); Player *a = getclient(actor);
if (a != nil) { if (a != nil) {
if (isteam(a.team, d.name)) if (isteam(a.team, d.name))
conoutf(@"%@ fragged his " conoutf(@"%@ fragged his "
@ -268,9 +272,9 @@ localservertoclient(unsigned char *buf, int len)
a.name, d.name); a.name, d.name);
} }
} }
OFVector3D loc = d.origin; OFVector3D loc = d_.origin;
playsound(S_DIE1 + rnd(2), &loc); playsound(S_DIE1 + rnd(2), &loc);
d.lifeSequence++; d_.lifeSequence++;
break; break;
} }
@ -295,7 +299,7 @@ localservertoclient(unsigned char *buf, int len)
} }
// server acknowledges that I picked up this item // server acknowledges that I picked up this item
case SV_ITEMACC: case SV_ITEMACC:
realpickup(getint(&p), player1); realpickup(getint(&p), Player.player1);
break; break;
case SV_EDITH: // coop editing messages, should be extended to case SV_EDITH: // coop editing messages, should be extended to
@ -361,8 +365,8 @@ localservertoclient(unsigned char *buf, int len)
case SV_PONG: case SV_PONG:
addmsg(0, 2, SV_CLIENTPING, addmsg(0, 2, SV_CLIENTPING,
player1.ping = Player.player1.ping = (Player.player1.ping * 5 +
(player1.ping * 5 + lastmillis - getint(&p)) / lastmillis - getint(&p)) /
6); 6);
break; break;

View file

@ -8,8 +8,9 @@
#define _MAXDEFSTR 260 #define _MAXDEFSTR 260
@class Entity;
@class DynamicEntity; @class DynamicEntity;
@class Entity;
@class Player;
@interface Cube: OFObject <OFApplicationDelegate> @interface Cube: OFObject <OFApplicationDelegate>
@property (class, readonly, nonatomic) Cube *sharedInstance; @property (class, readonly, nonatomic) Cube *sharedInstance;
@ -256,8 +257,6 @@ extern struct sqr *world, *wmip[];
extern struct header hdr; // current map header extern struct header hdr; // current map header
extern int sfactor, ssize; // ssize = 2^sfactor extern int sfactor, ssize; // ssize = 2^sfactor
extern int cubicsize, mipsize; // cubicsize = ssize^2 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) // all the other clients (in multiplayer)
extern OFMutableArray *players; extern OFMutableArray *players;
extern bool editmode; extern bool editmode;

View file

@ -7,6 +7,7 @@
#import "DynamicEntity.h" #import "DynamicEntity.h"
#import "Monster.h" #import "Monster.h"
#import "OFString+Cube.h" #import "OFString+Cube.h"
#import "Player.h"
bool editmode = false; bool editmode = false;
@ -58,6 +59,7 @@ VAR(editing, 0, 0, 1);
void void
toggleedit() toggleedit()
{ {
Player *player1 = Player.player1;
if (player1.state == CS_DEAD) if (player1.state == CS_DEAD)
return; // do not allow dead players to edit to avoid state return; // do not allow dead players to edit to avoid state
// confusion // confusion
@ -157,6 +159,7 @@ sheight(struct sqr *s, struct sqr *t, float z)
void void
cursorupdate() // called every frame from hud cursorupdate() // called every frame from hud
{ {
Player *player1 = Player.player1;
flrceil = ((int)(player1.pitch >= 0)) * 2; flrceil = ((int)(player1.pitch >= 0)) * 2;
volatile float x = volatile float x =
@ -626,7 +629,7 @@ COMMAND(newent, ARG_5STR,
^(OFString *what, OFString *a1, OFString *a2, OFString *a3, OFString *a4) { ^(OFString *what, OFString *a1, OFString *a2, OFString *a3, OFString *a4) {
EDITSEL; 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], [a1 cube_intValueWithBase:0], [a2 cube_intValueWithBase:0],
[a3 cube_intValueWithBase:0], [a4 cube_intValueWithBase:0]); [a3 cube_intValueWithBase:0], [a4 cube_intValueWithBase:0]);
}) })

View file

@ -5,6 +5,7 @@
#import "DynamicEntity.h" #import "DynamicEntity.h"
#import "Entity.h" #import "Entity.h"
#import "MapModelInfo.h" #import "MapModelInfo.h"
#import "Player.h"
OFMutableArray<Entity *> *ents; OFMutableArray<Entity *> *ents;
@ -128,7 +129,7 @@ struct itemstat {
void void
baseammo(int gun) 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 // these two functions are called when the server acknowledges that you really
@ -147,7 +148,7 @@ radditem(int i, int v)
} }
void void
realpickup(int n, DynamicEntity *d) realpickup(int n, Player *d)
{ {
switch (ents[n].type) { switch (ents[n].type) {
case I_SHELLS: case I_SHELLS:
@ -294,6 +295,7 @@ pickup(int n, DynamicEntity *d)
lastjumppad = lastmillis; lastjumppad = lastmillis;
OFVector3D v = OFMakeVector3D((int)(char)ents[n].attr3 / 10.0f, OFVector3D v = OFMakeVector3D((int)(char)ents[n].attr3 / 10.0f,
(int)(char)ents[n].attr2 / 10.0f, ents[n].attr1 / 10.0f); (int)(char)ents[n].attr2 / 10.0f, ents[n].attr1 / 10.0f);
Player *player1 = Player.player1;
player1.velocity = OFAddVectors3D( player1.velocity = OFAddVectors3D(
OFMakeVector3D(player1.velocity.x, player1.velocity.y, 0), OFMakeVector3D(player1.velocity.x, player1.velocity.y, 0),
v); v);
@ -306,6 +308,8 @@ pickup(int n, DynamicEntity *d)
void void
checkitems() checkitems()
{ {
Player *player1 = Player.player1;
if (editmode) if (editmode)
return; return;
@ -331,6 +335,8 @@ checkitems()
void void
checkquad(int time) checkquad(int time)
{ {
Player *player1 = Player.player1;
if (player1.quadMillis && (player1.quadMillis -= time) < 0) { if (player1.quadMillis && (player1.quadMillis -= time) < 0) {
player1.quadMillis = 0; player1.quadMillis = 0;
playsoundc(S_PUPOUT); playsoundc(S_PUPOUT);

View file

@ -5,8 +5,8 @@
#import "Menu.h" #import "Menu.h"
#import "Command.h" #import "Command.h"
#import "DynamicEntity.h"
#import "MenuItem.h" #import "MenuItem.h"
#import "Player.h"
static OFMutableArray<OFNumber *> *menuStack; static OFMutableArray<OFNumber *> *menuStack;
static OFMutableArray<Menu *> *menus; static OFMutableArray<Menu *> *menus;
@ -16,7 +16,7 @@ void
menuset(int menu) menuset(int menu)
{ {
if ((vmenu = menu) >= 1) if ((vmenu = menu) >= 1)
[player1 resetMovement]; [Player.player1 resetMovement];
if (vmenu == 1) if (vmenu == 1)
menus[1].menusel = 0; menus[1].menusel = 0;
} }

View file

@ -15,6 +15,7 @@ executable('client',
'MenuItem.m', 'MenuItem.m',
'Monster.m', 'Monster.m',
'OFString+Cube.m', 'OFString+Cube.m',
'Player.m',
'Projectile.m', 'Projectile.m',
'ResolverResult.m', 'ResolverResult.m',
'ResolverThread.m', 'ResolverThread.m',

View file

@ -10,6 +10,7 @@
#import "Entity.h" #import "Entity.h"
#import "MapModelInfo.h" #import "MapModelInfo.h"
#import "Monster.h" #import "Monster.h"
#import "Player.h"
// collide with player or monster // collide with player or monster
static bool static bool
@ -179,8 +180,8 @@ collide(DynamicEntity *d, bool spawn, float drop, float rise)
return false; return false;
} }
if (d != player1) if (d != Player.player1)
if (!plcollide(d, player1, &headspace, &hi, &lo)) if (!plcollide(d, Player.player1, &headspace, &hi, &lo))
return false; return false;
// this loop can be a performance bottleneck with many monster on a slow // this loop can be a performance bottleneck with many monster on a slow

View file

@ -82,7 +82,7 @@ extern bool multiplayer();
extern bool allowedittoggle(); extern bool allowedittoggle();
extern void sendpackettoserv(void *packet); extern void sendpackettoserv(void *packet);
extern void gets2c(); extern void gets2c();
extern void c2sinfo(DynamicEntity *d); extern void c2sinfo(Player *d);
extern void neterr(OFString *s); extern void neterr(OFString *s);
extern void initclientnet(); extern void initclientnet();
extern bool netmapstart(); extern bool netmapstart();
@ -101,7 +101,7 @@ extern void spawnplayer(DynamicEntity *d);
extern void selfdamage(int damage, int actor, DynamicEntity *act); extern void selfdamage(int damage, int actor, DynamicEntity *act);
extern OFString *getclientmap(); extern OFString *getclientmap();
extern OFString *modestr(int n); extern OFString *modestr(int n);
extern DynamicEntity *getclient(int cn); extern Player *getclient(int cn);
extern void setclient(int cn, id client); extern void setclient(int cn, id client);
extern void timeupdate(int timeremain); extern void timeupdate(int timeremain);
extern void fixplayer1range(); extern void fixplayer1range();
@ -255,7 +255,7 @@ extern void renderents();
extern void putitems(unsigned char **p); extern void putitems(unsigned char **p);
extern void checkquad(int time); extern void checkquad(int time);
extern void checkitems(); extern void checkitems();
extern void realpickup(int n, DynamicEntity *d); extern void realpickup(int n, Player *d);
extern void renderentities(); extern void renderentities();
extern void resetspawns(); extern void resetspawns();
extern void setspawn(size_t i, bool on); extern void setspawn(size_t i, bool on);

View file

@ -3,8 +3,8 @@
#include "cube.h" #include "cube.h"
#import "Command.h" #import "Command.h"
#import "DynamicEntity.h"
#import "Entity.h" #import "Entity.h"
#import "Player.h"
void void
line(int x1, int y1, float z1, int x2, int y2, float z2) line(int x1, int y1, float z1, int x2, int y2, float z2)
@ -327,6 +327,8 @@ VARP(crosshairfx, 0, 1, 1);
void void
gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwater) gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwater)
{ {
Player *player1 = Player.player1;
readmatrices(); readmatrices();
if (editmode) { if (editmode) {
if (cursordepth == 1.0f) if (cursordepth == 1.0f)

View file

@ -5,9 +5,9 @@
#include "cube.h" #include "cube.h"
#import "Command.h" #import "Command.h"
#import "DynamicEntity.h"
#import "Monster.h" #import "Monster.h"
#import "OFString+Cube.h" #import "OFString+Cube.h"
#import "Player.h"
#ifdef DARWIN #ifdef DARWIN
# define GL_COMBINE_EXT GL_COMBINE_ARB # define GL_COMBINE_EXT GL_COMBINE_ARB
@ -345,6 +345,8 @@ VARFP(gamma, 30, 100, 300, {
void void
transplayer() transplayer()
{ {
Player *player1 = Player.player1;
glLoadIdentity(); glLoadIdentity();
glRotated(player1.roll, 0.0, 0.0, 1.0); glRotated(player1.roll, 0.0, 0.0, 1.0);
@ -372,6 +374,8 @@ OFString *hudgunnames[] = { @"hudguns/fist", @"hudguns/shotg",
void void
drawhudmodel(int start, int end, float speed, int base) drawhudmodel(int start, int end, float speed, int base)
{ {
Player *player1 = Player.player1;
rendermodel(hudgunnames[player1.gunSelect], start, end, 0, 1.0f, rendermodel(hudgunnames[player1.gunSelect], start, end, 0, 1.0f,
OFMakeVector3D( OFMakeVector3D(
player1.origin.x, player1.origin.z, player1.origin.y), player1.origin.x, player1.origin.z, player1.origin.y),
@ -381,6 +385,8 @@ drawhudmodel(int start, int end, float speed, int base)
void void
drawhudgun(float fovy, float aspect, int farplane) drawhudgun(float fovy, float aspect, int farplane)
{ {
Player *player1 = Player.player1;
if (!hudgun /*|| !player1.gunSelect*/) if (!hudgun /*|| !player1.gunSelect*/)
return; return;
@ -410,6 +416,7 @@ drawhudgun(float fovy, float aspect, int farplane)
void void
gl_drawframe(int w, int h, float curfps) gl_drawframe(int w, int h, float curfps)
{ {
Player *player1 = Player.player1;
float hf = hdr.waterlevel - 0.3f; float hf = hdr.waterlevel - 0.3f;
float fovy = (float)fov * h / w; float fovy = (float)fov * h / w;
float aspect = w / (float)h; float aspect = w / (float)h;

View file

@ -3,10 +3,10 @@
#include "cube.h" #include "cube.h"
#import "Command.h" #import "Command.h"
#import "DynamicEntity.h"
#import "MD2.h" #import "MD2.h"
#import "MapModelInfo.h" #import "MapModelInfo.h"
#import "OFString+Cube.h" #import "OFString+Cube.h"
#import "Player.h"
static OFMutableDictionary<OFString *, MD2 *> *mdllookup = nil; static OFMutableDictionary<OFString *, MD2 *> *mdllookup = nil;
static OFMutableArray<MD2 *> *mapmodels = nil; static OFMutableArray<MD2 *> *mapmodels = nil;
@ -90,8 +90,8 @@ rendermodel(OFString *mdl, int frame, int range, int tex, float rad,
{ {
MD2 *m = loadmodel(mdl); MD2 *m = loadmodel(mdl);
if (isoccluded(player1.origin.x, player1.origin.y, position.x - rad, if (isoccluded(Player.player1.origin.x, Player.player1.origin.y,
position.z - rad, rad * 2)) position.x - rad, position.z - rad, rad * 2))
return; return;
delayedload(m); delayedload(m);

View file

@ -2,7 +2,7 @@
#include "cube.h" #include "cube.h"
#import "DynamicEntity.h" #import "Player.h"
#define MAXPARTICLES 10500 #define MAXPARTICLES 10500
const int NUMPARTCUTOFF = 20; const int NUMPARTCUTOFF = 20;
@ -56,8 +56,8 @@ void
render_particles(int time) render_particles(int time)
{ {
if (demoplayback && demotracking) if (demoplayback && demotracking)
newparticle( newparticle(Player.player1.origin, OFMakeVector3D(0, 0, 0),
player1.origin, OFMakeVector3D(0, 0, 0), 100000000, 8); 100000000, 8);
glDepthMask(GL_FALSE); glDepthMask(GL_FALSE);
glEnable(GL_BLEND); glEnable(GL_BLEND);

View file

@ -4,9 +4,9 @@
#include "cube.h" #include "cube.h"
#import "Command.h" #import "Command.h"
#import "DynamicEntity.h"
#import "Entity.h" #import "Entity.h"
#import "Monster.h" #import "Monster.h"
#import "Player.h"
#ifdef OF_BIG_ENDIAN #ifdef OF_BIG_ENDIAN
static const int islittleendian = 0; static const int islittleendian = 0;
@ -18,7 +18,7 @@ static gzFile f = NULL;
bool demorecording = false; bool demorecording = false;
bool demoplayback = false; bool demoplayback = false;
bool demoloading = false; bool demoloading = false;
static OFMutableArray<DynamicEntity *> *playerhistory; static OFMutableArray<Player *> *playerhistory;
int democlientnum = 0; int democlientnum = 0;
extern void startdemo(); extern void startdemo();
@ -105,7 +105,7 @@ savestate(OFIRI *IRI)
gzwrite(f, (void *)"CUBESAVE", 8); gzwrite(f, (void *)"CUBESAVE", 8);
gzputc(f, islittleendian); gzputc(f, islittleendian);
gzputi(SAVEGAMEVERSION); gzputi(SAVEGAMEVERSION);
OFData *data = [player1 dataBySerializing]; OFData *data = [Player.player1 dataBySerializing];
gzputi(data.count); gzputi(data.count);
char map[_MAXDEFSTR] = { 0 }; char map[_MAXDEFSTR] = { 0 };
memcpy(map, getclientmap().UTF8String, memcpy(map, getclientmap().UTF8String,
@ -219,8 +219,8 @@ loadgamerest()
[OFMutableData dataWithCapacity:DynamicEntity.serializedSize]; [OFMutableData dataWithCapacity:DynamicEntity.serializedSize];
[data increaseCountBy:DynamicEntity.serializedSize]; [data increaseCountBy:DynamicEntity.serializedSize];
gzread(f, data.mutableItems, data.count); gzread(f, data.mutableItems, data.count);
[player1 setFromSerializedData:data]; [Player.player1 setFromSerializedData:data];
player1.lastAction = lastmillis; Player.player1.lastAction = lastmillis;
int nmonsters = gzgeti(); int nmonsters = gzgeti();
OFArray<Monster *> *monsters = Monster.monsters; OFArray<Monster *> *monsters = Monster.monsters;
@ -231,7 +231,7 @@ loadgamerest()
gzread(f, data.mutableItems, data.count); gzread(f, data.mutableItems, data.count);
[monster setFromSerializedData:data]; [monster setFromSerializedData:data];
// lazy, could save id of enemy instead // lazy, could save id of enemy instead
monster.enemy = player1; monster.enemy = Player.player1;
// also lazy, but no real noticable effect on game // also lazy, but no real noticable effect on game
monster.lastAction = monster.trigger = lastmillis + 500; monster.lastAction = monster.trigger = lastmillis + 500;
if (monster.state == CS_DEAD) if (monster.state == CS_DEAD)
@ -242,7 +242,7 @@ loadgamerest()
int nplayers = gzgeti(); int nplayers = gzgeti();
for (int i = 0; i < nplayers; i++) { for (int i = 0; i < nplayers; i++) {
if (!gzget()) { if (!gzget()) {
DynamicEntity *d = getclient(i); Player *d = getclient(i);
assert(d); assert(d);
gzread(f, data.mutableItems, data.count); gzread(f, data.mutableItems, data.count);
[d setFromSerializedData:data]; [d setFromSerializedData:data];
@ -300,8 +300,11 @@ demoblend(int damage)
void void
incomingdemodata(unsigned char *buf, int len, bool extras) incomingdemodata(unsigned char *buf, int len, bool extras)
{ {
Player *player1 = Player.player1;
if (!demorecording) if (!demorecording)
return; return;
gzputi(lastmillis - starttime); gzputi(lastmillis - starttime);
gzputi(len); gzputi(len);
gzwrite(f, buf, len); gzwrite(f, buf, len);
@ -370,7 +373,7 @@ startdemo()
demoplayback = true; demoplayback = true;
starttime = lastmillis; starttime = lastmillis;
conoutf(@"now playing demo"); conoutf(@"now playing demo");
setclient(democlientnum, [player1 copy]); setclient(democlientnum, [Player.player1 copy]);
readdemotime(); readdemotime();
} }
@ -421,7 +424,7 @@ demoplaybackstep()
gzread(f, buf, len); gzread(f, buf, len);
localservertoclient(buf, len); // update game state localservertoclient(buf, len); // update game state
DynamicEntity *target = players[democlientnum]; Player *target = players[democlientnum];
assert(target); assert(target);
int extras; int extras;
@ -452,7 +455,7 @@ demoplaybackstep()
if (extras && if (extras &&
(playerhistory.count == 0 || (playerhistory.count == 0 ||
playerhistory.lastObject.lastUpdate != playbacktime)) { playerhistory.lastObject.lastUpdate != playbacktime)) {
DynamicEntity *d = [target copy]; Player *d = [target copy];
d.lastUpdate = playbacktime; d.lastUpdate = playbacktime;
if (playerhistory == nil) if (playerhistory == nil)
@ -475,13 +478,13 @@ demoplaybackstep()
size_t count = playerhistory.count; size_t count = playerhistory.count;
for (ssize_t i = count - 1; i >= 0; i--) { for (ssize_t i = count - 1; i >= 0; i--) {
if (playerhistory[i].lastUpdate < itime) { if (playerhistory[i].lastUpdate < itime) {
DynamicEntity *a = playerhistory[i]; Player *a = playerhistory[i];
DynamicEntity *b = a; Player *b = a;
if (i + 1 < playerhistory.count) if (i + 1 < playerhistory.count)
b = playerhistory[i + 1]; b = playerhistory[i + 1];
player1 = b; Player.player1 = b;
// interpolate pos & angles // interpolate pos & angles
if (a != b) { if (a != b) {
DynamicEntity *c = b; DynamicEntity *c = b;
@ -494,15 +497,15 @@ demoplaybackstep()
// printf("* %d\n", lastmillis); // printf("* %d\n", lastmillis);
float bf = (itime - a.lastUpdate) / float bf = (itime - a.lastUpdate) /
(float)(b.lastUpdate - a.lastUpdate); (float)(b.lastUpdate - a.lastUpdate);
fixwrap(a, player1); fixwrap(a, b);
fixwrap(c, player1); fixwrap(c, b);
fixwrap(z, player1); fixwrap(z, b);
float dist = float dist =
OFDistanceOfVectors3D(c.origin, z.origin); OFDistanceOfVectors3D(c.origin, z.origin);
// if teleport or spawn, don't interpolate // if teleport or spawn, don't interpolate
if (dist < 16) { if (dist < 16) {
catmulrom(z.origin, a.origin, b.origin, catmulrom(z.origin, a.origin, b.origin,
c.origin, bf, player1.origin); c.origin, bf, b.origin);
OFVector3D vz = OFMakeVector3D( OFVector3D vz = OFMakeVector3D(
z.yaw, z.pitch, z.roll); z.yaw, z.pitch, z.roll);
OFVector3D va = OFMakeVector3D( OFVector3D va = OFMakeVector3D(
@ -511,9 +514,8 @@ demoplaybackstep()
b.yaw, b.pitch, b.roll); b.yaw, b.pitch, b.roll);
OFVector3D vc = OFMakeVector3D( OFVector3D vc = OFMakeVector3D(
c.yaw, c.pitch, c.roll); c.yaw, c.pitch, c.roll);
OFVector3D vp1 = OFVector3D vp1 = OFMakeVector3D(
OFMakeVector3D(player1.yaw, b.yaw, b.pitch, b.roll);
player1.pitch, player1.roll);
catmulrom(vz, va, vb, vc, bf, vp1); catmulrom(vz, va, vb, vc, bf, vp1);
z.yaw = vz.x; z.yaw = vz.x;
z.pitch = vz.y; z.pitch = vz.y;
@ -527,9 +529,9 @@ demoplaybackstep()
c.yaw = vc.x; c.yaw = vc.x;
c.pitch = vc.y; c.pitch = vc.y;
c.roll = vc.z; c.roll = vc.z;
player1.yaw = vp1.x; b.yaw = vp1.x;
player1.pitch = vp1.y; b.pitch = vp1.y;
player1.roll = vp1.z; b.roll = vp1.z;
} }
fixplayer1range(); fixplayer1range();
} }

View file

@ -1,7 +1,7 @@
#include "cube.h" #include "cube.h"
#import "Command.h" #import "Command.h"
#import "DynamicEntity.h" #import "Player.h"
#include <SDL_mixer.h> #include <SDL_mixer.h>
@ -113,7 +113,7 @@ updatechanvol(int chan, const OFVector3D *loc)
int vol = soundvol, pan = 255 / 2; int vol = soundvol, pan = 255 / 2;
if (loc) { if (loc) {
OFVector3D origin = player1.origin; OFVector3D origin = Player.player1.origin;
float dist = OFDistanceOfVectors3D(origin, *loc); float dist = OFDistanceOfVectors3D(origin, *loc);
OFVector3D v = OFSubtractVectors3D(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)) { if (stereo && (v.x != 0 || v.y != 0)) {
// relative angle of sound along X-Y axis // relative angle of sound along X-Y axis
float yaw = float yaw = -atan2(v.x, v.y) -
-atan2(v.x, v.y) - player1.yaw * (PI / 180.0f); Player.player1.yaw * (PI / 180.0f);
// range is from 0 (left) to 255 (right) // range is from 0 (left) to 255 (right)
pan = (int)(255.9f * (0.5 * sin(yaw) + 0.5f)); pan = (int)(255.9f * (0.5 * sin(yaw) + 0.5f));
} }

View file

@ -6,6 +6,7 @@
#import "DynamicEntity.h" #import "DynamicEntity.h"
#import "Monster.h" #import "Monster.h"
#import "OFString+Cube.h" #import "OFString+Cube.h"
#import "Player.h"
#import "Projectile.h" #import "Projectile.h"
static const int MONSTERDAMAGEFACTOR = 4; 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 || if (a < -1 || b < -1 || c < -1 || a >= NUMGUNS || b >= NUMGUNS ||
c >= NUMGUNS) c >= NUMGUNS)
return; return;
Player *player1 = Player.player1;
int s = player1.gunSelect; int s = player1.gunSelect;
if (a >= 0 && s != a && player1.ammo[a]) if (a >= 0 && s != a && player1.ammo[a])
s = a; s = a;
@ -112,11 +115,11 @@ playerincrosshair()
if (demoplayback) if (demoplayback)
return NULL; return NULL;
for (id player in players) { OFVector3D o = Player.player1.origin;
if (player == [OFNull null]) for (Player *player in players) {
if (![Player isKindOfClass:Player.class])
continue; continue;
OFVector3D o = player1.origin;
if (intersect(player, o, worldpos)) if (intersect(player, o, worldpos))
return [player name]; return [player name];
} }
@ -162,12 +165,13 @@ static void
hit(int target, int damage, __kindof DynamicEntity *d, DynamicEntity *at) hit(int target, int damage, __kindof DynamicEntity *d, DynamicEntity *at)
{ {
OFVector3D o = d.origin; OFVector3D o = d.origin;
if (d == player1) if (d == Player.player1)
selfdamage(damage, at == player1 ? -1 : -2, at); selfdamage(damage, (at == Player.player1) ? -1 : -2, at);
else if ([d isKindOfClass:Monster.class]) else if ([d isKindOfClass:Monster.class])
[d incurDamage:damage fromEntity:at]; [d incurDamage:damage fromEntity:at];
else { else if ([d isKindOfClass:Player.class]) {
addmsg(1, 4, SV_DAMAGE, target, damage, d.lifeSequence); addmsg(1, 4, SV_DAMAGE, target, damage,
((Player *)d).lifeSequence);
playsound(S_PAIN1 + rnd(5), &o); playsound(S_PAIN1 + rnd(5), &o);
} }
particle_splash(3, damage, 1000, o); particle_splash(3, damage, 1000, o);
@ -219,7 +223,7 @@ splash(Projectile *p, OFVector3D v, OFVector3D vold, int notthisplayer,
if (!p.local) if (!p.local)
return; return;
radialeffect(player1, v, -1, qdam, p.owner); radialeffect(Player.player1, v, -1, qdam, p.owner);
[players enumerateObjectsUsingBlock:^( [players enumerateObjectsUsingBlock:^(
id player, size_t i, bool *stop) { id player, size_t i, bool *stop) {
@ -279,8 +283,8 @@ moveprojectiles(float time)
if (player != [OFNull null]) if (player != [OFNull null])
projdamage(player, p, v, i, -1, qdam); projdamage(player, p, v, i, -1, qdam);
if (p.owner != player1) if (p.owner != Player.player1)
projdamage(player1, p, v, -1, -1, qdam); projdamage(Player.player1, p, v, -1, -1, qdam);
for (Monster *monster in Monster.monsters) for (Monster *monster in Monster.monsters)
if (!vreject(monster.origin, v, 10.0f) && if (!vreject(monster.origin, v, 10.0f) &&
@ -310,7 +314,7 @@ void
shootv(int gun, OFVector3D from, OFVector3D to, DynamicEntity *d, bool local) shootv(int gun, OFVector3D from, OFVector3D to, DynamicEntity *d, bool local)
{ {
OFVector3D loc = d.origin; OFVector3D loc = d.origin;
playsound(guns[gun].sound, d == player1 ? NULL : &loc); playsound(guns[gun].sound, (d == Player.player1) ? NULL : &loc);
int pspeed = 25; int pspeed = 25;
switch (gun) { switch (gun) {
case GUN_FIST: case GUN_FIST:
@ -438,5 +442,5 @@ shoot(DynamicEntity *d, OFVector3D targ)
raydamage(monster, from, to, d, -2); raydamage(monster, from, to, d, -2);
if ([d isKindOfClass:Monster.class]) if ([d isKindOfClass:Monster.class])
raydamage(player1, from, to, d, -1); raydamage(Player.player1, from, to, d, -1);
} }

View file

@ -3,9 +3,9 @@
#include "cube.h" #include "cube.h"
#import "Command.h" #import "Command.h"
#import "DynamicEntity.h"
#import "Entity.h" #import "Entity.h"
#import "Monster.h" #import "Monster.h"
#import "Player.h"
extern OFString *entnames[]; // lookup from map entities above to strings extern OFString *entnames[]; // lookup from map entities above to strings
@ -298,7 +298,7 @@ closestent() // used for delent and edit mode ent display
return; return;
OFVector3D v = OFMakeVector3D(e.x, e.y, e.z); 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) { if (dist < bdist) {
best = i; best = i;
bdist = dist; 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: case TELEDEST:
e.attr2 = (unsigned char)e.attr1; e.attr2 = (unsigned char)e.attr1;
case PLAYERSTART: case PLAYERSTART:
e.attr1 = (int)player1.yaw; e.attr1 = (int)Player.player1.yaw;
break; break;
} }
addmsg(1, 10, SV_EDITENT, ents.count, type, e.x, e.y, e.z, e.attr1, addmsg(1, 10, SV_EDITENT, ents.count, type, e.x, e.y, e.z, e.attr1,

View file

@ -3,7 +3,7 @@
#include "cube.h" #include "cube.h"
#import "Command.h" #import "Command.h"
#import "DynamicEntity.h" #import "Player.h"
#define NUMRAYS 512 #define NUMRAYS 512
@ -21,6 +21,8 @@ COMMAND(toggleocull, ARG_NONE, ^{
void void
computeraytable(float vx, float vy) computeraytable(float vx, float vy)
{ {
Player *player1 = Player.player1;
if (!ocull) if (!ocull)
return; return;

View file

@ -4,7 +4,7 @@
#include "cube.h" #include "cube.h"
#import "DynamicEntity.h" #import "Player.h"
void void
render_wall(struct sqr *o, struct sqr *s, int x1, int y1, int x2, int y2, 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; int ry = vyy + lodbot;
float fsize = (float)(1 << mip); float fsize = (float)(1 << mip);
Player *player1 = Player.player1;
for (int ox = x; ox < xs; ox++) { for (int ox = x; ox < xs; ox++) {
// first collect occlusion information for this block // first collect occlusion information for this block
for (int oy = y; oy < ys; oy++) { for (int oy = y; oy < ys; oy++) {