X-Git-Url: http://de.git.xonotic.org/?p=voretournament%2Fvoretournament.git;a=blobdiff_plain;f=data%2Fqcsrc%2Fserver%2Fcl_client.qc;h=69404cb855267f1d807420b5d3d3622b6083b3dc;hp=021cf9eaf8534c7bb8480ee145176e51242c6724;hb=a59798ff492b6bb761c12d8c3e97dad25d236cd4;hpb=de90efbc04e63ca3080b5f0051a385df6a12438f diff --git a/data/qcsrc/server/cl_client.qc b/data/qcsrc/server/cl_client.qc index 021cf9ea..69404cb8 100644 --- a/data/qcsrc/server/cl_client.qc +++ b/data/qcsrc/server/cl_client.qc @@ -13,10 +13,13 @@ void Announce(string snd) { } void AnnounceTo(entity e, string snd) { - msg_entity = e; - WriteByte(MSG_ONE, SVC_TEMPENTITY); - WriteByte(MSG_ONE, TE_CSQC_ANNOUNCE); - WriteString(MSG_ONE, snd); + if (clienttype(e) == CLIENTTYPE_REAL) + { + msg_entity = e; + WriteByte(MSG_ONE, SVC_TEMPENTITY); + WriteByte(MSG_ONE, TE_CSQC_ANNOUNCE); + WriteString(MSG_ONE, snd); + } } float ClientData_Send(entity to, float sf) @@ -403,6 +406,7 @@ string CheckPlayerModel(string plyermodel) { { if(substring(plyermodel,-4,4) != ".zym") if(substring(plyermodel,-4,4) != ".dpm") + if(substring(plyermodel,-4,4) != ".iqm") if(substring(plyermodel,-4,4) != ".md3") if(substring(plyermodel,-4,4) != ".psk") return FallbackPlayerModel; @@ -414,11 +418,12 @@ string CheckPlayerModel(string plyermodel) { return plyermodel; } -void setmodel_apply(string modelname) +void setmodel_apply(string modelname, float reset_anims) { precache_model(modelname); setmodel(self, modelname); // players have high precision - player_setupanimsformodel(); + if(reset_anims) + player_setupanimsformodel(); } string setmodel_state() @@ -426,12 +431,12 @@ string setmodel_state() // set the proper belly model depending on how full we are string newmodel_name, newmodel_extension, applymodel; - tokenizebyseparator(self.playermodel, "."); - newmodel_name = argv(0); - newmodel_extension = argv(1); + // 4 is the extension length + newmodel_name = substring(self.playermodel, 0, strlen(self.playermodel) - 4); + newmodel_extension = substring(self.playermodel, strlen(self.playermodel) - 4, 4); if(self.stomach_load) - applymodel = strcat(newmodel_name, "_state", ftos(floor(self.stomach_load)), ".", newmodel_extension); + applymodel = strcat(newmodel_name, "_state", ftos(floor(self.stomach_load)), newmodel_extension); else applymodel = self.playermodel; @@ -454,7 +459,7 @@ void Client_setmodel(string applymodel) applymodel = CheckPlayerModel(applymodel); // this is never "", so no endless loop m1 = self.mins; m2 = self.maxs; - setmodel_apply(applymodel); + setmodel_apply(applymodel, FALSE); setsize (self, m1, m2); } @@ -466,6 +471,7 @@ void Client_uncustomizeentityforclient() float Client_customizeentityforclient() { entity modelsource; + string stomachmodel; if(self.modelindex == 0) return TRUE; @@ -507,27 +513,27 @@ float Client_customizeentityforclient() // now change the predator's player model into a stomach model for the prey // in other words, when a player is swallowed by another player, the predator becomes an inward stomach model so the prey can see theirself in the stomach // this is only visible to the prey however, otherwise players would appear as a floating stomach to everyone (ewww) + stomachmodel = strcat(substring(self.playermodel, 0, strlen(self.playermodel) - 4), "_stomach.md3"); // 4 is the extension length - // don't do this if we have chase_active enabled, as we'd be seeing a floating stomach from third person view - if(other.cvar_chase_active > 0 || other.classname == "observer") // the classname check prevents a bug - { - Client_setmodel(setmodel_state()); - if not(self.predator.classname == "player") - self.alpha = default_player_alpha; - return TRUE; - } if(other.spectatee_status) other = other.enemy; // also do this for the player we are spectating - if(other.predator == self) + + // don't do this if we have chase_active enabled, as we'd be seeing a floating stomach from third person view + if not(other.cvar_chase_active || other.classname == "observer") // the observer check prevents a bug + if(other.predator == self || other.fakepredator == self) { - tokenizebyseparator(self.playermodel, "."); - Client_setmodel(strcat(argv(0), "_stomach.md3")); + Client_setmodel(stomachmodel); self.alpha = other.cvar_cl_vore_stomachmodel; return TRUE; } + Client_setmodel(setmodel_state()); - if not(self.predator.classname == "player") + if not(self.stat_eaten || self.fakeprey) self.alpha = default_player_alpha; + else if(cvar("g_vore_neighborprey_distance") && (self.predator == other.predator || self.predator == other.fakepredator) && self != other && !(other.cvar_chase_active || other.classname == "observer")) + self.alpha = default_player_alpha; // allow seeing neighboring prey + else + self.alpha = -1; // hide prey return TRUE; } @@ -600,7 +606,8 @@ void PutObserverInServer (void) self.armorvalue = cvar("g_balance_armor_start"); self.pauserotarmor_finished = 0; self.pauserothealth_finished = 0; - self.pauseregen_finished = 0; + self.pauseregenhealth_finished = 0; + self.pauseregenarmor_finished = 0; self.damageforcescale = 0; self.death_time = 0; self.dead_frame = 0; @@ -720,7 +727,7 @@ void FixPlayermodel() { m1 = self.mins; m2 = self.maxs; - setmodel_apply (defaultmodel); + setmodel_apply (defaultmodel, TRUE); setsize (self, m1, m2); chmdl = TRUE; } @@ -733,7 +740,7 @@ void FixPlayermodel() self.playermodel = CheckPlayerModel(self.playermodel); // this is never "", so no endless loop m1 = self.mins; m2 = self.maxs; - setmodel_apply (self.playermodel); + setmodel_apply (self.playermodel, TRUE); setsize (self, m1, m2); chmdl = TRUE; } @@ -823,15 +830,22 @@ void PutClientInServer (void) RemoveGrabber(self); // Wazat's Grabber + Vore_DeadPrey_Detach(self); + self.fakeprey = FALSE; // clear the fakeprey status + self.classname = "player"; self.wasplayer = TRUE; self.iscreature = TRUE; self.movetype = MOVETYPE_WALK; - self.solid = SOLID_SLIDEBOX; - if(cvar("g_playerclip_collisions")) - self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP; + if(cvar("g_player_colisions")) + self.solid = SOLID_SLIDEBOX; else - self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY; + self.solid = SOLID_CORPSE; + self.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID; + if(cvar("g_playerclip_collisions")) + self.dphitcontentsmask |= DPCONTENTS_PLAYERCLIP; + if(clienttype(self) == CLIENTTYPE_BOT && cvar("g_botclip_collisions")) + self.dphitcontentsmask |= DPCONTENTS_BOTCLIP; self.frags = FRAGS_PLAYER; if(independent_players) MAKE_INDEPENDENT_PLAYER(self); @@ -865,13 +879,15 @@ void PutClientInServer (void) self.pauserotarmor_finished = time + cvar("g_balance_pause_armor_rot_spawn"); self.pauserothealth_finished = time + cvar("g_balance_pause_health_rot_spawn"); self.pauserotfuel_finished = time + cvar("g_balance_pause_fuel_rot_spawn"); - self.pauseregen_finished = time + cvar("g_balance_pause_health_regen_spawn"); + self.pauseregenhealth_finished = time + cvar("g_balance_pause_health_regen_spawn"); + self.pauseregenarmor_finished = time + cvar("g_balance_pause_armor_regen_spawn"); //extend the pause of rotting if client was reset at the beginning of the countdown if(!cvar("sv_ready_restart_after_countdown") && time < game_starttime) { // TODO why is this cvar NOTted? self.spawnshieldtime += game_starttime - time; self.pauserotarmor_finished += game_starttime - time; self.pauserothealth_finished += game_starttime - time; - self.pauseregen_finished += game_starttime - time; + self.pauseregenhealth_finished += game_starttime - time; + self.pauseregenarmor_finished += game_starttime - time; } self.damageforcescale = 2; self.death_time = 0; @@ -922,7 +938,7 @@ void PutClientInServer (void) // don't reset back to last position, even if new position is stuck in solid self.oldorigin = self.origin; self.prevorigin = self.origin; - self.lastrocket = world; // stop rocket guiding, no revenge from the grave! + self.lastteleporttime = time; // prevent insane speeds due to changing origin if(g_arena) { @@ -979,8 +995,16 @@ void PutClientInServer (void) // reset fields the weapons may use for (j = WEP_FIRST; j <= WEP_LAST; ++j) + { weapon_action(j, WR_RESETPLAYER); + // all weapons must be fully loaded when we spawn + entity e; + e = get_weaponinfo(j); + if(e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars + self.weapon_load[j] = cvar(strcat("g_balance_", e.netname, "_reload_ammo")); + } + oldself = self; self = spot; activator = oldself; @@ -1006,11 +1030,12 @@ float ClientInit_SendEntity(entity to, float sf) WriteString(MSG_ENTITY, world.fog); else WriteString(MSG_ENTITY, ""); + WriteCoord(MSG_ENTITY, cvar("g_campaign")); WriteByte(MSG_ENTITY, cvar("g_balance_armor_blockpercent") * 255.0); WriteByte(MSG_ENTITY, cvar("g_balance_weaponswitchdelay") * 255.0); + WriteCoord(MSG_ENTITY, cvar("g_vore")); WriteCoord(MSG_ENTITY, cvar("g_balance_vore_swallow_limit")); - WriteCoord(MSG_ENTITY, cvar("g_vore_showpreyhealth")); return TRUE; } @@ -1589,7 +1614,7 @@ void ChatBubbleThink() remove(self); return; } - if ((self.owner.BUTTON_CHAT && !self.owner.deadflag && self.owner.predator.classname != "player") + if ((self.owner.BUTTON_CHAT && !self.owner.deadflag && !self.owner.stat_eaten && self.owner.fakepredator.classname != "player") #ifdef TETRIS || self.owner.tetris_on #endif @@ -1632,11 +1657,12 @@ void TeamBubbleThink() return; } // setorigin(self, self.owner.origin + '0 0 15' + self.owner.maxs_z * '0 0 1'); // bandwidth hog. setattachment does this now - if (self.owner.BUTTON_CHAT || self.owner.deadflag || self.owner.killindicator || self.owner.predator.classname == "player") + if (self.owner.BUTTON_CHAT || self.owner.deadflag || self.owner.killindicator || self.owner.stat_eaten) self.model = ""; else { - if(cvar("g_balance_vore_teamheal") && self.owner.health < cvar("g_balance_vore_teamheal_stable")) + if(cvar("g_balance_vore_teamheal") && cvar("g_vore_teamvore")) + if(self.owner.health < cvar("g_balance_vore_teamheal_stable")) setmodel(self, "models/misc/teambubbleheal.spr"); // indicate that this player can be teamhealed else setmodel(self, "models/misc/teambubble.spr"); @@ -1687,10 +1713,31 @@ void UpdateTeamBubble() else self.colormod = '1 1 1'; };*/ +.float oldcolormap; void respawn(void) { + if(self.alpha >= 0 && self.modelindex != 0 && cvar("g_respawn_ghosts")) + { + self.solid = SOLID_NOT; + self.takedamage = DAMAGE_NO; + self.movetype = MOVETYPE_FLY; + self.velocity = '0 0 1' * cvar("g_respawn_ghosts_speed"); + self.avelocity = randomvec() * cvar("g_respawn_ghosts_speed") * 3 - randomvec() * cvar("g_respawn_ghosts_speed") * 3; + self.effects |= EF_ADDITIVE; + self.oldcolormap = self.colormap; + self.colormap = 512; + pointparticles(particleeffectnum("respawn_ghost"), self.origin, '0 0 0', 1); + if(cvar("g_respawn_ghosts_maxtime")) + SUB_SetFade (self, time + cvar("g_respawn_ghosts_maxtime") / 2 + random () * (cvar("g_respawn_ghosts_maxtime") - cvar("g_respawn_ghosts_maxtime") / 2), 1.5); + } + CopyBody(1); self.effects |= EF_NODRAW; // prevent another CopyBody + if(self.oldcolormap) + { + self.colormap = self.oldcolormap; + self.oldcolormap = 0; + } PutClientInServer(); } @@ -1841,7 +1888,8 @@ float CalcRot(float current, float stable, float rotfactor, float rotframetime) return max(stable, current + (stable - current) * rotfactor * rotframetime); } -float CalcRotRegen(float current, float regenstable, float regenfactor, float regenlinear, float regenframetime, float rotstable, float rotfactor, float rotlinear, float rotframetime, float limit) +.float regen_soundtime; +float CalcRotRegen(float current, float regenstable, float regenfactor, float regenlinear, float regenframetime, float rotstable, float rotfactor, float rotlinear, float rotframetime, float limit, string regensound) { if(current > rotstable) { @@ -1857,6 +1905,18 @@ float CalcRotRegen(float current, float regenstable, float regenfactor, float re { current = CalcRegen(current, regenstable, regenfactor, regenframetime); current = min(regenstable, current + regenlinear * regenframetime); + + if(regensound != "") + if(regenfactor || regenlinear) + { + if(self.regen_soundtime < time) + { + msg_entity = self; + if(clienttype(msg_entity) == CLIENTTYPE_REAL) + soundto(MSG_ONE, self, CHAN_AUTO, regensound, VOL_BASE, ATTN_NONE); + } + self.regen_soundtime = time + 1; // only replay the sound if regen was paused for one second + } } } @@ -1896,8 +1956,8 @@ void player_regen (void) if (!g_ca && (!g_lms || cvar("g_lms_regenerate"))) { - self.armorvalue = CalcRotRegen(self.armorvalue, mina, cvar("g_balance_armor_regen"), cvar("g_balance_armor_regenlinear"), regen_mod * frametime * (time > self.pauseregen_finished), maxa, cvar("g_balance_armor_rot"), cvar("g_balance_armor_rotlinear"), rot_mod * frametime * (time > self.pauserotarmor_finished), limita); - self.health = CalcRotRegen(self.health, minh, cvar("g_balance_health_regen"), cvar("g_balance_health_regenlinear"), regen_mod * frametime * (time > self.pauseregen_finished), maxh, cvar("g_balance_health_rot"), cvar("g_balance_health_rotlinear"), rot_mod * frametime * (time > self.pauserothealth_finished), limith); + self.armorvalue = CalcRotRegen(self.armorvalue, mina, cvar("g_balance_armor_regen"), cvar("g_balance_armor_regenlinear"), regen_mod * frametime * (time > self.pauseregenarmor_finished), maxa, cvar("g_balance_armor_rot"), cvar("g_balance_armor_rotlinear"), rot_mod * frametime * (time > self.pauserotarmor_finished), limita, "misc/armor_regen.wav"); + self.health = CalcRotRegen(self.health, minh, cvar("g_balance_health_regen"), cvar("g_balance_health_regenlinear"), regen_mod * frametime * (time > self.pauseregenhealth_finished), maxh, cvar("g_balance_health_rot"), cvar("g_balance_health_rotlinear"), rot_mod * frametime * (time > self.pauserothealth_finished), limith, "misc/health_regen.wav"); // if player rotted to death... die! if(self.health < 1) @@ -1905,7 +1965,7 @@ void player_regen (void) } if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_fuel = CalcRotRegen(self.ammo_fuel, minf, cvar("g_balance_fuel_regen"), cvar("g_balance_fuel_regenlinear"), regen_mod * frametime * (time > self.pauseregen_finished) * (self.items & IT_FUEL_REGEN != 0), maxf, cvar("g_balance_fuel_rot"), cvar("g_balance_fuel_rotlinear"), rot_mod * frametime * (time > self.pauserotfuel_finished), limitf); + self.ammo_fuel = CalcRotRegen(self.ammo_fuel, minf, cvar("g_balance_fuel_regen"), cvar("g_balance_fuel_regenlinear"), regen_mod * frametime * (time > self.pauseregenhealth_finished) * (self.items & IT_FUEL_REGEN != 0), maxf, cvar("g_balance_fuel_rot"), cvar("g_balance_fuel_rotlinear"), rot_mod * frametime * (time > self.pauserotfuel_finished), limitf, ""); } float zoomstate_set; @@ -1993,10 +2053,13 @@ void SpectateCopy(entity spectatee) { self.armortype = spectatee.armortype; self.armorvalue = spectatee.armorvalue; self.ammo_fuel = spectatee.ammo_fuel; + self.clip_load = spectatee.clip_load; + self.clip_size = spectatee.clip_size; self.effects = spectatee.effects & EFMASK_CHEAP; // eat performance self.health = spectatee.health; self.impulse = 0; self.items = spectatee.items; + self.last_pickup = spectatee.last_pickup; self.strength_finished = spectatee.strength_finished; self.invincible_finished = spectatee.invincible_finished; self.pressedkeys = spectatee.pressedkeys; @@ -2011,12 +2074,18 @@ void SpectateCopy(entity spectatee) { self.dmg_save = spectatee.dmg_save; self.dmg_inflictor = spectatee.dmg_inflictor; self.angles = spectatee.v_angle; + self.scale = spectatee.scale; self.fixangle = TRUE; self.stomach_load = spectatee.stomach_load; self.stat_eaten = spectatee.stat_eaten; self.stat_stomachload = spectatee.stat_stomachload; self.stat_digesting = spectatee.stat_digesting; self.stat_canleave = spectatee.stat_canleave; + self.stat_canswallow = spectatee.stat_canswallow; + self.stat_sbring1_type = spectatee.stat_sbring1_type; + self.stat_sbring1_clip = spectatee.stat_sbring1_clip; + self.stat_sbring2_type = spectatee.stat_sbring2_type; + self.stat_sbring2_clip = spectatee.stat_sbring2_clip; setorigin(self, spectatee.origin); setsize(self, spectatee.mins, spectatee.maxs); SetZoomState(spectatee.zoomstate); @@ -2208,6 +2277,39 @@ float vercmp(string v1, string v2) return vercmp_recursive(v1, v2); } +void SetPlayerSize() +{ + if(cvar("g_healthsize")) + { + // change player scale based on the amount of health we have + + self.scale = bound(cvar("g_healthsize_min"), self.health, cvar("g_healthsize_max")) / cvar("g_healthsize"); + + // The following code sets the bounding box to match the player's size. + // It is currently disabled because of issues with engine movement prediction (cl_movement). + // The engine expects the bounding box to be default size, and changing it will cause glitches. + // This code may be enabled once the engine has the ability to use different bbox sizes for movement prediction. + if(self.crouch) + { + //setsize (self, PL_CROUCH_MIN * self.scale, PL_CROUCH_MAX * self.scale); + if(!self.stat_eaten) + self.view_ofs = PL_CROUCH_VIEW_OFS * self.scale; + } + else + { + //setsize (self, PL_MIN * self.scale, PL_MAX * self.scale); + if(!self.stat_eaten) + self.view_ofs = PL_VIEW_OFS * self.scale; + } + } + + if(self.stat_eaten && cvar("g_vore_neighborprey_distance")) + { + // resize prey if neighborprey is enabled + self.scale *= cvar("g_vore_neighborprey_scale"); + } +} + void ObserverThink() { if (self.flags & FL_JUMPRELEASED) { @@ -2530,6 +2632,8 @@ void PlayerPreThink (void) } } + SetPlayerSize(); + FixPlayermodel(); GrabberFrame(); @@ -2605,11 +2709,31 @@ void PlayerPreThink (void) if(self.taunt_soundtime) if(time > self.taunt_soundtime) { + switch(self.taunt_soundtype) + { + case TAUNTTYPE_DEATH: + PlayerSound(self, playersound_taunt, CHAN_VOICE, VOICETYPE_AUTOTAUNT); + break; + case TAUNTTYPE_VOREPRED: + PlayerSound(self, playersound_pred, CHAN_VOICE, VOICETYPE_AUTOTAUNT); + break; + case TAUNTTYPE_VOREPREY: + PlayerSound(self, playersound_prey, CHAN_VOICE, VOICETYPE_AUTOTAUNT); + break; + default: + dprint("Incorrect autotaunt type\n"); + break; + } + self.taunt_soundtime = 0; - PlayerSound(self, playersound_taunt, CHAN_VOICE, VOICETYPE_AUTOTAUNT); + self.taunt_soundtype = 0; } target_voicescript_next(self); + + // if a player goes unarmed after holding a loaded weapon, empty his clip size and remove the crosshair ammo ring + if(!self.weapon) + self.clip_load = self.clip_size = 0; } float isInvisibleString(string s) @@ -2622,9 +2746,16 @@ float isInvisibleString(string s) switch(c) { case 0: - case 32: - case 160: + case 32: // space break; + case 192: // charmap space + if (!cvar("utf8_enable")) + break; + return FALSE; + case 160: // space in unicode fonts + case 0xE000 + 192: // utf8 charmap space + if (cvar("utf8_enable")) + break; default: return FALSE; }