X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fcl_player.qc;h=a542e6431345095828ccd90dc87dd9ecc081406e;hb=b7d363a108963ca13647ee25b58c5a531366cf49;hp=c6b0359c4ee89bd20f3b05de8df71eae2c251f7f;hpb=068324d293df795dbc41de75f38256b8c6c35607;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/cl_player.qc b/qcsrc/server/cl_player.qc index c6b0359c4..a542e6431 100644 --- a/qcsrc/server/cl_player.qc +++ b/qcsrc/server/cl_player.qc @@ -1,6 +1,6 @@ #include "cl_player.qh" -#include "bot/bot.qh" +#include "bot/api.qh" #include "cheats.qh" #include "g_damage.qh" #include "g_subs.qh" @@ -9,6 +9,7 @@ #include "teamplay.qh" #include "weapons/throwing.qh" #include "command/common.qh" +#include "../common/state.qh" #include "../common/anim.qh" #include "../common/animdecide.qh" #include "../common/csqcmodel_settings.qh" @@ -19,6 +20,8 @@ #include "../common/minigames/sv_minigames.qh" +#include "../common/physics/player.qh" +#include "../common/effects/qc/all.qh" #include "../common/mutators/mutator/waypoints/waypointsprites.qh" #include "../common/triggers/include.qh" @@ -34,107 +37,107 @@ void Drop_Special_Items(entity player) MUTATOR_CALLHOOK(DropSpecialItems, player); } -void CopyBody_Think() -{SELFPARAM(); - if(self.CopyBody_nextthink && time > self.CopyBody_nextthink) +void CopyBody_Think(entity this) +{ + if(this.CopyBody_nextthink && time > this.CopyBody_nextthink) { - self.CopyBody_think(); - if(wasfreed(self)) + this.CopyBody_think(this); + if(wasfreed(this)) return; - self.CopyBody_nextthink = self.nextthink; - self.CopyBody_think = self.think; - self.think = CopyBody_Think; + this.CopyBody_nextthink = this.nextthink; + this.CopyBody_think = getthink(this); + setthink(this, CopyBody_Think); } - CSQCMODEL_AUTOUPDATE(self); - self.nextthink = time; + CSQCMODEL_AUTOUPDATE(this); + this.nextthink = time; } -void CopyBody(float keepvelocity) -{SELFPARAM(); - if (self.effects & EF_NODRAW) +void CopyBody(entity this, float keepvelocity) +{ + if (this.effects & EF_NODRAW) return; - setself(new(body)); - self.enemy = this; - self.lip = this.lip; - self.colormap = this.colormap; - self.iscreature = this.iscreature; - self.teleportable = this.teleportable; - self.damagedbycontents = this.damagedbycontents; - self.angles = this.angles; - self.v_angle = this.v_angle; - self.avelocity = this.avelocity; - self.damageforcescale = this.damageforcescale; - self.effects = this.effects; - self.glowmod = this.glowmod; - self.event_damage = this.event_damage; - self.anim_state = this.anim_state; - self.anim_time = this.anim_time; - self.anim_lower_action = this.anim_lower_action; - self.anim_lower_time = this.anim_lower_time; - self.anim_upper_action = this.anim_upper_action; - self.anim_upper_time = this.anim_upper_time; - self.anim_implicit_state = this.anim_implicit_state; - self.anim_implicit_time = this.anim_implicit_time; - self.anim_lower_implicit_action = this.anim_lower_implicit_action; - self.anim_lower_implicit_time = this.anim_lower_implicit_time; - self.anim_upper_implicit_action = this.anim_upper_implicit_action; - self.anim_upper_implicit_time = this.anim_upper_implicit_time; - self.dphitcontentsmask = this.dphitcontentsmask; - self.death_time = this.death_time; - self.pain_finished = this.pain_finished; - self.health = this.health; - self.armorvalue = this.armorvalue; - self.armortype = this.armortype; - self.model = this.model; - self.modelindex = this.modelindex; - self.skin = this.skin; - self.species = this.species; - self.movetype = this.movetype; - self.solid = this.solid; - self.ballistics_density = this.ballistics_density; - self.takedamage = this.takedamage; - self.customizeentityforclient = this.customizeentityforclient; - self.uncustomizeentityforclient = this.uncustomizeentityforclient; - self.uncustomizeentityforclient_set = this.uncustomizeentityforclient_set; + entity clone = new(body); + clone.enemy = this; + clone.lip = this.lip; + clone.colormap = this.colormap; + clone.iscreature = this.iscreature; + clone.teleportable = this.teleportable; + clone.damagedbycontents = this.damagedbycontents; + clone.angles = this.angles; + clone.v_angle = this.v_angle; + clone.avelocity = this.avelocity; + clone.damageforcescale = this.damageforcescale; + clone.effects = this.effects; + clone.glowmod = this.glowmod; + clone.event_damage = this.event_damage; + clone.anim_state = this.anim_state; + clone.anim_time = this.anim_time; + clone.anim_lower_action = this.anim_lower_action; + clone.anim_lower_time = this.anim_lower_time; + clone.anim_upper_action = this.anim_upper_action; + clone.anim_upper_time = this.anim_upper_time; + clone.anim_implicit_state = this.anim_implicit_state; + clone.anim_implicit_time = this.anim_implicit_time; + clone.anim_lower_implicit_action = this.anim_lower_implicit_action; + clone.anim_lower_implicit_time = this.anim_lower_implicit_time; + clone.anim_upper_implicit_action = this.anim_upper_implicit_action; + clone.anim_upper_implicit_time = this.anim_upper_implicit_time; + clone.dphitcontentsmask = this.dphitcontentsmask; + clone.death_time = this.death_time; + clone.pain_finished = this.pain_finished; + clone.health = this.health; + clone.armorvalue = this.armorvalue; + clone.armortype = this.armortype; + clone.model = this.model; + clone.modelindex = this.modelindex; + clone.skin = this.skin; + clone.species = this.species; + clone.move_qcphysics = false; // don't run gamecode logic on clones, too many + set_movetype(clone, this.move_movetype); + clone.solid = this.solid; + clone.ballistics_density = this.ballistics_density; + clone.takedamage = this.takedamage; + setcefc(clone, getcefc(this)); + clone.uncustomizeentityforclient = this.uncustomizeentityforclient; + clone.uncustomizeentityforclient_set = this.uncustomizeentityforclient_set; if (keepvelocity == 1) - self.velocity = this.velocity; - self.oldvelocity = self.velocity; - self.alpha = this.alpha; - self.fade_time = this.fade_time; - self.fade_rate = this.fade_rate; - //self.weapon = this.weapon; - setorigin(self, this.origin); - setsize(self, this.mins, this.maxs); - self.prevorigin = this.origin; - self.reset = SUB_Remove; - - Drag_MoveDrag(this, self); - - if(self.colormap <= maxclients && self.colormap > 0) - self.colormap = 1024 + this.clientcolors; - - CSQCMODEL_AUTOINIT(self); - self.CopyBody_nextthink = this.nextthink; - self.CopyBody_think = this.think; - self.nextthink = time; - self.think = CopyBody_Think; + clone.velocity = this.velocity; + clone.oldvelocity = clone.velocity; + clone.alpha = this.alpha; + clone.fade_time = this.fade_time; + clone.fade_rate = this.fade_rate; + //clone.weapon = this.weapon; + setorigin(clone, this.origin); + setsize(clone, this.mins, this.maxs); + clone.prevorigin = this.origin; + clone.reset = SUB_Remove; + clone._ps = this._ps; + + Drag_MoveDrag(this, clone); + + if(clone.colormap <= maxclients && clone.colormap > 0) + clone.colormap = 1024 + this.clientcolors; + + CSQCMODEL_AUTOINIT(clone); + clone.CopyBody_nextthink = this.nextthink; + clone.CopyBody_think = getthink(this); + clone.nextthink = time; + setthink(clone, CopyBody_Think); // "bake" the current animation frame for clones (they don't get clientside animation) - animdecide_load_if_needed(self); - animdecide_setframes(self, false, frame, frame1time, frame2, frame2time); - - setself(this); + animdecide_load_if_needed(clone); + animdecide_setframes(clone, false, frame, frame1time, frame2, frame2time); } -void player_setupanimsformodel() -{SELFPARAM(); +void player_setupanimsformodel(entity this) +{ // load animation info - animdecide_load_if_needed(self); - animdecide_setstate(self, 0, false); + animdecide_load_if_needed(this); + animdecide_setstate(this, 0, false); } -void player_anim () -{SELFPARAM(); - int deadbits = (self.anim_state & (ANIMSTATE_DEAD1 | ANIMSTATE_DEAD2)); - if(IS_DEAD(self)) { +void player_anim(entity this) +{ + int deadbits = (this.anim_state & (ANIMSTATE_DEAD1 | ANIMSTATE_DEAD2)); + if(IS_DEAD(this)) { if (!deadbits) { // Decide on which death animation to use. if(random() < 0.5) @@ -147,14 +150,14 @@ void player_anim () deadbits = 0; } int animbits = deadbits; - if(STAT(FROZEN, self)) + if(STAT(FROZEN, this)) animbits |= ANIMSTATE_FROZEN; - if(self.movetype == MOVETYPE_FOLLOW) + if(this.move_movetype == MOVETYPE_FOLLOW) animbits |= ANIMSTATE_FOLLOW; - if(self.crouch) + if(this.crouch) animbits |= ANIMSTATE_DUCK; - animdecide_setstate(self, animbits, false); - animdecide_setimplicitstate(self, (IS_ONGROUND(self))); + animdecide_setstate(this, animbits, false); + animdecide_setimplicitstate(this, IS_ONGROUND(this)); } void PlayerCorpseDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force) @@ -362,7 +365,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, { this.pusher = attacker; this.pushltime = time + autocvar_g_maxpushtime; - this.istypefrag = this.BUTTON_CHAT; + this.istypefrag = PHYS_INPUT_BUTTON_CHAT(this); } else if(time < this.pushltime) { @@ -375,10 +378,16 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, this.istypefrag = 0; } - frag_damage = damage; - MUTATOR_CALLHOOK(PlayerDamage_SplitHealthArmor, inflictor, attacker, this, force, take, save); - take = bound(0, damage_take, this.health); - save = bound(0, damage_save, this.armorvalue); + if (time < this.spawnshieldtime && autocvar_g_spawnshield_blockdamage < 1) + { + vector v = healtharmor_applydamage(this.armorvalue, max(0, autocvar_g_spawnshield_blockdamage), deathtype, damage); + take = v.x; + save = v.y; + } + + MUTATOR_CALLHOOK(PlayerDamage_SplitHealthArmor, inflictor, attacker, this, force, take, save, deathtype, damage); + take = bound(0, M_ARGV(4, float), this.health); + save = bound(0, M_ARGV(5, float), this.armorvalue); excess = max(0, damage - take - save); if(sound_allowed(MSG_BROADCAST, attacker)) @@ -396,7 +405,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, if (take > 100) Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, this, attacker); - if (time >= this.spawnshieldtime) + if (time >= this.spawnshieldtime || autocvar_g_spawnshield_blockdamage < 1) { if (!(this.flags & FL_GODMODE)) { @@ -428,15 +437,15 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, // exclude pain sounds for laserjumps as long as you aren't REALLY low on health and would die of the next two { if(deathtype == DEATH_FALL.m_id) - PlayerSound(this, playersound_fall, CH_PAIN, VOICETYPE_PLAYERSOUND); - else if(this.health > 75) // TODO make a "gentle" version? - PlayerSound(this, playersound_pain100, CH_PAIN, VOICETYPE_PLAYERSOUND); + PlayerSound(this, playersound_fall, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND); + else if(this.health > 75) + PlayerSound(this, playersound_pain100, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND); else if(this.health > 50) - PlayerSound(this, playersound_pain75, CH_PAIN, VOICETYPE_PLAYERSOUND); + PlayerSound(this, playersound_pain75, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND); else if(this.health > 25) - PlayerSound(this, playersound_pain50, CH_PAIN, VOICETYPE_PLAYERSOUND); + PlayerSound(this, playersound_pain50, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND); else - PlayerSound(this, playersound_pain25, CH_PAIN, VOICETYPE_PLAYERSOUND); + PlayerSound(this, playersound_pain25, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND); } } } @@ -486,11 +495,14 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, valid_damage_for_weaponstats = 1; } + dh = dh - max(this.health, 0); + da = da - max(this.armorvalue, 0); if(valid_damage_for_weaponstats) { - dh = dh - max(this.health, 0); - da = da - max(this.armorvalue, 0); WeaponStats_LogDamage(awep.m_id, abot, PS(this).m_weapon.m_id, vbot, dh + da); + } + if (dh + da) + { MUTATOR_CALLHOOK(PlayerDamaged, attacker, this, dh, da, hitloc, deathtype); } @@ -508,20 +520,20 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, if(valid_damage_for_weaponstats) WeaponStats_LogKill(awep.m_id, abot, PS(this).m_weapon.m_id, vbot); - if(autocvar_sv_gentle < 1) // TODO make a "gentle" version? + if(autocvar_sv_gentle < 1) if(sound_allowed(MSG_BROADCAST, attacker)) { if(deathtype == DEATH_DROWN.m_id) - PlayerSound(this, playersound_drown, CH_PAIN, VOICETYPE_PLAYERSOUND); + PlayerSound(this, playersound_drown, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND); else - PlayerSound(this, playersound_death, CH_PAIN, VOICETYPE_PLAYERSOUND); + PlayerSound(this, playersound_death, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND); } // get rid of kill indicator if(this.killindicator) { - remove(this.killindicator); - this.killindicator = world; + delete(this.killindicator); + this.killindicator = NULL; if(this.killindicator_teamchange) defer_ClientKill_Now_TeamChange = true; @@ -543,11 +555,11 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, if(accuracy_isgooddamage(attacker, this)) attacker.accuracy.(accuracy_frags[w.m_id-1]) += 1; - MUTATOR_CALLHOOK(PlayerDies, inflictor, attacker, this, deathtype); - excess = frag_damage; + MUTATOR_CALLHOOK(PlayerDies, inflictor, attacker, this, deathtype, damage); + excess = M_ARGV(4, float); Weapon wep = PS(this).m_weapon; - WITH(entity, self, this, wep.wr_playerdeath(wep)); + wep.wr_playerdeath(wep, this); RemoveGrapplingHook(this); @@ -583,7 +595,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, // view from the floor this.view_ofs = '0 0 -8'; // toss the corpse - this.movetype = MOVETYPE_TOSS; + set_movetype(this, MOVETYPE_TOSS); // shootable corpse this.solid = SOLID_CORPSE; this.ballistics_density = autocvar_g_ballistics_density_corpse; @@ -613,10 +625,10 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, // set up to fade out later SUB_SetFade (this, time + 6 + random (), 1); // reset body think wrapper broken by SUB_SetFade - if(this.classname == "body" && this.think != CopyBody_Think) { - this.CopyBody_think = this.think; + if(this.classname == "body" && getthink(this) != CopyBody_Think) { + this.CopyBody_think = getthink(this); this.CopyBody_nextthink = this.nextthink; - this.think = CopyBody_Think; + setthink(this, CopyBody_Think); this.nextthink = time; } @@ -628,7 +640,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, // reset fields the weapons may use just in case FOREACH(Weapons, it != WEP_Null, LAMBDA( - WITH(entity, self, this, it.wr_resetplayer(it)); + it.wr_resetplayer(it, this); for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { ATTACK_FINISHED_FOR(this, it.m_id, slot) = 0; @@ -648,6 +660,12 @@ void MoveToTeam(entity client, int team_colour, int type) LogTeamchange(client.playerid, client.team, type); } +/** print(), but only print if the server is not local */ +void dedicated_print(string input) +{ + if (server_is_dedicated) print(input); +} + /** * message "": do not say, just test flood control * return value: @@ -655,20 +673,14 @@ void MoveToTeam(entity client, int team_colour, int type) * 0 = reject * -1 = fake accept */ -int Say(entity source, float teamsay, entity privatesay, string msgin, bool floodcontrol) +int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodcontrol) { - string msgstr, colorstr, cmsgstr, namestr, fullmsgstr, sourcemsgstr, fullcmsgstr, sourcecmsgstr, colorprefix; - float flood; - var .float flood_field; - float ret; - string privatemsgprefix = string_null; float privatemsgprefixlen = 0; - - if(!teamsay && !privatesay) - if(substring(msgin, 0, 1) == " ") - msgin = substring(msgin, 1, strlen(msgin) - 1); // work around DP say bug (say_team does not have this!) + if (!teamsay && !privatesay) if (substring(msgin, 0, 1) == " ") + msgin = substring(msgin, 1, -1); // work around DP say bug (say_team does not have this!) - msgin = formatmessage(msgin); + msgin = formatmessage(source, msgin); + string colorstr; if (!IS_PLAYER(source)) colorstr = "^0"; // black for spectators else if(teamplay) @@ -682,6 +694,11 @@ int Say(entity source, float teamsay, entity privatesay, string msgin, bool floo if(intermission_running) teamsay = false; + if (!source) { + colorstr = ""; + teamsay = false; + } + if(msgin != "") msgin = trigger_magicear_processmessage_forallears(source, teamsay, privatesay, msgin); @@ -691,23 +708,23 @@ int Say(entity source, float teamsay, entity privatesay, string msgin, bool floo // for now, just give "say" back and only handle say_team if(!teamsay) { - clientcommand(self, strcat("say ", msgin)); + clientcommand(source, strcat("say ", msgin)); return; } */ - if(autocvar_g_chat_teamcolors) - namestr = playername(source); - else - namestr = source.netname; + string namestr = ""; + if (source) + namestr = autocvar_g_chat_teamcolors ? playername(source) : source.netname; - if(strdecolorize(namestr) == namestr) - colorprefix = "^3"; - else - colorprefix = "^7"; + string colorprefix = (strdecolorize(namestr) == namestr) ? "^3" : "^7"; - if(msgin != "") - { + string msgstr, cmsgstr; + string privatemsgprefix = string_null; + int privatemsgprefixlen = 0; + if (msgin == "") { + msgstr = cmsgstr = ""; + } else { if(privatesay) { msgstr = strcat("\{1}\{13}* ", colorprefix, namestr, "^3 tells you: ^7"); @@ -741,23 +758,22 @@ int Say(entity source, float teamsay, entity privatesay, string msgin, bool floo msgin = strreplace("/me", strcat(colorprefix, namestr), msgin); msgstr = strcat("\{1}^4* ", "^7", msgin); } - else - msgstr = strcat("\{1}", colorprefix, namestr, "^7: ", msgin); + else { + msgstr = "\{1}"; + msgstr = strcat(msgstr, (namestr != "") ? strcat(colorprefix, namestr, "^7: ") : "^7"); + msgstr = strcat(msgstr, msgin); + } cmsgstr = ""; } msgstr = strcat(strreplace("\n", " ", msgstr), "\n"); // newlines only are good for centerprint } - else - { - msgstr = cmsgstr = ""; - } - fullmsgstr = msgstr; - fullcmsgstr = cmsgstr; + string fullmsgstr = msgstr; + string fullcmsgstr = cmsgstr; // FLOOD CONTROL - flood = 0; - flood_field = floodcontrol_chat; + int flood = 0; + var .float flood_field = floodcontrol_chat; if(floodcontrol) { float flood_spl; @@ -829,6 +845,7 @@ int Say(entity source, float teamsay, entity privatesay, string msgin, bool floo source.(flood_field) = flood = 0; } + string sourcemsgstr, sourcecmsgstr; if(flood == 2) // cannot happen for empty msgstr { if(autocvar_g_chat_flood_notify_flooder) @@ -849,8 +866,7 @@ int Say(entity source, float teamsay, entity privatesay, string msgin, bool floo sourcecmsgstr = cmsgstr; } - if(!privatesay) - if (!IS_PLAYER(source)) + if (!privatesay && source && !IS_PLAYER(source)) { if (!intermission_running) if(teamsay || (autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !(warmup_stage || gameover))) @@ -864,6 +880,7 @@ int Say(entity source, float teamsay, entity privatesay, string msgin, bool floo if(privatesay) sourcemsgstr = strcat(privatemsgprefix, substring(sourcemsgstr, privatemsgprefixlen, -1)); + int ret; if(source.muted) { // always fake the message @@ -904,7 +921,7 @@ int Say(entity source, float teamsay, entity privatesay, string msgin, bool floo { sprint(source, sourcemsgstr); dedicated_print(msgstr); // send to server console too - FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source && it.active_minigame == source.active_minigame, LAMBDA(sprint(it, msgstr))); + FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source && it.active_minigame == source.active_minigame, sprint(it, msgstr)); } else if(teamsay > 0) // team message, only sent to team mates { @@ -912,26 +929,27 @@ int Say(entity source, float teamsay, entity privatesay, string msgin, bool floo dedicated_print(msgstr); // send to server console too if(sourcecmsgstr != "") centerprint(source, sourcecmsgstr); - FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && it != source && it.team == source.team, LAMBDA( + FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && it != source && it.team == source.team, { sprint(it, msgstr); if(cmsgstr != "") centerprint(it, cmsgstr); - )); + }); } else if(teamsay < 0) // spectator message, only sent to spectators { sprint(source, sourcemsgstr); dedicated_print(msgstr); // send to server console too - FOREACH_CLIENT(!IS_PLAYER(it) && IS_REAL_CLIENT(it) && it != source, LAMBDA(sprint(it, msgstr))); - } - else if(sourcemsgstr != msgstr) // trimmed/server fixed message, sent to all players - { - sprint(source, sourcemsgstr); - dedicated_print(msgstr); // send to server console too - FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source, LAMBDA(sprint(it, msgstr))); + FOREACH_CLIENT(!IS_PLAYER(it) && IS_REAL_CLIENT(it) && it != source, sprint(it, msgstr)); } else - bprint(msgstr); // entirely normal message, sent to all players -- bprint sends to server console too. + { + if (source) { + sprint(source, sourcemsgstr); + dedicated_print(msgstr); // send to server console too + MX_Say(strcat(playername(source), "^7: ", msgin)); + } + FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source, sprint(it, msgstr)); + } } return ret;