X-Git-Url: https://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fserver%2Fclient.qc;h=d8a8c3c52e5f4aeeffa9274870b324eb5b2eaedd;hp=7ff2f028f0faf330492b3f4dcb41546c72723495;hb=67410278136b3bf6c5437027ab2f39d0da49753c;hpb=00a0bc7a2ef3ba8b9c0d7edb1c066b8dac3d0298 diff --git a/qcsrc/server/client.qc b/qcsrc/server/client.qc index 7ff2f028f0..d8a8c3c52e 100644 --- a/qcsrc/server/client.qc +++ b/qcsrc/server/client.qc @@ -112,9 +112,9 @@ bool ClientData_Send(entity this, entity to, int sf) if (IS_SPEC(e)) e = e.enemy; sf = 0; - if (e.race_completed) sf |= 1; // forced scoreboard - if (to.spectatee_status) sf |= 2; // spectator ent number follows - if (e.zoomstate) sf |= 4; // zoomed + if (CS(e).race_completed) sf |= 1; // forced scoreboard + if (CS(to).spectatee_status) sf |= 2; // spectator ent number follows + if (CS(e).zoomstate) sf |= 4; // zoomed if (autocvar_sv_showspectators) sf |= 16; // show spectators WriteHeader(MSG_ENTITY, ENT_CLIENT_CLIENTDATA); @@ -122,7 +122,7 @@ bool ClientData_Send(entity this, entity to, int sf) if (sf & 2) { - WriteByte(MSG_ENTITY, to.spectatee_status); + WriteByte(MSG_ENTITY, CS(to).spectatee_status); } if(sf & 16) @@ -137,27 +137,25 @@ bool ClientData_Send(entity this, entity to, int sf) void ClientData_Attach(entity this) { - Net_LinkEntity(this.clientdata = new_pure(clientdata), false, 0, ClientData_Send); - this.clientdata.drawonlytoclient = this; - this.clientdata.owner = this; + Net_LinkEntity(CS(this).clientdata = new_pure(clientdata), false, 0, ClientData_Send); + CS(this).clientdata.drawonlytoclient = this; + CS(this).clientdata.owner = this; } void ClientData_Detach(entity this) { - delete(this.clientdata); - this.clientdata = NULL; + delete(CS(this).clientdata); + CS(this).clientdata = NULL; } void ClientData_Touch(entity e) { - e.clientdata.SendFlags = 1; + CS(e).clientdata.SendFlags = 1; // make it spectatable - FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != e && IS_SPEC(it) && it.enemy == e, LAMBDA(it.clientdata.SendFlags = 1)); + FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != e && IS_SPEC(it) && it.enemy == e, LAMBDA(CS(it).clientdata.SendFlags = 1)); } -.string netname_previous; - void SetSpectatee(entity this, entity spectatee); void SetSpectatee_status(entity this, int spectatee_num); @@ -229,12 +227,10 @@ void PutObserverInServer(entity this) { entity spot = SelectSpawnPoint(this, true); if (!spot) LOG_FATAL("No spawnpoints for observers?!?"); - this.angles = spot.angles; - this.angles_z = 0; + this.angles = vec2(spot.angles); this.fixangle = true; // offset it so that the spectator spawns higher off the ground, looks better this way setorigin(this, spot.origin + STAT(PL_VIEW_OFS, this)); - this.prevorigin = this.origin; if (IS_REAL_CLIENT(this)) { msg_entity = this; @@ -278,22 +274,22 @@ void PutObserverInServer(entity this) PlayerScore_Clear(this); // clear scores when needed } - if (this.killcount != FRAGS_SPECTATOR) + if (CS(this).killcount != FRAGS_SPECTATOR) { Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_SPECTATE, this.netname); if(!game_stopped) if(autocvar_g_chat_nospectators == 1 || (!warmup_stage && autocvar_g_chat_nospectators == 2)) Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_CHAT_NOSPECTATORS); - if(this.just_joined == false) { + if(!CS(this).just_joined) LogTeamchange(this.playerid, -1, 4); - } else - this.just_joined = false; + else + CS(this).just_joined = false; } accuracy_resend(this); - this.spectatortime = time; + CS(this).spectatortime = time; if(this.bot_attack) IL_REMOVE(g_bot_targets, this); this.bot_attack = false; @@ -340,7 +336,6 @@ void PutObserverInServer(entity this) this.items = 0; this.weapons = '0 0 0'; - this.dual_weapons = '0 0 0'; this.drawonlytoclient = this; this.weaponmodel = ""; @@ -349,7 +344,7 @@ void PutObserverInServer(entity this) this.weaponentities[slot] = NULL; } this.exteriorweaponentity = NULL; - this.killcount = FRAGS_SPECTATOR; + CS(this).killcount = FRAGS_SPECTATOR; this.velocity = '0 0 0'; this.avelocity = '0 0 0'; this.punchangle = '0 0 0'; @@ -404,7 +399,7 @@ void FixPlayermodel(entity player) int n = tokenize_console(defaultmodel); if(n > 0) { - defaultmodel = argv(floor(n * player.model_randomizer)); + defaultmodel = argv(floor(n * CS(player).model_randomizer)); // However, do NOT randomize if the player-selected model is in the list. for (int i = 0; i < n; ++i) if ((argv(i) == player.playermodel && defaultskin == stof(player.playerskin)) || argv(i) == strcat(player.playermodel, ":", player.playerskin)) @@ -490,251 +485,257 @@ void FixPlayermodel(entity player) setcolor(player, stof(autocvar_sv_defaultplayercolors)); } - -/** Called when a client spawns in the server */ -void PutClientInServer(entity this) +void PutPlayerInServer(entity this) { - if (IS_BOT_CLIENT(this)) { - TRANSMUTE(Player, this); - } else if (IS_REAL_CLIENT(this)) { - msg_entity = this; - WriteByte(MSG_ONE, SVC_SETVIEW); - WriteEntity(MSG_ONE, this); + if (this.vehicle) vehicles_exit(this.vehicle, VHEF_RELEASE); + + PlayerState_attach(this); + accuracy_resend(this); + + if (this.team < 0) + JoinBestTeam(this, false, true); + + entity spot = SelectSpawnPoint(this, false); + if (!spot) { + Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_JOIN_NOSPAWNS); + return; // spawn failed } - if (game_stopped) - TRANSMUTE(Observer, this); - SetSpectatee(this, NULL); + TRANSMUTE(Player, this); - // reset player keys - this.itemkeys = 0; + CS(this).wasplayer = true; + this.iscreature = true; + this.teleportable = TELEPORT_NORMAL; + if(!this.damagedbycontents) + IL_PUSH(g_damagedbycontents, this); + this.damagedbycontents = true; + set_movetype(this, MOVETYPE_WALK); + this.solid = SOLID_SLIDEBOX; + this.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID; + if (autocvar_g_playerclip_collisions) + this.dphitcontentsmask |= DPCONTENTS_PLAYERCLIP; + if (IS_BOT_CLIENT(this) && autocvar_g_botclip_collisions) + this.dphitcontentsmask |= DPCONTENTS_BOTCLIP; + this.frags = FRAGS_PLAYER; + if (INDEPENDENT_PLAYERS) MAKE_INDEPENDENT_PLAYER(this); + this.flags = FL_CLIENT | FL_PICKUPITEMS; + if (autocvar__notarget) + this.flags |= FL_NOTARGET; + this.takedamage = DAMAGE_AIM; + this.effects = EF_TELEPORT_BIT | EF_RESTARTANIM_BIT; + this.dmg = 2; // WTF + + if (warmup_stage) { + this.ammo_shells = warmup_start_ammo_shells; + this.ammo_nails = warmup_start_ammo_nails; + this.ammo_rockets = warmup_start_ammo_rockets; + this.ammo_cells = warmup_start_ammo_cells; + this.ammo_plasma = warmup_start_ammo_plasma; + this.ammo_fuel = warmup_start_ammo_fuel; + this.health = warmup_start_health; + this.armorvalue = warmup_start_armorvalue; + this.weapons = WARMUP_START_WEAPONS; + } else { + this.ammo_shells = start_ammo_shells; + this.ammo_nails = start_ammo_nails; + this.ammo_rockets = start_ammo_rockets; + this.ammo_cells = start_ammo_cells; + this.ammo_plasma = start_ammo_plasma; + this.ammo_fuel = start_ammo_fuel; + this.health = start_health; + this.armorvalue = start_armorvalue; + this.weapons = start_weapons; + } + SetSpectatee_status(this, 0); + + PS(this).dual_weapons = '0 0 0'; + + this.superweapons_finished = (this.weapons & WEPSET_SUPERWEAPONS) ? time + autocvar_g_balance_superweapons_time : 0; + + this.items = start_items; + + this.spawnshieldtime = time + autocvar_g_spawnshieldtime; + this.pauserotarmor_finished = time + autocvar_g_balance_pause_armor_rot_spawn; + this.pauserothealth_finished = time + autocvar_g_balance_pause_health_rot_spawn; + this.pauserotfuel_finished = time + autocvar_g_balance_pause_fuel_rot_spawn; + this.pauseregen_finished = time + autocvar_g_balance_pause_health_regen_spawn; + // extend the pause of rotting if client was reset at the beginning of the countdown + if (!autocvar_sv_ready_restart_after_countdown && time < game_starttime) { // TODO why is this cvar NOTted? + float f = game_starttime - time; + this.spawnshieldtime += f; + this.pauserotarmor_finished += f; + this.pauserothealth_finished += f; + this.pauseregen_finished += f; + } + this.damageforcescale = 2; + this.death_time = 0; + this.respawn_flags = 0; + this.respawn_time = 0; + this.stat_respawn_time = 0; + this.scale = autocvar_sv_player_scale; + this.fade_time = 0; + this.pain_frame = 0; + this.pain_finished = 0; + this.pushltime = 0; + setthink(this, func_null); // players have no think function + this.nextthink = 0; + this.dmg_team = 0; + PS(this).ballistics_density = autocvar_g_ballistics_density_player; - MUTATOR_CALLHOOK(PutClientInServer, this); + this.deadflag = DEAD_NO; - if (IS_OBSERVER(this)) { - PutObserverInServer(this); - } else if (IS_PLAYER(this)) { - if (this.vehicle) vehicles_exit(this.vehicle, VHEF_RELEASE); + this.angles = spot.angles; + this.angles_z = 0; // never spawn tilted even if the spot says to + if (IS_BOT_CLIENT(this)) + this.v_angle = this.angles; + this.fixangle = true; // turn this way immediately + this.oldvelocity = this.velocity = '0 0 0'; + this.avelocity = '0 0 0'; + this.punchangle = '0 0 0'; + this.punchvector = '0 0 0'; - PlayerState_attach(this); - accuracy_resend(this); + this.strength_finished = 0; + this.invincible_finished = 0; + this.fire_endtime = -1; + this.revive_progress = 0; + this.revival_time = 0; + this.air_finished = time + 12; - if (this.team < 0) - JoinBestTeam(this, false, true); + entity spawnevent = new_pure(spawnevent); + spawnevent.owner = this; + Net_LinkEntity(spawnevent, false, 0.5, SpawnEvent_Send); - entity spot = SelectSpawnPoint(this, false); - if (!spot) { - Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_JOIN_NOSPAWNS); - return; // spawn failed - } + // Cut off any still running player sounds. + stopsound(this, CH_PLAYER_SINGLE); - TRANSMUTE(Player, this); + this.model = ""; + FixPlayermodel(this); + this.drawonlytoclient = NULL; - this.wasplayer = true; - this.iscreature = true; - this.teleportable = TELEPORT_NORMAL; - if(!this.damagedbycontents) - IL_PUSH(g_damagedbycontents, this); - this.damagedbycontents = true; - set_movetype(this, MOVETYPE_WALK); - this.solid = SOLID_SLIDEBOX; - this.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID; - if (autocvar_g_playerclip_collisions) - this.dphitcontentsmask |= DPCONTENTS_PLAYERCLIP; - if (IS_BOT_CLIENT(this) && autocvar_g_botclip_collisions) - this.dphitcontentsmask |= DPCONTENTS_BOTCLIP; - this.frags = FRAGS_PLAYER; - if (INDEPENDENT_PLAYERS) MAKE_INDEPENDENT_PLAYER(this); - this.flags = FL_CLIENT | FL_PICKUPITEMS; - if (autocvar__notarget) - this.flags |= FL_NOTARGET; - this.takedamage = DAMAGE_AIM; - this.effects = EF_TELEPORT_BIT | EF_RESTARTANIM_BIT; - this.dmg = 2; // WTF - - if (warmup_stage) { - this.ammo_shells = warmup_start_ammo_shells; - this.ammo_nails = warmup_start_ammo_nails; - this.ammo_rockets = warmup_start_ammo_rockets; - this.ammo_cells = warmup_start_ammo_cells; - this.ammo_plasma = warmup_start_ammo_plasma; - this.ammo_fuel = warmup_start_ammo_fuel; - this.health = warmup_start_health; - this.armorvalue = warmup_start_armorvalue; - this.weapons = WARMUP_START_WEAPONS; - } else { - this.ammo_shells = start_ammo_shells; - this.ammo_nails = start_ammo_nails; - this.ammo_rockets = start_ammo_rockets; - this.ammo_cells = start_ammo_cells; - this.ammo_plasma = start_ammo_plasma; - this.ammo_fuel = start_ammo_fuel; - this.health = start_health; - this.armorvalue = start_armorvalue; - this.weapons = start_weapons; - } - SetSpectatee_status(this, 0); - - this.dual_weapons = '0 0 0'; - - this.superweapons_finished = (this.weapons & WEPSET_SUPERWEAPONS) ? time + autocvar_g_balance_superweapons_time : 0; - - this.items = start_items; - - this.spawnshieldtime = time + autocvar_g_spawnshieldtime; - this.pauserotarmor_finished = time + autocvar_g_balance_pause_armor_rot_spawn; - this.pauserothealth_finished = time + autocvar_g_balance_pause_health_rot_spawn; - this.pauserotfuel_finished = time + autocvar_g_balance_pause_fuel_rot_spawn; - this.pauseregen_finished = time + autocvar_g_balance_pause_health_regen_spawn; - // extend the pause of rotting if client was reset at the beginning of the countdown - if (!autocvar_sv_ready_restart_after_countdown && time < game_starttime) { // TODO why is this cvar NOTted? - float f = game_starttime - time; - this.spawnshieldtime += f; - this.pauserotarmor_finished += f; - this.pauserothealth_finished += f; - this.pauseregen_finished += f; - } - this.damageforcescale = 2; - this.death_time = 0; - this.respawn_flags = 0; - this.respawn_time = 0; - this.stat_respawn_time = 0; - this.scale = autocvar_sv_player_scale; - this.fade_time = 0; - this.pain_frame = 0; - this.pain_finished = 0; - this.pushltime = 0; - setthink(this, func_null); // players have no think function - this.nextthink = 0; - this.dmg_team = 0; - this.ballistics_density = autocvar_g_ballistics_density_player; - - this.deadflag = DEAD_NO; - - this.angles = spot.angles; - this.angles_z = 0; // never spawn tilted even if the spot says to - if (IS_BOT_CLIENT(this)) - this.v_angle = this.angles; - this.fixangle = true; // turn this way immediately - this.oldvelocity = this.velocity = '0 0 0'; - this.avelocity = '0 0 0'; - this.punchangle = '0 0 0'; - this.punchvector = '0 0 0'; - - this.strength_finished = 0; - this.invincible_finished = 0; - this.fire_endtime = -1; - this.revive_progress = 0; - this.revival_time = 0; - this.air_finished = time + 12; - - entity spawnevent = new_pure(spawnevent); - spawnevent.owner = this; - Net_LinkEntity(spawnevent, false, 0.5, SpawnEvent_Send); - - // Cut off any still running player sounds. - stopsound(this, CH_PLAYER_SINGLE); - - this.model = ""; - FixPlayermodel(this); - this.drawonlytoclient = NULL; - - this.viewloc = NULL; - - this.crouch = false; - this.view_ofs = STAT(PL_VIEW_OFS, this); - setsize(this, STAT(PL_MIN, this), STAT(PL_MAX, this)); - this.spawnorigin = spot.origin; - setorigin(this, spot.origin + '0 0 1' * (1 - this.mins.z - 24)); - // don't reset back to last position, even if new position is stuck in solid - this.oldorigin = this.origin; - this.prevorigin = this.origin; - this.lastteleporttime = time; // prevent insane speeds due to changing origin - if(this.conveyor) - IL_REMOVE(g_conveyed, this); - this.conveyor = NULL; // prevent conveyors at the previous location from moving a freshly spawned player - this.hud = HUD_NORMAL; - - this.event_damage = PlayerDamage; - - if(!this.bot_attack) - IL_PUSH(g_bot_targets, this); - this.bot_attack = true; - this.monster_attack = true; - navigation_dynamicgoal_init(this, false); - - PHYS_INPUT_BUTTON_ATCK(this) = PHYS_INPUT_BUTTON_JUMP(this) = PHYS_INPUT_BUTTON_ATCK2(this) = false; - - if (this.killcount == FRAGS_SPECTATOR) { - PlayerScore_Clear(this); - this.killcount = 0; - } + this.viewloc = NULL; - for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) - { - .entity weaponentity = weaponentities[slot]; - entity oldwep = this.(weaponentity); - CL_SpawnWeaponentity(this, weaponentity); - if(oldwep && oldwep.owner == this) - this.(weaponentity).m_gunalign = oldwep.m_gunalign; - } - this.alpha = default_player_alpha; - this.colormod = '1 1 1' * autocvar_g_player_brightness; - this.exteriorweaponentity.alpha = default_weapon_alpha; + this.crouch = false; + this.view_ofs = STAT(PL_VIEW_OFS, this); + setsize(this, STAT(PL_MIN, this), STAT(PL_MAX, this)); + this.spawnorigin = spot.origin; + setorigin(this, spot.origin + '0 0 1' * (1 - this.mins.z - 24)); + // don't reset back to last position, even if new position is stuck in solid + this.oldorigin = this.origin; + this.lastteleporttime = time; // prevent insane speeds due to changing origin + if(this.conveyor) + IL_REMOVE(g_conveyed, this); + this.conveyor = NULL; // prevent conveyors at the previous location from moving a freshly spawned player + this.hud = HUD_NORMAL; + + this.event_damage = PlayerDamage; + + if(!this.bot_attack) + IL_PUSH(g_bot_targets, this); + this.bot_attack = true; + if(!this.monster_attack) + IL_PUSH(g_monster_targets, this); + this.monster_attack = true; + navigation_dynamicgoal_init(this, false); + + PHYS_INPUT_BUTTON_ATCK(this) = PHYS_INPUT_BUTTON_JUMP(this) = PHYS_INPUT_BUTTON_ATCK2(this) = false; + + if (CS(this).killcount == FRAGS_SPECTATOR) { + PlayerScore_Clear(this); + CS(this).killcount = 0; + } + + for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + entity oldwep = this.(weaponentity); + CL_SpawnWeaponentity(this, weaponentity); + if(oldwep && oldwep.owner == this) + this.(weaponentity).m_gunalign = oldwep.m_gunalign; + } + this.alpha = default_player_alpha; + this.colormod = '1 1 1' * autocvar_g_player_brightness; + this.exteriorweaponentity.alpha = default_weapon_alpha; - this.speedrunning = false; + this.speedrunning = false; - target_voicescript_clear(this); + target_voicescript_clear(this); - // reset fields the weapons may use - FOREACH(Weapons, true, LAMBDA( - it.wr_resetplayer(it, this); + // reset fields the weapons may use + FOREACH(Weapons, true, LAMBDA( + it.wr_resetplayer(it, this); // reload all reloadable weapons - if (it.spawnflags & WEP_FLAG_RELOADABLE) { - for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) - { - .entity weaponentity = weaponentities[slot]; - this.(weaponentity).weapon_load[it.m_id] = it.reloading_ammo; - } + if (it.spawnflags & WEP_FLAG_RELOADABLE) { + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + this.(weaponentity).weapon_load[it.m_id] = it.reloading_ammo; } - )); - - { - string s = spot.target; - spot.target = string_null; - SUB_UseTargets(spot, this, NULL); - spot.target = s; } + )); - Unfreeze(this); + { + string s = spot.target; + spot.target = string_null; + SUB_UseTargets(spot, this, NULL); + spot.target = s; + } - MUTATOR_CALLHOOK(PlayerSpawn, this, spot); + Unfreeze(this); - if (autocvar_spawn_debug) - { - sprint(this, strcat("spawnpoint origin: ", vtos(spot.origin), "\n")); - delete(spot); // usefull for checking if there are spawnpoints, that let drop through the floor - } + MUTATOR_CALLHOOK(PlayerSpawn, this, spot); - for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) - { - .entity weaponentity = weaponentities[slot]; - if(slot == 0 || autocvar_g_weaponswitch_debug == 1) - this.(weaponentity).m_switchweapon = w_getbestweapon(this, weaponentity); - else - this.(weaponentity).m_switchweapon = WEP_Null; - this.(weaponentity).m_weapon = WEP_Null; - this.(weaponentity).weaponname = ""; - this.(weaponentity).m_switchingweapon = WEP_Null; - this.(weaponentity).cnt = -1; - } + if (autocvar_spawn_debug) + { + sprint(this, strcat("spawnpoint origin: ", vtos(spot.origin), "\n")); + delete(spot); // usefull for checking if there are spawnpoints, that let drop through the floor + } + + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(slot == 0 || autocvar_g_weaponswitch_debug == 1) + this.(weaponentity).m_switchweapon = w_getbestweapon(this, weaponentity); + else + this.(weaponentity).m_switchweapon = WEP_Null; + this.(weaponentity).m_weapon = WEP_Null; + this.(weaponentity).weaponname = ""; + this.(weaponentity).m_switchingweapon = WEP_Null; + this.(weaponentity).cnt = -1; + } + + MUTATOR_CALLHOOK(PlayerWeaponSelect, this); - MUTATOR_CALLHOOK(PlayerWeaponSelect, this); + if (!warmup_stage && !this.alivetime) + this.alivetime = time; - if (!warmup_stage && !this.alivetime) - this.alivetime = time; + antilag_clear(this, CS(this)); +} - antilag_clear(this, CS(this)); +/** Called when a client spawns in the server */ +void PutClientInServer(entity this) +{ + if (IS_BOT_CLIENT(this)) { + TRANSMUTE(Player, this); + } else if (IS_REAL_CLIENT(this)) { + msg_entity = this; + WriteByte(MSG_ONE, SVC_SETVIEW); + WriteEntity(MSG_ONE, this); + } + if (game_stopped) + TRANSMUTE(Observer, this); + + SetSpectatee(this, NULL); + + // reset player keys + if(PS(this)) + PS(this).itemkeys = 0; + + MUTATOR_CALLHOOK(PutClientInServer, this); + + if (IS_OBSERVER(this)) { + PutObserverInServer(this); + } else if (IS_PLAYER(this)) { + PutPlayerInServer(this); } } @@ -773,6 +774,7 @@ void ClientInit_misc(entity this) else WriteString(channel, ""); WriteByte(channel, this.count * 255.0); // g_balance_armor_blockpercent + WriteByte(channel, this.cnt * 255.0); // g_balance_damagepush_speedfactor WriteByte(channel, serverflags); WriteCoord(channel, autocvar_g_trueaim_minrange); } @@ -785,6 +787,11 @@ void ClientInit_CheckUpdate(entity this) this.count = autocvar_g_balance_armor_blockpercent; this.SendFlags |= 1; } + if(this.cnt != autocvar_g_balance_damagepush_speedfactor) + { + this.cnt = autocvar_g_balance_damagepush_speedfactor; + this.SendFlags |= 1; + } } void ClientInit_Spawn() @@ -817,7 +824,7 @@ SetChangeParms void SetChangeParms (entity this) { // save parms for level change - parm1 = this.parm_idlesince - time; + parm1 = CS(this).parm_idlesince - time; MUTATOR_CALLHOOK(SetChangeParms); } @@ -830,12 +837,12 @@ DecodeLevelParms void DecodeLevelParms(entity this) { // load parms - this.parm_idlesince = parm1; - if (this.parm_idlesince == -(86400 * 366)) - this.parm_idlesince = time; + CS(this).parm_idlesince = parm1; + if (CS(this).parm_idlesince == -(86400 * 366)) + CS(this).parm_idlesince = time; // whatever happens, allow 60 seconds of idling directly after connect for map loading - this.parm_idlesince = max(this.parm_idlesince, time - sv_maxidle + 60); + CS(this).parm_idlesince = max(CS(this).parm_idlesince, time - sv_maxidle + 60); MUTATOR_CALLHOOK(DecodeLevelParms); } @@ -851,19 +858,19 @@ Called when a client types 'kill' in the console .float clientkill_nexttime; void ClientKill_Now_TeamChange(entity this) { - if(this.killindicator_teamchange == -1) + if(CS(this).killindicator_teamchange == -1) { JoinBestTeam( this, false, true ); } - else if(this.killindicator_teamchange == -2) + else if(CS(this).killindicator_teamchange == -2) { if(blockSpectators) Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime); PutObserverInServer(this); } else - SV_ChangeTeam(this, this.killindicator_teamchange - 1); - this.killindicator_teamchange = 0; + SV_ChangeTeam(this, CS(this).killindicator_teamchange - 1); + CS(this).killindicator_teamchange = 0; } void ClientKill_Now(entity this) @@ -871,7 +878,7 @@ void ClientKill_Now(entity this) if(this.vehicle) { vehicles_exit(this.vehicle, VHEF_RELEASE); - if(!this.killindicator_teamchange) + if(!CS(this).killindicator_teamchange) { this.vehicle_health = -1; Damage(this, this, this, 1 , DEATH_KILL.m_id, this.origin, '0 0 0'); @@ -883,7 +890,7 @@ void ClientKill_Now(entity this) this.killindicator = NULL; - if(this.killindicator_teamchange) + if(CS(this).killindicator_teamchange) ClientKill_Now_TeamChange(this); if(!IS_SPEC(this) && !IS_OBSERVER(this)) @@ -912,7 +919,7 @@ void KillIndicator_Think(entity this) ClientKill_Now(this.owner); return; } - else if(g_cts && this.health == 1) // health == 1 means that it's silent + else if(this.health == 1) // health == 1 means that it's silent { this.nextthink = time + 1; this.cnt -= 1; @@ -942,13 +949,11 @@ void ClientKill_TeamChange (entity this, float targetteam) // 0 = don't change, killtime = autocvar_g_balance_kill_delay; - if(g_race_qualifying || g_cts) - killtime = 0; - if(MUTATOR_CALLHOOK(ClientKill, this, killtime)) return; + killtime = M_ARGV(1, float); - this.killindicator_teamchange = targetteam; + CS(this).killindicator_teamchange = targetteam; if(!this.killindicator) { @@ -1045,28 +1050,47 @@ void FixClientCvars(entity e) if(autocvar_sv_gentle) stuffcmd(e, "cl_cmd settemp cl_gentle 1\n"); + stuffcmd(e, sprintf("\ncl_jumpspeedcap_min \"%s\"\n", autocvar_sv_jumpspeedcap_min)); + stuffcmd(e, sprintf("\ncl_jumpspeedcap_max \"%s\"\n", autocvar_sv_jumpspeedcap_max)); + MUTATOR_CALLHOOK(FixClientCvars, e); } -float PlayerInIDList(entity p, string idlist) +bool findinlist_abbrev(string tofind, string list) +{ + if(list == "" || tofind == "") + return false; // empty list or search, just return + + // this function allows abbreviated strings! + FOREACH_WORD(list, it == substring(tofind, 0, strlen(it)), + { + return true; + }); + + return false; +} + +bool PlayerInIPList(entity p, string iplist) { - float n, i; - string s; + // some safety checks (never allow local?) + if(p.netaddress == "local" || p.netaddress == "" || !IS_REAL_CLIENT(p)) + return false; + return findinlist_abbrev(p.netaddress, iplist); +} + +bool PlayerInIDList(entity p, string idlist) +{ // NOTE: we do NOT check crypto_idfp_signed here, an unsigned ID is fine too for this - if (!p.crypto_idfp) - return 0; + if(!p.crypto_idfp) + return false; - // this function allows abbreviated player IDs too! - n = tokenize_console(idlist); - for(i = 0; i < n; ++i) - { - s = argv(i); - if(s == substring(p.crypto_idfp, 0, strlen(s))) - return 1; - } + return findinlist_abbrev(p.crypto_idfp, idlist); +} - return 0; +bool PlayerInList(entity player, string list) +{ + return boolean(PlayerInIDList(player, list) || PlayerInIPList(player, list)); } #ifdef DP_EXT_PRECONNECT @@ -1107,8 +1131,8 @@ void ClientConnect(entity this) #ifdef WATERMARK Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_WATERMARK, WATERMARK); #endif - this.version_nagtime = time + 10 + random() * 10; TRANSMUTE(Client, this); + CS(this).version_nagtime = time + 10 + random() * 10; // identify the right forced team if (autocvar_g_campaign) @@ -1125,10 +1149,10 @@ void ClientConnect(entity this) } } } - else if (PlayerInIDList(this, autocvar_g_forced_team_red)) this.team_forced = NUM_TEAM_1; - else if (PlayerInIDList(this, autocvar_g_forced_team_blue)) this.team_forced = NUM_TEAM_2; - else if (PlayerInIDList(this, autocvar_g_forced_team_yellow)) this.team_forced = NUM_TEAM_3; - else if (PlayerInIDList(this, autocvar_g_forced_team_pink)) this.team_forced = NUM_TEAM_4; + else if (PlayerInList(this, autocvar_g_forced_team_red)) this.team_forced = NUM_TEAM_1; + else if (PlayerInList(this, autocvar_g_forced_team_blue)) this.team_forced = NUM_TEAM_2; + else if (PlayerInList(this, autocvar_g_forced_team_yellow)) this.team_forced = NUM_TEAM_3; + else if (PlayerInList(this, autocvar_g_forced_team_pink)) this.team_forced = NUM_TEAM_4; else switch (autocvar_g_forced_team_otherwise) { default: this.team_forced = 0; break; @@ -1171,9 +1195,9 @@ void ClientConnect(entity this) LogTeamchange(this.playerid, this.team, 1); - this.just_joined = true; // stop spamming the eventlog with additional lines when the client connects + CS(this).just_joined = true; // stop spamming the eventlog with additional lines when the client connects - this.netname_previous = strzone(this.netname); + CS(this).netname_previous = strzone(this.netname); if(teamplay && IS_PLAYER(this)) Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_JOIN_CONNECT_TEAM), this.netname); @@ -1206,14 +1230,14 @@ void ClientConnect(entity this) bot_relinkplayerlist(); - this.spectatortime = time; + CS(this).spectatortime = time; if (blockSpectators) { Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime); } - this.jointime = time; - this.allowed_timeouts = autocvar_sv_timeout_number; + CS(this).jointime = time; + CS(this).allowed_timeouts = autocvar_sv_timeout_number; if (IS_REAL_CLIENT(this)) { @@ -1230,15 +1254,13 @@ void ClientConnect(entity this) CSQCMODEL_AUTOINIT(this); - this.model_randomizer = random(); + CS(this).model_randomizer = random(); if (IS_REAL_CLIENT(this)) sv_notice_join(this); // update physics stats (players can spawn before physics runs) - STAT(MOVEVARS_HIGHSPEED, this) = autocvar_g_movement_highspeed; - MUTATOR_CALLHOOK(PlayerPhysics_UpdateStats, this); // do it BEFORE the function so we can modify highspeed! - Physics_UpdateStats(this, PHYS_HIGHSPEED(this)); + Physics_UpdateStats(this); IL_EACH(g_initforplayer, it.init_for_player, { it.init_for_player(it, this); @@ -1250,7 +1272,7 @@ void ClientConnect(entity this) { if (!autocvar_g_campaign && !IS_PLAYER(this)) { - this.motd_actived_time = -1; + CS(this).motd_actived_time = -1; Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_MOTD, getwelcomemessage(this)); } } @@ -1270,7 +1292,7 @@ void ClientDisconnect(entity this) PlayerStats_GameReport_FinalizePlayer(this); if (this.vehicle) vehicles_exit(this.vehicle, VHEF_RELEASE); - if (this.active_minigame) part_minigame(this); + if (CS(this).active_minigame) part_minigame(this); if (IS_PLAYER(this)) Send_Effect(EFFECT_SPAWN_NEUTRAL, this.origin, '0 0 0', 1); if (autocvar_sv_eventlog) @@ -1283,6 +1305,7 @@ void ClientDisconnect(entity this) MUTATOR_CALLHOOK(ClientDisconnect, this); + if (CS(this).netname_previous) strunzone(CS(this).netname_previous); // needs to be before the CS entity is removed! ClientState_detach(this); Portal_ClearAll(this); @@ -1302,7 +1325,6 @@ void ClientDisconnect(entity this) bot_relinkplayerlist(); - if (this.netname_previous) strunzone(this.netname_previous); if (this.clientstatus) strunzone(this.clientstatus); if (this.weaponorder_byimpulse) strunzone(this.weaponorder_byimpulse); if (this.personal) delete(this.personal); @@ -1329,7 +1351,7 @@ void ChatBubbleThink(entity this) if ( !IS_DEAD(this.owner) && IS_PLAYER(this.owner) ) { - if ( this.owner.active_minigame ) + if ( CS(this.owner).active_minigame ) this.mdl = "models/sprites/minigame_busy.iqm"; else if (PHYS_INPUT_BUTTON_CHAT(this.owner)) this.mdl = "models/misc/chatbubble.spr"; @@ -1643,9 +1665,9 @@ void player_regen(entity this) bool zoomstate_set; void SetZoomState(entity this, float newzoom) { - if(newzoom != this.zoomstate) + if(newzoom != CS(this).zoomstate) { - this.zoomstate = newzoom; + CS(this).zoomstate = newzoom; ClientData_Touch(this); } zoomstate_set = true; @@ -1655,16 +1677,16 @@ void GetPressedKeys(entity this) { MUTATOR_CALLHOOK(GetPressedKeys, this); int keys = STAT(PRESSED_KEYS, this); - keys = BITSET(keys, KEY_FORWARD, this.movement.x > 0); - keys = BITSET(keys, KEY_BACKWARD, this.movement.x < 0); - keys = BITSET(keys, KEY_RIGHT, this.movement.y > 0); - keys = BITSET(keys, KEY_LEFT, this.movement.y < 0); + keys = BITSET(keys, KEY_FORWARD, CS(this).movement.x > 0); + keys = BITSET(keys, KEY_BACKWARD, CS(this).movement.x < 0); + keys = BITSET(keys, KEY_RIGHT, CS(this).movement.y > 0); + keys = BITSET(keys, KEY_LEFT, CS(this).movement.y < 0); keys = BITSET(keys, KEY_JUMP, PHYS_INPUT_BUTTON_JUMP(this)); keys = BITSET(keys, KEY_CROUCH, PHYS_INPUT_BUTTON_CROUCH(this)); keys = BITSET(keys, KEY_ATCK, PHYS_INPUT_BUTTON_ATCK(this)); keys = BITSET(keys, KEY_ATCK2, PHYS_INPUT_BUTTON_ATCK2(this)); - this.pressedkeys = keys; // store for other users + CS(this).pressedkeys = keys; // store for other users STAT(PRESSED_KEYS, this) = keys; } @@ -1693,7 +1715,7 @@ void SpectateCopy(entity this, entity spectatee) this.clip_size = spectatee.clip_size; this.effects = spectatee.effects & EFMASK_CHEAP; // eat performance this.health = spectatee.health; - this.impulse = 0; + CS(this).impulse = 0; this.items = spectatee.items; this.last_pickup = spectatee.last_pickup; this.hit_time = spectatee.hit_time; @@ -1702,7 +1724,6 @@ void SpectateCopy(entity this, entity spectatee) this.superweapons_finished = spectatee.superweapons_finished; STAT(PRESSED_KEYS, this) = STAT(PRESSED_KEYS, spectatee); this.weapons = spectatee.weapons; - this.dual_weapons = spectatee.dual_weapons; this.vortex_charge = spectatee.vortex_charge; this.vortex_chargepool_ammo = spectatee.vortex_chargepool_ammo; this.okvortex_charge = spectatee.okvortex_charge; @@ -1725,7 +1746,7 @@ void SpectateCopy(entity this, entity spectatee) this.fixangle = true; setorigin(this, spectatee.origin); setsize(this, spectatee.mins, spectatee.maxs); - SetZoomState(this, spectatee.zoomstate); + SetZoomState(this, CS(spectatee).zoomstate); for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { @@ -1805,10 +1826,10 @@ bool SpectateSet(entity this) void SetSpectatee_status(entity this, int spectatee_num) { - int oldspectatee_status = this.spectatee_status; - this.spectatee_status = spectatee_num; + int oldspectatee_status = CS(this).spectatee_status; + CS(this).spectatee_status = spectatee_num; - if (this.spectatee_status != oldspectatee_status) + if (CS(this).spectatee_status != oldspectatee_status) { ClientData_Touch(this); if (g_race || g_cts) race_InitSpectator(); @@ -1940,7 +1961,7 @@ void ShowRespawnCountdown(entity this) .bool team_selected; bool ShowTeamSelection(entity this) { - if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || this.team_selected || (this.wasplayer && autocvar_g_changeteam_banned) || this.team_forced > 0) + if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || this.team_selected || (CS(this).wasplayer && autocvar_g_changeteam_banned) || this.team_forced > 0) return false; stuffcmd(this, "menu_showteamselect\n"); return true; @@ -2026,7 +2047,7 @@ void checkSpectatorBlock(entity this) if(!this.caplayer) if(IS_REAL_CLIENT(this)) { - if( time > (this.spectatortime + autocvar_g_maxplayers_spectator_blocktime) ) { + if( time > (CS(this).spectatortime + autocvar_g_maxplayers_spectator_blocktime) ) { Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_QUIT_KICK_SPECTATING); dropclient(this); } @@ -2035,46 +2056,46 @@ void checkSpectatorBlock(entity this) void PrintWelcomeMessage(entity this) { - if(this.motd_actived_time == 0) + if(CS(this).motd_actived_time == 0) { if (autocvar_g_campaign) { if ((IS_PLAYER(this) && PHYS_INPUT_BUTTON_INFO(this)) || (!IS_PLAYER(this))) { - this.motd_actived_time = time; + CS(this).motd_actived_time = time; Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_MOTD, campaign_message); } } else { if (PHYS_INPUT_BUTTON_INFO(this)) { - this.motd_actived_time = time; + CS(this).motd_actived_time = time; Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_MOTD, getwelcomemessage(this)); } } } - else if(this.motd_actived_time > 0) // showing MOTD or campaign message + else if(CS(this).motd_actived_time > 0) // showing MOTD or campaign message { if (autocvar_g_campaign) { if (PHYS_INPUT_BUTTON_INFO(this)) - this.motd_actived_time = time; - else if ((time - this.motd_actived_time > 2) && IS_PLAYER(this)) { // hide it some seconds after BUTTON_INFO has been released - this.motd_actived_time = 0; + CS(this).motd_actived_time = time; + else if ((time - CS(this).motd_actived_time > 2) && IS_PLAYER(this)) { // hide it some seconds after BUTTON_INFO has been released + CS(this).motd_actived_time = 0; Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_MOTD); } } else { if (PHYS_INPUT_BUTTON_INFO(this)) - this.motd_actived_time = time; - else if (time - this.motd_actived_time > 2) { // hide it some seconds after BUTTON_INFO has been released - this.motd_actived_time = 0; + CS(this).motd_actived_time = time; + else if (time - CS(this).motd_actived_time > 2) { // hide it some seconds after BUTTON_INFO has been released + CS(this).motd_actived_time = 0; Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_MOTD); } } } - else //if(this.motd_actived_time < 0) // just connected, motd is active + else //if(CS(this).motd_actived_time < 0) // just connected, motd is active { if(PHYS_INPUT_BUTTON_INFO(this)) // BUTTON_INFO hides initial MOTD - this.motd_actived_time = -2; // wait until BUTTON_INFO gets released - else if(this.motd_actived_time == -2 || IS_PLAYER(this) || IS_SPEC(this)) + CS(this).motd_actived_time = -2; // wait until BUTTON_INFO gets released + else if(CS(this).motd_actived_time == -2 || IS_PLAYER(this) || IS_SPEC(this)) { // instanctly hide MOTD - this.motd_actived_time = 0; + CS(this).motd_actived_time = 0; Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_MOTD); } } @@ -2082,7 +2103,7 @@ void PrintWelcomeMessage(entity this) bool joinAllowed(entity this) { - if (this.version_mismatch) return false; + if (CS(this).version_mismatch) return false; if (!nJoinAllowed(this, this)) return false; if (teamplay && lockteams) return false; if (ShowTeamSelection(this)) return false; @@ -2090,19 +2111,202 @@ bool joinAllowed(entity this) return true; } +.int items_added; +bool PlayerThink(entity this) +{ + if (game_stopped || intermission_running) { + this.modelflags &= ~MF_ROCKET; + if(intermission_running) + IntermissionThink(this); + return false; + } + + if (timeout_status == TIMEOUT_ACTIVE) { + // don't allow the player to turn around while game is paused + // FIXME turn this into CSQC stuff + this.v_angle = this.lastV_angle; + this.angles = this.lastV_angle; + this.fixangle = true; + } + + if (frametime) player_powerups(this); + + if (IS_DEAD(this)) { + if (this.personal && g_race_qualifying) { + if (time > this.respawn_time) { + STAT(RESPAWN_TIME, this) = this.respawn_time = time + 1; // only retry once a second + respawn(this); + CS(this).impulse = CHIMPULSE_SPEEDRUN.impulse; + } + } else { + if (frametime) player_anim(this); + + if (this.respawn_flags & RESPAWN_DENY) + { + STAT(RESPAWN_TIME, this) = 0; + return false; + } + + bool button_pressed = (PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_JUMP(this) || PHYS_INPUT_BUTTON_ATCK2(this) || PHYS_INPUT_BUTTON_HOOK(this) || PHYS_INPUT_BUTTON_USE(this)); + + switch(this.deadflag) + { + case DEAD_DYING: + { + if ((this.respawn_flags & RESPAWN_FORCE) && !(this.respawn_time < this.respawn_time_max)) + this.deadflag = DEAD_RESPAWNING; + else if (!button_pressed || (time >= this.respawn_time_max && (this.respawn_flags & RESPAWN_FORCE))) + this.deadflag = DEAD_DEAD; + break; + } + case DEAD_DEAD: + { + if (button_pressed) + this.deadflag = DEAD_RESPAWNABLE; + else if (time >= this.respawn_time_max && (this.respawn_flags & RESPAWN_FORCE)) + this.deadflag = DEAD_RESPAWNING; + break; + } + case DEAD_RESPAWNABLE: + { + if (!button_pressed || (this.respawn_flags & RESPAWN_FORCE)) + this.deadflag = DEAD_RESPAWNING; + break; + } + case DEAD_RESPAWNING: + { + if (time > this.respawn_time) + { + this.respawn_time = time + 1; // only retry once a second + this.respawn_time_max = this.respawn_time; + respawn(this); + } + break; + } + } + + ShowRespawnCountdown(this); + + if (this.respawn_flags & RESPAWN_SILENT) + STAT(RESPAWN_TIME, this) = 0; + else if ((this.respawn_flags & RESPAWN_FORCE) && this.respawn_time < this.respawn_time_max) + { + if (time < this.respawn_time) + STAT(RESPAWN_TIME, this) = this.respawn_time; + else if (this.deadflag != DEAD_RESPAWNING) + STAT(RESPAWN_TIME, this) = -this.respawn_time_max; + } + else + STAT(RESPAWN_TIME, this) = this.respawn_time; + } + + // if respawning, invert stat_respawn_time to indicate this, the client translates it + if (this.deadflag == DEAD_RESPAWNING && STAT(RESPAWN_TIME, this) > 0) + STAT(RESPAWN_TIME, this) *= -1; + + return false; + } + + bool have_hook = false; + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if(this.(weaponentity).hook.state) + { + have_hook = true; + break; + } + } + bool do_crouch = PHYS_INPUT_BUTTON_CROUCH(this); + if (have_hook) { + do_crouch = false; + } else if (this.waterlevel >= WATERLEVEL_SWIMMING) { + do_crouch = false; + } else if (this.vehicle) { + do_crouch = false; + } else if (STAT(FROZEN, this)) { + do_crouch = false; + } + + if (do_crouch) { + if (!this.crouch) { + this.crouch = true; + this.view_ofs = STAT(PL_CROUCH_VIEW_OFS, this); + setsize(this, STAT(PL_CROUCH_MIN, this), STAT(PL_CROUCH_MAX, this)); + // setanim(this, this.anim_duck, false, true, true); // this anim is BROKEN anyway + } + } else if (this.crouch) { + tracebox(this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this), this.origin, false, this); + if (!trace_startsolid) { + this.crouch = false; + this.view_ofs = STAT(PL_VIEW_OFS, this); + setsize(this, STAT(PL_MIN, this), STAT(PL_MAX, this)); + } + } + + FixPlayermodel(this); + + // LordHavoc: allow firing on move frames (sub-ticrate), this gives better timing on slow servers + //if(frametime) + { + this.items &= ~this.items_added; + + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + W_WeaponFrame(this, weaponentity); + + if(slot == 0) + { + this.clip_load = this.(weaponentity).clip_load; + this.clip_size = this.(weaponentity).clip_size; + } + } + + this.items_added = 0; + if ((this.items & ITEM_Jetpack.m_itemid) && ((this.items & ITEM_JetpackRegen.m_itemid) || this.ammo_fuel >= 0.01)) + this.items_added |= IT_FUEL; + + this.items |= this.items_added; + } + + player_regen(this); + + // WEAPONTODO: Add a weapon request for this + // rot vortex charge to the charge limit + for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + { + .entity weaponentity = weaponentities[slot]; + if (WEP_CVAR(vortex, charge_rot_rate) && this.(weaponentity).vortex_charge > WEP_CVAR(vortex, charge_limit) && this.(weaponentity).vortex_charge_rottime < time) + this.(weaponentity).vortex_charge = bound(WEP_CVAR(vortex, charge_limit), this.(weaponentity).vortex_charge - WEP_CVAR(vortex, charge_rot_rate) * frametime / W_TICSPERFRAME, 1); + } + + if (frametime) player_anim(this); + + // secret status + secrets_setstatus(this); + + // monsters status + monsters_setstatus(this); + + this.dmg_team = max(0, this.dmg_team - autocvar_g_teamdamage_resetspeed * frametime); + + return true; +} + void ObserverThink(entity this) { - if ( this.impulse ) + if ( CS(this).impulse ) { - MinigameImpulse(this, this.impulse); - this.impulse = 0; + MinigameImpulse(this, CS(this).impulse); + CS(this).impulse = 0; } if (this.flags & FL_JUMPRELEASED) { if (PHYS_INPUT_BUTTON_JUMP(this) && joinAllowed(this)) { this.flags &= ~FL_JUMPRELEASED; this.flags |= FL_SPAWNING; - } else if(PHYS_INPUT_BUTTON_ATCK(this) && !this.version_mismatch) { + } else if(PHYS_INPUT_BUTTON_ATCK(this) && !CS(this).version_mismatch) { this.flags &= ~FL_JUMPRELEASED; if(SpectateNext(this)) { TRANSMUTE(Spectator, this); @@ -2126,15 +2330,15 @@ void ObserverThink(entity this) void SpectatorThink(entity this) { - if ( this.impulse ) + if ( CS(this).impulse ) { - if(MinigameImpulse(this, this.impulse)) - this.impulse = 0; + if(MinigameImpulse(this, CS(this).impulse)) + CS(this).impulse = 0; - if (this.impulse == IMP_weapon_drop.impulse) + if (CS(this).impulse == IMP_weapon_drop.impulse) { STAT(CAMERA_SPECTATOR, this) = (STAT(CAMERA_SPECTATOR, this) + 1) % 3; - this.impulse = 0; + CS(this).impulse = 0; return; } } @@ -2143,7 +2347,7 @@ void SpectatorThink(entity this) if (PHYS_INPUT_BUTTON_JUMP(this) && joinAllowed(this)) { this.flags &= ~FL_JUMPRELEASED; this.flags |= FL_SPAWNING; - } else if(PHYS_INPUT_BUTTON_ATCK(this) || this.impulse == 10 || this.impulse == 15 || this.impulse == 18 || (this.impulse >= 200 && this.impulse <= 209)) { + } else if(PHYS_INPUT_BUTTON_ATCK(this) || CS(this).impulse == 10 || CS(this).impulse == 15 || CS(this).impulse == 18 || (CS(this).impulse >= 200 && CS(this).impulse <= 209)) { this.flags &= ~FL_JUMPRELEASED; if(SpectateNext(this)) { TRANSMUTE(Spectator, this); @@ -2151,8 +2355,8 @@ void SpectatorThink(entity this) TRANSMUTE(Observer, this); PutClientInServer(this); } - this.impulse = 0; - } else if(this.impulse == 12 || this.impulse == 16 || this.impulse == 19 || (this.impulse >= 220 && this.impulse <= 229)) { + CS(this).impulse = 0; + } else if(CS(this).impulse == 12 || CS(this).impulse == 16 || CS(this).impulse == 19 || (CS(this).impulse >= 220 && CS(this).impulse <= 229)) { this.flags &= ~FL_JUMPRELEASED; if(SpectatePrev(this)) { TRANSMUTE(Spectator, this); @@ -2160,7 +2364,7 @@ void SpectatorThink(entity this) TRANSMUTE(Observer, this); PutClientInServer(this); } - this.impulse = 0; + CS(this).impulse = 0; } else if (PHYS_INPUT_BUTTON_ATCK2(this)) { this.flags &= ~FL_JUMPRELEASED; TRANSMUTE(Observer, this); @@ -2243,20 +2447,11 @@ PlayerPreThink Called every frame for each client before the physics are run ============= */ -.float usekeypressed; .float last_vehiclecheck; -.int items_added; void PlayerPreThink (entity this) { WarpZone_PlayerPhysics_FixVAngle(this); - STAT(GAMESTARTTIME, this) = game_starttime; - STAT(ROUNDSTARTTIME, this) = round_starttime; - STAT(ALLOW_OLDVORTEXBEAM, this) = autocvar_g_allow_oldvortexbeam; - STAT(LEADLIMIT, this) = autocvar_leadlimit; - - STAT(WEAPONSINMAP, this) = weaponsInMap; - if (frametime) { // physics frames: update anticheat stuff anticheat_prethink(this); @@ -2275,17 +2470,17 @@ void PlayerPreThink (entity this) this.netname = strzone(sprintf("Player#%d", this.playerid)); // stuffcmd(this, strcat("name ", this.netname, "\n")); // maybe? } - if (this.netname != this.netname_previous) { + if (this.netname != CS(this).netname_previous) { if (autocvar_sv_eventlog) { GameLogEcho(strcat(":name:", ftos(this.playerid), ":", playername(this, false))); } - if (this.netname_previous) strunzone(this.netname_previous); - this.netname_previous = strzone(this.netname); + if (CS(this).netname_previous) strunzone(CS(this).netname_previous); + CS(this).netname_previous = strzone(this.netname); } // version nagging - if (this.version_nagtime && this.cvar_g_xonoticversion && time > this.version_nagtime) { - this.version_nagtime = 0; + if (CS(this).version_nagtime && this.cvar_g_xonoticversion && time > CS(this).version_nagtime) { + CS(this).version_nagtime = 0; if (strstrofs(this.cvar_g_xonoticversion, "git", 0) >= 0 || strstrofs(this.cvar_g_xonoticversion, "autobuild", 0) >= 0) { // git client } else if (strstrofs(autocvar_g_xonoticversion, "git", 0) >= 0 || strstrofs(autocvar_g_xonoticversion, "autobuild", 0) >= 0) { @@ -2308,29 +2503,32 @@ void PlayerPreThink (entity this) this.max_armorvalue = 0; } - if (STAT(FROZEN, this) == 2) - { - this.revive_progress = bound(0, this.revive_progress + frametime * this.revive_speed, 1); - this.health = max(1, this.revive_progress * start_health); - this.iceblock.alpha = bound(0.2, 1 - this.revive_progress, 1); - - if (this.revive_progress >= 1) - Unfreeze(this); - } - else if (STAT(FROZEN, this) == 3) + if(IS_PLAYER(this)) { - this.revive_progress = bound(0, this.revive_progress - frametime * this.revive_speed, 1); - this.health = max(0, autocvar_g_nades_ice_health + (start_health-autocvar_g_nades_ice_health) * this.revive_progress ); + if (STAT(FROZEN, this) == 2) + { + this.revive_progress = bound(0, this.revive_progress + frametime * this.revive_speed, 1); + this.health = max(1, this.revive_progress * start_health); + this.iceblock.alpha = bound(0.2, 1 - this.revive_progress, 1); - if (this.health < 1) + if (this.revive_progress >= 1) + Unfreeze(this); + } + else if (STAT(FROZEN, this) == 3) { - if (this.vehicle) - vehicles_exit(this.vehicle, VHEF_RELEASE); - if(this.event_damage) - this.event_damage(this, this, this.frozen_by, 1, DEATH_NADE_ICE_FREEZE.m_id, this.origin, '0 0 0'); + this.revive_progress = bound(0, this.revive_progress - frametime * this.revive_speed, 1); + this.health = max(0, autocvar_g_nades_ice_health + (start_health-autocvar_g_nades_ice_health) * this.revive_progress ); + + if (this.health < 1) + { + if (this.vehicle) + vehicles_exit(this.vehicle, VHEF_RELEASE); + if(this.event_damage) + this.event_damage(this, this, this.frozen_by, 1, DEATH_NADE_ICE_FREEZE.m_id, this.origin, '0 0 0'); + } + else if (this.revive_progress <= 0) + Unfreeze(this); } - else if (this.revive_progress <= 0) - Unfreeze(this); } MUTATOR_CALLHOOK(PlayerPreThink, this); @@ -2359,201 +2557,17 @@ void PlayerPreThink (entity this) if(!this.cvar_cl_newusekeysupported) // FIXME remove this - it was a stupid idea to begin with, we can JUST use the button { - if(PHYS_INPUT_BUTTON_USE(this) && !this.usekeypressed) + if(PHYS_INPUT_BUTTON_USE(this) && !CS(this).usekeypressed) PlayerUseKey(this); - this.usekeypressed = PHYS_INPUT_BUTTON_USE(this); + CS(this).usekeypressed = PHYS_INPUT_BUTTON_USE(this); } if (IS_REAL_CLIENT(this)) PrintWelcomeMessage(this); if (IS_PLAYER(this)) { - CheckRules_Player(this); - - if (game_stopped || intermission_running) { - this.modelflags &= ~MF_ROCKET; - if(intermission_running) - IntermissionThink(this); + if(!PlayerThink(this)) return; - } - - if (timeout_status == TIMEOUT_ACTIVE) { - // don't allow the player to turn around while game is paused - // FIXME turn this into CSQC stuff - this.v_angle = this.lastV_angle; - this.angles = this.lastV_angle; - this.fixangle = true; - } - - if (frametime) player_powerups(this); - - if (IS_DEAD(this)) { - if (this.personal && g_race_qualifying) { - if (time > this.respawn_time) { - STAT(RESPAWN_TIME, this) = this.respawn_time = time + 1; // only retry once a second - respawn(this); - this.impulse = CHIMPULSE_SPEEDRUN.impulse; - } - } else { - if (frametime) player_anim(this); - - if (this.respawn_flags & RESPAWN_DENY) - { - STAT(RESPAWN_TIME, this) = 0; - return; - } - - bool button_pressed = (PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_JUMP(this) || PHYS_INPUT_BUTTON_ATCK2(this) || PHYS_INPUT_BUTTON_HOOK(this) || PHYS_INPUT_BUTTON_USE(this)); - - switch(this.deadflag) - { - case DEAD_DYING: - { - if ((this.respawn_flags & RESPAWN_FORCE) && !(this.respawn_time < this.respawn_time_max)) - this.deadflag = DEAD_RESPAWNING; - else if (!button_pressed || (time >= this.respawn_time_max && (this.respawn_flags & RESPAWN_FORCE))) - this.deadflag = DEAD_DEAD; - break; - } - case DEAD_DEAD: - { - if (button_pressed) - this.deadflag = DEAD_RESPAWNABLE; - else if (time >= this.respawn_time_max && (this.respawn_flags & RESPAWN_FORCE)) - this.deadflag = DEAD_RESPAWNING; - break; - } - case DEAD_RESPAWNABLE: - { - if (!button_pressed || (this.respawn_flags & RESPAWN_FORCE)) - this.deadflag = DEAD_RESPAWNING; - break; - } - case DEAD_RESPAWNING: - { - if (time > this.respawn_time) - { - this.respawn_time = time + 1; // only retry once a second - this.respawn_time_max = this.respawn_time; - respawn(this); - } - break; - } - } - - ShowRespawnCountdown(this); - - if (this.respawn_flags & RESPAWN_SILENT) - STAT(RESPAWN_TIME, this) = 0; - else if ((this.respawn_flags & RESPAWN_FORCE) && this.respawn_time < this.respawn_time_max) - { - if (time < this.respawn_time) - STAT(RESPAWN_TIME, this) = this.respawn_time; - else if (this.deadflag != DEAD_RESPAWNING) - STAT(RESPAWN_TIME, this) = -this.respawn_time_max; - } - else - STAT(RESPAWN_TIME, this) = this.respawn_time; - } - - // if respawning, invert stat_respawn_time to indicate this, the client translates it - if (this.deadflag == DEAD_RESPAWNING && STAT(RESPAWN_TIME, this) > 0) - STAT(RESPAWN_TIME, this) *= -1; - - return; - } - - this.prevorigin = this.origin; - - bool have_hook = false; - for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) - { - .entity weaponentity = weaponentities[slot]; - if(this.(weaponentity).hook.state) - { - have_hook = true; - break; - } - } - bool do_crouch = PHYS_INPUT_BUTTON_CROUCH(this); - if (have_hook) { - do_crouch = false; - } else if (this.waterlevel >= WATERLEVEL_SWIMMING) { - do_crouch = false; - } else if (this.vehicle) { - do_crouch = false; - } else if (STAT(FROZEN, this)) { - do_crouch = false; - } - - if (do_crouch) { - if (!this.crouch) { - this.crouch = true; - this.view_ofs = STAT(PL_CROUCH_VIEW_OFS, this); - setsize(this, STAT(PL_CROUCH_MIN, this), STAT(PL_CROUCH_MAX, this)); - // setanim(this, this.anim_duck, false, true, true); // this anim is BROKEN anyway - } - } else if (this.crouch) { - tracebox(this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this), this.origin, false, this); - if (!trace_startsolid) { - this.crouch = false; - this.view_ofs = STAT(PL_VIEW_OFS, this); - setsize(this, STAT(PL_MIN, this), STAT(PL_MAX, this)); - } - } - - FixPlayermodel(this); - - // LordHavoc: allow firing on move frames (sub-ticrate), this gives better timing on slow servers - //if(frametime) - { - this.items &= ~this.items_added; - - for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) - { - .entity weaponentity = weaponentities[slot]; - W_WeaponFrame(this, weaponentity); - - if(slot == 0) - { - this.clip_load = this.(weaponentity).clip_load; - this.clip_size = this.(weaponentity).clip_size; - } - } - - this.items_added = 0; - if (this.items & ITEM_Jetpack.m_itemid && (this.items & ITEM_JetpackRegen.m_itemid || this.ammo_fuel >= 0.01)) - this.items_added |= IT_FUEL; - - this.items |= this.items_added; - } - - player_regen(this); - - // WEAPONTODO: Add a weapon request for this - // rot vortex charge to the charge limit - for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) - { - .entity weaponentity = weaponentities[slot]; - if (WEP_CVAR(vortex, charge_rot_rate) && this.(weaponentity).vortex_charge > WEP_CVAR(vortex, charge_limit) && this.(weaponentity).vortex_charge_rottime < time) - { - this.(weaponentity).vortex_charge = bound(WEP_CVAR(vortex, charge_limit), this.(weaponentity).vortex_charge - WEP_CVAR(vortex, charge_rot_rate) * frametime / W_TICSPERFRAME, 1); - } - if (WEP_CVAR(okvortex, charge_rot_rate) && this.(weaponentity).okvortex_charge > WEP_CVAR(okvortex, charge_limit) && this.(weaponentity).okvortex_charge_rottime < time) - { - this.(weaponentity).okvortex_charge = bound(WEP_CVAR(okvortex, charge_limit), this.(weaponentity).okvortex_charge - WEP_CVAR(okvortex, charge_rot_rate) * frametime / W_TICSPERFRAME, 1); - } - } - - if (frametime) player_anim(this); - - // secret status - secrets_setstatus(this); - - // monsters status - monsters_setstatus(this); - - this.dmg_team = max(0, this.dmg_team - autocvar_g_teamdamage_resetspeed * frametime); } else if (game_stopped || intermission_running) { if(intermission_running) @@ -2580,19 +2594,19 @@ void PlayerPreThink (entity this) SetZoomState(this, PHYS_INPUT_BUTTON_ZOOM(this) || PHYS_INPUT_BUTTON_ZOOMSCRIPT(this) || wep_zoomed); } - if (this.teamkill_soundtime && time > this.teamkill_soundtime) + if (CS(this).teamkill_soundtime && time > CS(this).teamkill_soundtime) { - this.teamkill_soundtime = 0; + CS(this).teamkill_soundtime = 0; - entity e = this.teamkill_soundsource; + entity e = CS(this).teamkill_soundsource; entity oldpusher = e.pusher; e.pusher = this; PlayerSound(e, playersound_teamshoot, CH_VOICE, VOL_BASEVOICE, VOICETYPE_LASTATTACKER_ONLY); e.pusher = oldpusher; } - if (this.taunt_soundtime && time > this.taunt_soundtime) { - this.taunt_soundtime = 0; + if (CS(this).taunt_soundtime && time > CS(this).taunt_soundtime) { + CS(this).taunt_soundtime = 0; PlayerSound(this, playersound_taunt, CH_VOICE, VOL_BASEVOICE, VOICETYPE_AUTOTAUNT); } @@ -2639,12 +2653,12 @@ void Player_Physics(entity this) if(!this.move_qcphysics) return; - if(!frametime && !this.pm_frametime) + if(!frametime && !CS(this).pm_frametime) return; - Movetype_Physics_NoMatchTicrate(this, this.pm_frametime, true); + Movetype_Physics_NoMatchTicrate(this, CS(this).pm_frametime, true); - this.pm_frametime = 0; + CS(this).pm_frametime = 0; } /* @@ -2654,7 +2668,6 @@ PlayerPostThink Called every frame for each client after the physics are run ============= */ -.float idlekick_lasttimeleft; void PlayerPostThink (entity this) { Player_Physics(this); @@ -2675,19 +2688,19 @@ void PlayerPostThink (entity this) if (sv_maxidle_slots > 0 && (maxclients - totalClients) > sv_maxidle_slots) { /* do nothing */ } - else if (time - this.parm_idlesince < 1) // instead of (time == this.parm_idlesince) to support sv_maxidle <= 10 + else if (time - CS(this).parm_idlesince < 1) // instead of (time == this.parm_idlesince) to support sv_maxidle <= 10 { - if (this.idlekick_lasttimeleft) + if (CS(this).idlekick_lasttimeleft) { - this.idlekick_lasttimeleft = 0; + CS(this).idlekick_lasttimeleft = 0; Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_IDLING); } } else { - float timeleft = ceil(sv_maxidle - (time - this.parm_idlesince)); + float timeleft = ceil(sv_maxidle - (time - CS(this).parm_idlesince)); if (timeleft == min(10, sv_maxidle - 1)) { // - 1 to support sv_maxidle <= 10 - if (!this.idlekick_lasttimeleft) + if (!CS(this).idlekick_lasttimeleft) Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_DISCONNECT_IDLING, timeleft); } if (timeleft <= 0) { @@ -2696,17 +2709,16 @@ void PlayerPostThink (entity this) return; } else if (timeleft <= 10) { - if (timeleft != this.idlekick_lasttimeleft) { + if (timeleft != CS(this).idlekick_lasttimeleft) { Send_Notification(NOTIF_ONE, this, MSG_ANNCE, Announcer_PickNumber(CNT_IDLE, timeleft)); } - this.idlekick_lasttimeleft = timeleft; + CS(this).idlekick_lasttimeleft = timeleft; } } } CheatFrame(this); - //CheckPlayerJump(); if (game_stopped) { this.solid = SOLID_NOT; @@ -2716,9 +2728,8 @@ void PlayerPostThink (entity this) if (IS_PLAYER(this)) { DrownPlayer(this); - CheckRules_Player(this); UpdateChatBubble(this); - if (this.impulse) ImpulseCommands(this); + if (CS(this).impulse) ImpulseCommands(this); if (game_stopped) { CSQCMODEL_AUTOUPDATE(this); @@ -2736,3 +2747,43 @@ void PlayerPostThink (entity this) CSQCMODEL_AUTOUPDATE(this); } + +// hack to copy the button fields from the client entity to the Client State +void PM_UpdateButtons(entity this, entity store) +{ + if(this.impulse) + store.impulse = this.impulse; + this.impulse = 0; + + store.button0 = this.button0; + store.button2 = this.button2; + store.button3 = this.button3; + store.button4 = this.button4; + store.button5 = this.button5; + store.button6 = this.button6; + store.button7 = this.button7; + store.button8 = this.button8; + store.button9 = this.button9; + store.button10 = this.button10; + store.button11 = this.button11; + store.button12 = this.button12; + store.button13 = this.button13; + store.button14 = this.button14; + store.button15 = this.button15; + store.button16 = this.button16; + store.buttonuse = this.buttonuse; + store.buttonchat = this.buttonchat; + + store.cursor_active = this.cursor_active; + store.cursor_screen = this.cursor_screen; + store.cursor_trace_start = this.cursor_trace_start; + store.cursor_trace_endpos = this.cursor_trace_endpos; + store.cursor_trace_ent = this.cursor_trace_ent; + + store.ping = this.ping; + store.ping_packetloss = this.ping_packetloss; + store.ping_movementloss = this.ping_movementloss; + + store.v_angle = this.v_angle; + store.movement = this.movement; +}