X-Git-Url: http://de.git.xonotic.org/?p=voretournament%2Fvoretournament.git;a=blobdiff_plain;f=data%2Fqcsrc%2Fserver%2Fcl_client.qc;h=8f058155c16a32c95245724dd31d9a967fafb382;hp=c369b3ef356f3a1633fa1509787dec14b94b8b11;hb=02d2b7c6fea422d536b734893e079ab7f123c1c9;hpb=8e42d7a5946fa23db799590f5e56b604b4134326 diff --git a/data/qcsrc/server/cl_client.qc b/data/qcsrc/server/cl_client.qc index c369b3ef..8f058155 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) @@ -393,8 +396,7 @@ Checks if the argument string can be a valid playermodel. Returns a valid one in doubt. ============= */ -// string FallbackPlayerModel = "models/player/vixen.zym"; -string FallbackPlayerModel = "models/onslaught/generator.md3"; // TEMPORARY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +string FallbackPlayerModel = "models/player/vixen.zym"; string CheckPlayerModel(string plyermodel) { if(strlen(plyermodel) < 4) return FallbackPlayerModel; @@ -404,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; @@ -415,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() @@ -427,16 +431,20 @@ 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); + + float vore_state; + if(self.stomach_load > ceil(g_balance_vore_swallow_limit * 0.6)) + vore_state = 3; + else if(self.stomach_load > ceil(g_balance_vore_swallow_limit * 0.3)) + vore_state = 2; + else if(self.stomach_load) + vore_state = 1; - if(self.stomach_load >= 3) - applymodel = strcat(newmodel_name, "_state3.", newmodel_extension); - else if(self.stomach_load >= 2) - applymodel = strcat(newmodel_name, "_state2.", newmodel_extension); - else if(self.stomach_load >= 1) - applymodel = strcat(newmodel_name, "_state1.", newmodel_extension); + if(vore_state) + applymodel = strcat(newmodel_name, "_state", ftos(vore_state), newmodel_extension); else applymodel = self.playermodel; @@ -459,7 +467,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); } @@ -471,6 +479,7 @@ void Client_uncustomizeentityforclient() float Client_customizeentityforclient() { entity modelsource; + string stomachmodel; if(self.modelindex == 0) return TRUE; @@ -510,29 +519,29 @@ float Client_customizeentityforclient() #endif // 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 eater becomes an inward stomach model so the prey can see theirself in the stomach + // 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.eater.classname == "player") - self.alpha = default_player_alpha; - return TRUE; - } - if(other.spectatee_status) + if(other.spectatee_status && other.spectatee_status == num_for_edict(other.enemy)) other = other.enemy; // also do this for the player we are spectating - if(other.eater == 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.eater.classname == "player") + if not(self.stat_eaten || self.fakeprey) self.alpha = default_player_alpha; + else if(cvar("g_vore_neighborprey_distance") && !self.fakeprey && (self.predator == other.predator || self.predator == other.fakepredator) && !(other.cvar_chase_active || other.classname == "observer")) + self.alpha = default_player_alpha; // allow seeing neighboring prey + else + self.alpha = -1; // hide prey return TRUE; } @@ -605,7 +614,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; @@ -725,7 +735,7 @@ void FixPlayermodel() { m1 = self.mins; m2 = self.maxs; - setmodel_apply (defaultmodel); + setmodel_apply (defaultmodel, TRUE); setsize (self, m1, m2); chmdl = TRUE; } @@ -738,7 +748,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; } @@ -828,15 +838,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); @@ -870,13 +887,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; @@ -927,7 +946,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) { @@ -984,8 +1003,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; @@ -1011,11 +1038,19 @@ 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_balance_vore_swallow_limit")); - WriteCoord(MSG_ENTITY, cvar("g_vore_showpreyhealth")); + WriteCoord(MSG_ENTITY, cvar("g_vore")); + WriteCoord(MSG_ENTITY, g_balance_vore_swallow_limit); + + // tell the client if this server uses armor + float armor_enabled; + if(cvar("g_balance_armor_start") || (cvar("g_lms") && cvar("g_lms_start_armor")) || (inWarmupStage && cvar("g_warmup_start_armor")) || cvar("g_balance_armor_regen") || cvar("g_balance_armor_regenlinear")) + armor_enabled = TRUE; + WriteByte(MSG_ENTITY, armor_enabled); + return TRUE; } @@ -1594,7 +1629,7 @@ void ChatBubbleThink() remove(self); return; } - if ((self.owner.BUTTON_CHAT && !self.owner.deadflag && self.owner.eater.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 @@ -1637,11 +1672,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.eater.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"); @@ -1692,10 +1728,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(); } @@ -1846,7 +1903,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) { @@ -1862,6 +1920,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 + } } } @@ -1901,8 +1971,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) @@ -1910,7 +1980,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; @@ -1998,10 +2068,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; @@ -2016,12 +2089,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); @@ -2213,6 +2292,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) { @@ -2401,6 +2513,29 @@ void PlayerPreThink (void) if(frametime) { + + if(self.health <= 0 && cvar("g_deathglow")) + { + if(self.glowmod_x > 0) + self.glowmod_x -= cvar("g_deathglow") * frametime; + else + self.glowmod_x = -1; + if(self.glowmod_y > 0) + self.glowmod_y -= cvar("g_deathglow") * frametime; + else + self.glowmod_y = -1; + if(self.glowmod_z > 0) + self.glowmod_z -= cvar("g_deathglow") * frametime; + else + self.glowmod_z = -1; + } + else + { + // set weapon and player glowmod + self.glowmod = colormapPaletteColor(self.clientcolors & 0x0F, TRUE) * 2; + self.weaponentity_glowmod = self.glowmod; + } + player_powerups(); } @@ -2535,6 +2670,8 @@ void PlayerPreThink (void) } } + SetPlayerSize(); + FixPlayermodel(); GrabberFrame(); @@ -2610,11 +2747,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) @@ -2627,9 +2784,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; }