X-Git-Url: http://de.git.xonotic.org/?p=voretournament%2Fvoretournament.git;a=blobdiff_plain;f=data%2Fqcsrc%2Fserver%2Fcl_client.qc;h=9ca8a4e7627b0f1991be5c944a4cc4ce611a0b59;hp=aee74f091881c8a18ac5d619511b90e326ac6d39;hb=9476b45c525bfb1886a7c296f3583e3b57c9d372;hpb=8dc6d951d2e109ccf8966e2c408343161e2d8cda diff --git a/data/qcsrc/server/cl_client.qc b/data/qcsrc/server/cl_client.qc index aee74f09..9ca8a4e7 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,13 +418,11 @@ 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 - - // don't attempt to animate the stomach model - if not(substring(modelname, strlen(modelname) - 8 - 4, 8) == "_stomach") // - 4 is the extension + if(reset_anims) player_setupanimsformodel(); } @@ -430,16 +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 >= 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(self.stomach_load) + applymodel = strcat(newmodel_name, "_state", ftos(floor(self.stomach_load)), newmodel_extension); else applymodel = self.playermodel; @@ -462,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); } @@ -474,6 +471,7 @@ void Client_uncustomizeentityforclient() float Client_customizeentityforclient() { entity modelsource; + string stomachmodel; if(self.modelindex == 0) return TRUE; @@ -513,28 +511,24 @@ 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) 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.predator.classname == "player" || self.fakeprey) self.alpha = default_player_alpha; return TRUE; } @@ -565,6 +559,8 @@ void PutObserverInServer (void) WriteEntity(MSG_ONE, self); } + Vore_Disconnect(); + kh_Key_DropAll(self, TRUE); if(self.flagcarried) @@ -606,7 +602,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; @@ -726,7 +723,7 @@ void FixPlayermodel() { m1 = self.mins; m2 = self.maxs; - setmodel_apply (defaultmodel); + setmodel_apply (defaultmodel, TRUE); setsize (self, m1, m2); chmdl = TRUE; } @@ -739,7 +736,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; } @@ -829,15 +826,21 @@ void PutClientInServer (void) RemoveGrabber(self); // Wazat's Grabber + Vore_DeadPrey_Detach(self); + 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); @@ -871,13 +874,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; @@ -928,7 +933,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) { @@ -985,8 +990,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; @@ -1012,11 +1025,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; } @@ -1595,7 +1609,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.predator.classname != "player" && self.owner.fakepredator.classname != "player") #ifdef TETRIS || self.owner.tetris_on #endif @@ -1627,7 +1641,6 @@ void UpdateChatBubble() } } - void TeamBubbleThink() { self.nextthink = time; @@ -1639,11 +1652,16 @@ 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.predator.classname == "player" || self.owner.fakepredator.classname == "player") self.model = ""; else - self.model = self.mdl; - + { + 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"); + } }; float TeamBubble_customizeentityforclient() @@ -1667,8 +1685,8 @@ void UpdateTeamBubble() // setorigin(self.teambubbleentity, self.origin + '0 0 15' + self.maxs_z * '0 0 1'); setorigin(self.teambubbleentity, '0 0 15' + self.maxs_z * '0 0 1'); setattachment(self.teambubbleentity, self, ""); // sticks to moving player better, also conserves bandwidth - self.teambubbleentity.mdl = self.teambubbleentity.model; - self.teambubbleentity.model = self.teambubbleentity.mdl; +// self.teambubbleentity.mdl = self.teambubbleentity.model; +// self.teambubbleentity.model = self.teambubbleentity.mdl; self.teambubbleentity.customizeentityforclient = TeamBubble_customizeentityforclient; self.teambubbleentity.effects = EF_LOWPRECISION; } @@ -1844,7 +1862,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) { @@ -1860,6 +1879,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 + } } } @@ -1899,8 +1930,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) @@ -1908,7 +1939,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; @@ -1996,10 +2027,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; @@ -2019,6 +2053,8 @@ void SpectateCopy(entity spectatee) { 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; setorigin(self, spectatee.origin); setsize(self, spectatee.mins, spectatee.maxs); SetZoomState(spectatee.zoomstate); @@ -2210,6 +2246,37 @@ float vercmp(string v1, string v2) return vercmp_recursive(v1, v2); } +void ApplyHealthSize() +{ + if not(cvar("g_healthsize")) + return; + + if(self.predator.classname == "player" || self.fakeprey) + { + self.view_ofs = PL_CROUCH_VIEW_OFS * self.predator.scale; + self.scale = 0; + } + else + { + self.scale = cvar("g_healthsize") / self.health; + + // 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); + self.view_ofs = PL_CROUCH_VIEW_OFS * self.scale; + } + else + { + //setsize (self, PL_MIN * self.scale, PL_MAX * self.scale); + self.view_ofs = PL_VIEW_OFS * self.scale; + } + } +} + void ObserverThink() { if (self.flags & FL_JUMPRELEASED) { @@ -2322,9 +2389,6 @@ void PlayerPreThink (void) // core code for the vore system Vore(); - if(self.spectatee_status) - Vore_Disconnect(); - // version nagging if(self.version_nagtime) if(self.cvar_g_voretournamentversion) @@ -2420,7 +2484,7 @@ void PlayerPreThink (void) { if(frametime) player_anim(); - button_pressed = (self.BUTTON_ATCK || self.BUTTON_JUMP || self.BUTTON_ATCK2 || self.BUTTON_GRABBER || self.BUTTON_USE); + button_pressed = (self.BUTTON_ATCK || self.BUTTON_JUMP || self.BUTTON_ATCK2 || self.BUTTON_JETPACK || self.BUTTON_USE); force_respawn = (g_lms || (g_ca) || cvar("g_forced_respawn")); if (self.deadflag == DEAD_DYING) { @@ -2535,6 +2599,9 @@ void PlayerPreThink (void) } } + // health based player size + ApplyHealthSize(); + FixPlayermodel(); GrabberFrame(); @@ -2610,11 +2677,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 +2714,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; }