X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fclient.qc;h=58bf67762fe2f852de1b335aaab134dff74170b7;hb=976e2ab8d154e70da6178e7b0f9d73bd720ddcd1;hp=8c76503bf4802906a18d0b426a8fd041ce25b4ac;hpb=0e281586812367f4a1fd13d6ce32638f9b3059de;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/client.qc b/qcsrc/server/client.qc index 8c76503bf..58bf67762 100644 --- a/qcsrc/server/client.qc +++ b/qcsrc/server/client.qc @@ -338,6 +338,7 @@ void PutObserverInServer(entity this) this.items = 0; this.weapons = '0 0 0'; + this.dual_weapons = '0 0 0'; this.drawonlytoclient = this; this.weaponmodel = ""; @@ -354,6 +355,15 @@ void PutObserverInServer(entity this) this.oldvelocity = this.velocity; this.fire_endtime = -1; this.event_damage = func_null; + + for(int slot = 0; slot < MAX_AXH; ++slot) + { + entity axh = this.(AuxiliaryXhair[slot]); + this.(AuxiliaryXhair[slot]) = NULL; + + if(axh.owner == this && axh != NULL && !wasfreed(axh)) + delete(axh); + } } int player_getspecies(entity this) @@ -374,11 +384,12 @@ void FixPlayermodel(entity player) { if(teamplay) { - string s = Static_Team_ColorName_Lower(player.team); - if (s != "neutral") + switch(player.team) { - defaultmodel = cvar_string(strcat("sv_defaultplayermodel_", s)); - defaultskin = cvar(strcat("sv_defaultplayerskin_", s)); + case NUM_TEAM_1: defaultmodel = autocvar_sv_defaultplayermodel_red; defaultskin = autocvar_sv_defaultplayerskin_red; break; + case NUM_TEAM_2: defaultmodel = autocvar_sv_defaultplayermodel_blue; defaultskin = autocvar_sv_defaultplayerskin_blue; break; + case NUM_TEAM_3: defaultmodel = autocvar_sv_defaultplayermodel_yellow; defaultskin = autocvar_sv_defaultplayerskin_yellow; break; + case NUM_TEAM_4: defaultmodel = autocvar_sv_defaultplayermodel_pink; defaultskin = autocvar_sv_defaultplayerskin_pink; break; } } @@ -409,9 +420,13 @@ void FixPlayermodel(entity player) { if(teamplay) { - string s = Static_Team_ColorName_Lower(player.team); - if (s != "neutral") - defaultskin = cvar(strcat("sv_defaultplayerskin_", s)); + switch(player.team) + { + case NUM_TEAM_1: defaultskin = autocvar_sv_defaultplayerskin_red; break; + case NUM_TEAM_2: defaultskin = autocvar_sv_defaultplayerskin_blue; break; + case NUM_TEAM_3: defaultskin = autocvar_sv_defaultplayerskin_yellow; break; + case NUM_TEAM_4: defaultskin = autocvar_sv_defaultplayerskin_pink; break; + } } if(!defaultskin) @@ -473,245 +488,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 (game_stopped) - TRANSMUTE(Observer, this); + if (this.vehicle) vehicles_exit(this.vehicle, VHEF_RELEASE); - SetSpectatee(this, NULL); + PlayerState_attach(this); + accuracy_resend(this); - // reset player keys - this.itemkeys = 0; + if (this.team < 0) + JoinBestTeam(this, false, true); - MUTATOR_CALLHOOK(PutClientInServer, this); + entity spot = SelectSpawnPoint(this, false); + if (!spot) { + Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_JOIN_NOSPAWNS); + return; // spawn failed + } - if (IS_OBSERVER(this)) { - PutObserverInServer(this); - } else if (IS_PLAYER(this)) { - if (this.vehicle) vehicles_exit(this.vehicle, VHEF_RELEASE); + TRANSMUTE(Player, this); - PlayerState_attach(this); - accuracy_resend(this); + 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; - if (this.team < 0) - JoinBestTeam(this, false, true); + this.deadflag = DEAD_NO; - entity spot = SelectSpawnPoint(this, false); - if (!spot) { - Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_JOIN_NOSPAWNS); - return; // spawn failed - } + 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'; - TRANSMUTE(Player, 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; - 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.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; + entity spawnevent = new_pure(spawnevent); + spawnevent.owner = this; + Net_LinkEntity(spawnevent, false, 0.5, SpawnEvent_Send); - this.viewloc = NULL; + // Cut off any still running player sounds. + stopsound(this, CH_PLAYER_SINGLE); - 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.model = ""; + FixPlayermodel(this); + this.drawonlytoclient = NULL; - this.event_damage = PlayerDamage; + this.viewloc = NULL; - if(!this.bot_attack) - IL_PUSH(g_bot_targets, this); - this.bot_attack = true; - this.monster_attack = true; + 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; + 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 (this.killcount == FRAGS_SPECTATOR) { + PlayerScore_Clear(this); + this.killcount = 0; + } - PHYS_INPUT_BUTTON_ATCK(this) = PHYS_INPUT_BUTTON_JUMP(this) = PHYS_INPUT_BUTTON_ATCK2(this) = false; + 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; - if (this.killcount == FRAGS_SPECTATOR) { - PlayerScore_Clear(this); - this.killcount = 0; - } + this.speedrunning = false; - for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) - { - .entity weaponentity = weaponentities[slot]; - CL_SpawnWeaponentity(this, weaponentity); + target_voicescript_clear(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; + } } - this.alpha = default_player_alpha; - this.colormod = '1 1 1' * autocvar_g_player_brightness; - this.exteriorweaponentity.alpha = default_weapon_alpha; + )); + + { + string s = spot.target; + spot.target = string_null; + SUB_UseTargets(spot, this, NULL); + spot.target = s; + } - this.speedrunning = false; + Unfreeze(this); - target_voicescript_clear(this); + MUTATOR_CALLHOOK(PlayerSpawn, this, spot); - // 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 (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 + } - { - string s = spot.target; - spot.target = string_null; - SUB_UseTargets(spot, this, NULL); - spot.target = s; - } + 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; + } - Unfreeze(this); + MUTATOR_CALLHOOK(PlayerWeaponSelect, this); - MUTATOR_CALLHOOK(PlayerSpawn, this, spot); + if (!warmup_stage && !this.alivetime) + this.alivetime = time; - 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 - } + antilag_clear(this, CS(this)); +} - for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) - { - .entity weaponentity = weaponentities[slot]; - if(slot == 0) - 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; - } +/** 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); - MUTATOR_CALLHOOK(PlayerWeaponSelect, this); + SetSpectatee(this, NULL); - if (!warmup_stage && !this.alivetime) - this.alivetime = time; + // reset player keys + this.itemkeys = 0; + + MUTATOR_CALLHOOK(PutClientInServer, this); - antilag_clear(this, CS(this)); + if (IS_OBSERVER(this)) { + PutObserverInServer(this); + } else if (IS_PLAYER(this)) { + PutPlayerInServer(this); } } @@ -794,7 +821,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); } @@ -807,12 +834,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); } @@ -828,19 +855,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) @@ -848,7 +875,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'); @@ -860,7 +887,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)) @@ -889,7 +916,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; @@ -919,13 +946,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) { @@ -1022,28 +1047,44 @@ 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) { - float n, i; - string s; + // this function allows abbreviated strings! + FOREACH_WORD(list, it == substring(tofind, 0, strlen(it)), + { + return true; + }); + + return false; +} + +bool PlayerInIPList(entity p, string iplist) +{ + // 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 PlayerInIDList(player, list) || PlayerInIPList(player, list); } #ifdef DP_EXT_PRECONNECT @@ -1102,10 +1143,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; @@ -1202,7 +1243,7 @@ void ClientConnect(entity this) stuffcmd(this, strcat("\nfog ", world.fog, "\nr_fog_exp2 0\nr_drawfog 1\n")); if (autocvar_sv_teamnagger && !(autocvar_bot_vs_human && AvailableTeams() == 2)) - if (!g_ca && !g_cts && !g_race) // teamnagger is currently bad for ca, race & cts + if(!MUTATOR_CALLHOOK(HideTeamNagger, this)) send_CSQC_teamnagger(); CSQCMODEL_AUTOINIT(this); @@ -1213,6 +1254,8 @@ void ClientConnect(entity 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)); IL_EACH(g_initforplayer, it.init_for_player, { @@ -1253,7 +1296,8 @@ void ClientDisconnect(entity this) Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_DISCONNECT, this.netname); - SetSpectatee(this, NULL); + if(IS_SPEC(this)) + SetSpectatee(this, NULL); MUTATOR_CALLHOOK(ClientDisconnect, this); @@ -1419,7 +1463,8 @@ void player_powerups(entity this) if (time < this.strength_finished) { this.items = this.items | ITEM_Strength.m_itemid; - Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_STRENGTH, this.netname); + if(!g_cts) + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_STRENGTH, this.netname); Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_POWERUP_STRENGTH); } } @@ -1439,7 +1484,8 @@ void player_powerups(entity this) if (time < this.invincible_finished) { this.items = this.items | ITEM_Shield.m_itemid; - Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_SHIELD, this.netname); + if(!g_cts) + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_SHIELD, this.netname); Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_POWERUP_SHIELD); } } @@ -1473,7 +1519,8 @@ void player_powerups(entity this) if (time < this.superweapons_finished || (this.items & IT_UNLIMITED_SUPERWEAPONS)) { this.items = this.items | IT_SUPERWEAPON; - Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_SUPERWEAPON_PICKUP, this.netname); + if(!g_cts) + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_SUPERWEAPON_PICKUP, this.netname); Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_SUPERWEAPON_PICKUP); } else @@ -1673,6 +1720,7 @@ 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.hagar_load = spectatee.hagar_load; @@ -1701,6 +1749,11 @@ void SpectateCopy(entity this, entity spectatee) this.(weaponentity) = spectatee.(weaponentity); } + for(int slot = 0; slot < MAX_AXH; ++slot) + { + this.(AuxiliaryXhair[slot]) = spectatee.(AuxiliaryXhair[slot]); + } + anticheat_spectatecopy(this, spectatee); this.hud = spectatee.hud; if(spectatee.vehicle) @@ -1780,6 +1833,9 @@ void SetSpectatee_status(entity this, int spectatee_num) void SetSpectatee(entity this, entity spectatee) { + if(IS_BOT_CLIENT(this)) + return; // bots abuse .enemy, this code is useless to them + entity old_spectatee = this.enemy; this.enemy = spectatee; @@ -1920,6 +1976,7 @@ void Join(entity this) PutClientInServer(this); + if(IS_PLAYER(this)) if(teamplay && this.team != -1) Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_JOIN_PLAY_TEAM), this.netname); else @@ -2330,6 +2387,7 @@ void PlayerPreThink (entity this) CheckRules_Player(this); if (game_stopped || intermission_running) { + this.modelflags &= ~MF_ROCKET; if(intermission_running) IntermissionThink(this); return; @@ -2354,6 +2412,13 @@ void PlayerPreThink (entity this) } } 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) @@ -2599,7 +2664,6 @@ PlayerPostThink Called every frame for each client after the physics are run ============= */ -.float idlekick_lasttimeleft; void PlayerPostThink (entity this) { Player_Physics(this); @@ -2620,19 +2684,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) { @@ -2641,10 +2705,10 @@ 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; } } }