X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fcl_client.qc;h=0b583279d6d6dbc5a92bc5e4c4629ac53a5a4904;hb=19a4a52c42e00347a51b62ff1e5adcadecda31e0;hp=2386c3ca9b407a04ac21c6e7c7c6448d8b726b39;hpb=1a2fb5bb1187437cb98c4e4803c97774647369fd;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc index 2386c3ca9..7c3308041 100644 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@ -123,7 +123,7 @@ void spawnpoint_use() // Returns: // _x: prio (-1 if unusable) // _y: weight -vector Spawn_Score(entity spot, entity playerlist, float teamcheck, float anypoint) +vector Spawn_Score(entity spot, float mindist, float teamcheck) { float shortest, thisdist; float prio; @@ -151,55 +151,37 @@ vector Spawn_Score(entity spot, entity playerlist, float teamcheck, float anypoi return '-1 0 0'; } + shortest = vlen(world.maxs - world.mins); + FOR_EACH_PLAYER(player) if (player != self) + { + thisdist = vlen(player.origin - spot.origin); + if (thisdist < shortest) + shortest = thisdist; + } + if(shortest > mindist) + prio += SPAWN_PRIO_GOOD_DISTANCE; + + spawn_score = prio * '1 0 0' + shortest * '0 1 0'; + spawn_spot = spot; + // filter out spots for assault if(spot.target != "") { entity ent; - float good, found; + float found; found = 0; - good = 0; for(ent = world; (ent = find(ent, targetname, spot.target)); ) { ++found; - if(ent.classname == "target_objective") - { - if(ent.health < 0 || ent.health >= ASSAULT_VALUE_INACTIVE) - continue; - } - else if(ent.classname == "trigger_race_checkpoint") + if(ent.spawn_evalfunc) { - if(!anypoint) // spectators may spawn everywhere - { - if(g_race_qualifying) - { - // spawn at first - if(ent.race_checkpoint != 0) - continue; - if(spot.race_place != race_lowest_place_spawn) - continue; - } - else - { - if(ent.race_checkpoint != self.race_respawn_checkpoint) - continue; - // try reusing the previous spawn - if(ent == self.race_respawn_spotref || spot == self.race_respawn_spotref) - prio += 1; - if(ent.race_checkpoint == 0) - { - float pl; - pl = self.race_place; - if(pl > race_highest_place_spawn) - pl = 0; - if(pl == 0 && !self.race_started) - pl = race_highest_place_spawn; // use last place if he has not even touched finish yet - if(spot.race_place != pl) - continue; - } - } - } + entity oldself = self; + self = ent; + spawn_score = ent.spawn_evalfunc(oldself, spot, spawn_score); + self = oldself; + if(spawn_score_x < 0) + return spawn_score; } - ++good; } if(!found) @@ -207,95 +189,42 @@ vector Spawn_Score(entity spot, entity playerlist, float teamcheck, float anypoi dprint("WARNING: spawnpoint at ", vtos(spot.origin), " could not find its target ", spot.target, "\n"); return '-1 0 0'; } - - if(good < found) // at least one was bad - return '-1 0 0'; } - player = playerlist; - shortest = vlen(world.maxs - world.mins); - for(player = playerlist; player; player = player.chain) - if (player != self) - { - thisdist = vlen(player.origin - spot.origin); - if (thisdist < shortest) - shortest = thisdist; - } - return prio * '1 0 0' + shortest * '0 1 0'; + MUTATOR_CALLHOOK(Spawn_Score); + return spawn_score; +} + +void Spawn_ScoreAll(entity firstspot, float mindist, float teamcheck) +{ + entity spot; + for(spot = firstspot; spot; spot = spot.chain) + spot.spawnpoint_score = Spawn_Score(spot, mindist, teamcheck); } -float spawn_allbad; -float spawn_allgood; -entity Spawn_FilterOutBadSpots(entity firstspot, entity playerlist, float mindist, float teamcheck, float anypoint) +entity Spawn_FilterOutBadSpots(entity firstspot, float mindist, float teamcheck) { entity spot, spotlist, spotlistend; - spawn_allgood = TRUE; - spawn_allbad = TRUE; spotlist = world; spotlistend = world; + Spawn_ScoreAll(firstspot, mindist, teamcheck); + for(spot = firstspot; spot; spot = spot.chain) { - spot.spawnpoint_score = Spawn_Score(spot, playerlist, teamcheck, anypoint); - - if(autocvar_spawn_debugview) - { - setmodel(spot, "models/runematch/rune.mdl"); - if(spot.spawnpoint_score_y < mindist) - { - spot.colormod = '1 0 0'; - spot.scale = 1; - } - else - { - spot.colormod = '0 1 0'; - spot.scale = spot.spawnpoint_score_y / mindist; - } - } - if(spot.spawnpoint_score_x >= 0) // spawning allowed here { - if(spot.spawnpoint_score_y < mindist) - { - // too short distance - spawn_allgood = FALSE; - } - else - { - // perfect - spawn_allbad = FALSE; - - if(spotlistend) - spotlistend.chain = spot; - spotlistend = spot; - if(!spotlist) - spotlist = spot; - - /* - if(teamcheck >= 0) - if(spot.team != teamcheck) - error("invalid spawn added"); - - print("added ", etos(spot), "\n"); - */ - } + if(spotlistend) + spotlistend.chain = spot; + spotlistend = spot; + if(!spotlist) + spotlist = spot; } } if(spotlistend) spotlistend.chain = world; - /* - entity e; - if(teamcheck >= 0) - for(e = spotlist; e; e = e.chain) - { - print("seen ", etos(e), "\n"); - if(e.team != teamcheck) - error("invalid spawn found"); - } - */ - return spotlist; } @@ -322,8 +251,7 @@ Finds a point to respawn entity SelectSpawnPoint (float anypoint) { float teamcheck; - entity firstspot_new; - entity spot, firstspot, playerlist; + entity spot, firstspot; spot = find (world, classname, "testplayerstart"); if (spot) @@ -354,8 +282,6 @@ entity SelectSpawnPoint (float anypoint) // if we get here, we either require team spawns but have none, or we require non-team spawns and have none; use any spawn then - // get the list of players - playerlist = findchain(classname, "player"); // get the entire list of spots firstspot = findchain(classname, "info_player_deathmatch"); // filter out the bad ones @@ -366,42 +292,26 @@ entity SelectSpawnPoint (float anypoint) } else { - firstspot_new = Spawn_FilterOutBadSpots(firstspot, playerlist, 100, teamcheck, anypoint); - if(!firstspot_new) - firstspot_new = Spawn_FilterOutBadSpots(firstspot, playerlist, -1, teamcheck, anypoint); - firstspot = firstspot_new; + float mindist; + if (arena_roundbased && !g_ca) + mindist = 800; + else + mindist = 100; + firstspot = Spawn_FilterOutBadSpots(firstspot, mindist, teamcheck); // there is 50/50 chance of choosing a random spot or the furthest spot // (this means that roughly every other spawn will be furthest, so you // usually won't get fragged at spawn twice in a row) - if (arena_roundbased && !g_ca) - { - firstspot_new = Spawn_FilterOutBadSpots(firstspot, playerlist, 800, teamcheck, anypoint); - if(firstspot_new) - firstspot = firstspot_new; - spot = Spawn_WeightedPoint(firstspot, 1, 1, 1); - } - else if (random() > autocvar_g_spawn_furthest) + if (random() > autocvar_g_spawn_furthest) spot = Spawn_WeightedPoint(firstspot, 1, 1, 1); else spot = Spawn_WeightedPoint(firstspot, 1, 5000, 5); // chooses a far far away spawnpoint } - if(autocvar_spawn_debugview) - { - print("spot mindistance: ", vtos(spot.spawnpoint_score), "\n"); - - entity e; - if(teamcheck >= 0) - for(e = firstspot; e; e = e.chain) - if(e.team != teamcheck) - error("invalid spawn found"); - } - if (!spot) { if(autocvar_spawn_debug) - GotoNextMap(); + GotoNextMap(0); else { if(some_spawn_has_been_used) @@ -431,25 +341,26 @@ string CheckPlayerModel(string plyermodel) { // to change a cvar default, we'll have a small leak here. FallbackPlayerModel = strzone(cvar_defstring("_cl_playermodel")); } - if(strlen(plyermodel) < 4) - return FallbackPlayerModel; + // only in right path if( substring(plyermodel,0,14) != "models/player/") return FallbackPlayerModel; - else if(autocvar_sv_servermodelsonly) + // only good file extensions + 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; + // forbid the LOD models + if(substring(plyermodel, -9,5) == "_lod1") + return FallbackPlayerModel; + if(substring(plyermodel, -9,5) == "_lod2") + return FallbackPlayerModel; + if(plyermodel != strtolower(plyermodel)) + return FallbackPlayerModel; + // also, restrict to server models + if(autocvar_sv_servermodelsonly) { - 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; - // forbid the LOD models - if(substring(plyermodel, -9,5) == "_lod1") - return FallbackPlayerModel; - if(substring(plyermodel, -9,5) == "_lod2") - return FallbackPlayerModel; - if(plyermodel != strtolower(plyermodel)) - return FallbackPlayerModel; if(!fexists(plyermodel)) return FallbackPlayerModel; } @@ -493,8 +404,7 @@ void PutObserverInServer (void) DropAllRunes(self); MUTATOR_CALLHOOK(MakePlayerObserver); - if (g_minstagib) - minstagib_stop_countdown(); + minstagib_stop_countdown(self); Portal_ClearAll(self); @@ -505,14 +415,11 @@ void PutObserverInServer (void) } if(self.vehicle) - vehicles_exit(VHEF_RELESE); + vehicles_exit(VHEF_RELESE); if(self.flagcarried) DropFlag(self.flagcarried, world, world); - if(self.ballcarried && g_nexball) - DropBall(self.ballcarried, self.origin + self.ballcarried.origin, self.velocity); - WaypointSprite_PlayerDead(); if not(g_ca) // don't reset teams when moving a ca player to the spectators @@ -545,7 +452,7 @@ void PutObserverInServer (void) self.health = -666; self.takedamage = DAMAGE_NO; self.solid = SOLID_NOT; - self.movetype = MOVETYPE_FLY_WORLDONLY; //(self.cvar_cl_clippedspectating ? MOVETYPE_NOCLIP : MOVETYPE_FLY); // it's too early for this anyway, lets just set it in playerprethink + self.movetype = MOVETYPE_FLY_WORLDONLY; // user preference is controlled by playerprethink self.flags = FL_CLIENT | FL_NOTARGET; self.armorvalue = 666; self.effects = 0; @@ -555,7 +462,7 @@ void PutObserverInServer (void) self.pauseregen_finished = 0; self.damageforcescale = 0; self.death_time = 0; - self.dead_frame = 0; + self.respawn_time = 0; self.alpha = 0; self.scale = 0; self.fade_time = 0; @@ -563,7 +470,9 @@ void PutObserverInServer (void) self.pain_finished = 0; self.strength_finished = 0; self.invincible_finished = 0; + self.superweapons_finished = 0; self.pushltime = 0; + self.istypefrag = 0; self.think = SUB_Null; self.nextthink = 0; self.hook_time = 0; @@ -574,10 +483,10 @@ void PutObserverInServer (void) self.fixangle = TRUE; self.crouch = FALSE; - setorigin (self, spot.origin); + setorigin (self, (spot.origin + PL_VIEW_OFS)); // offset it so that the spectator spawns higher off the ground, looks better this way self.prevorigin = self.origin; self.items = 0; - self.weapons = 0; + WEPSET_CLEAR_E(self); self.model = ""; FixPlayermodel(); setmodel(self, "null"); @@ -639,11 +548,11 @@ void FixPlayermodel() vector m1, m2; defaultmodel = ""; + defaultskin = 0; + chmdl = FALSE; if(autocvar_sv_defaultcharacter == 1) { - defaultskin = 0; - if(teamplay) { string s; @@ -673,13 +582,6 @@ void FixPlayermodel() } } - if(self.modelindex == 0 && self.deadflag == DEAD_NO) - { - if(self.model != "") - bprint("\{1}^1Player ", self.netname, "^1 has a zero modelindex, trying to fix...\n"); - self.model = ""; // force the != checks to return true - } - if(defaultmodel != "") { if (defaultmodel != self.model) @@ -740,11 +642,14 @@ Called when a client spawns in the server ============= */ //void() ctf_playerchanged; + void PutClientInServer (void) { if(clienttype(self) == CLIENTTYPE_BOT) { self.classname = "player"; + if(g_ca) + self.caplayer = 1; } else if(clienttype(self) == CLIENTTYPE_REAL) { @@ -752,7 +657,7 @@ void PutClientInServer (void) WriteByte(MSG_ONE, SVC_SETVIEW); WriteEntity(MSG_ONE, self); } - + // reset player keys self.itemkeys = 0; @@ -764,8 +669,7 @@ void PutClientInServer (void) self.classname = "observer"; } - if(g_arena || (g_ca && !allowed_to_spawn)) - if(!self.spawned) + if((g_arena && !self.spawned) || (g_ca && !allowed_to_spawn)) self.classname = "observer"; if(gameover) @@ -832,7 +736,7 @@ void PutClientInServer (void) self.ammo_fuel = warmup_start_ammo_fuel; self.health = warmup_start_health; self.armorvalue = warmup_start_armorvalue; - self.weapons = warmup_start_weapons; + WEPSET_COPY_EA(self, warmup_start_weapons); } else { @@ -843,20 +747,24 @@ void PutClientInServer (void) self.ammo_fuel = start_ammo_fuel; self.health = start_health; self.armorvalue = start_armorvalue; - self.weapons = start_weapons; + WEPSET_COPY_EA(self, start_weapons); } + if(WEPSET_CONTAINS_ANY_EA(self, WEPBIT_SUPERWEAPONS)) // exception for minstagib, as minstanex is a superweapon + self.superweapons_finished = time + autocvar_g_balance_superweapons_time; + else + self.superweapons_finished = 0; + if(g_weaponarena_random) { if(g_weaponarena_random_with_laser) - self.weapons &~= WEPBIT_LASER; - self.weapons = randombits(self.weapons, g_weaponarena_random, FALSE); + WEPSET_ANDNOT_EW(self, WEP_LASER); + W_RandomWeapons(self, g_weaponarena_random); if(g_weaponarena_random_with_laser) - self.weapons |= WEPBIT_LASER; + WEPSET_OR_EW(self, WEP_LASER); } self.items = start_items; - self.jump_interval = time; self.spawnshieldtime = time + autocvar_g_spawnshieldtime; self.pauserotarmor_finished = time + autocvar_g_balance_pause_armor_rot_spawn; @@ -872,8 +780,7 @@ void PutClientInServer (void) } self.damageforcescale = 2; self.death_time = 0; - self.dead_frame = 0; - self.alpha = 0; + self.respawn_time = 0; self.scale = 0; self.fade_time = 0; self.pain_frame = 0; @@ -926,13 +833,12 @@ void PutClientInServer (void) self.lastrocket = world; // stop rocket guiding, no revenge from the grave! self.lastteleporttime = time; // prevent insane speeds due to changing origin self.hud = HUD_NORMAL; - + if(g_arena) { Spawnqueue_Remove(self); Spawnqueue_Mark(self); } - else if(g_ca) self.caplayer = 1; @@ -959,18 +865,9 @@ void PutClientInServer (void) race_PostSpawn(spot); - if(autocvar_spawn_debug) - { - sprint(self, strcat("spawnpoint origin: ", vtos(spot.origin), "\n")); - remove(spot); // usefull for checking if there are spawnpoints, that let drop through the floor - } - //stuffcmd(self, "chase_active 0"); //stuffcmd(self, "set viewsize $tmpviewsize \n"); - if (autocvar_g_spawnsound) - sound (self, CH_TRIGGER, "misc/spawn.wav", VOL_BASE, ATTN_NORM); - if(g_assault) { if(self.team == assault_attacker_team) centerprint(self, "You are attacking!"); @@ -1003,8 +900,15 @@ void PutClientInServer (void) activator = world; self = oldself; + spawn_spot = spot; MUTATOR_CALLHOOK(PlayerSpawn); + if(autocvar_spawn_debug) + { + sprint(self, strcat("spawnpoint origin: ", vtos(spot.origin), "\n")); + remove(spot); // usefull for checking if there are spawnpoints, that let drop through the floor + } + self.switchweapon = w_getbestweapon(self); self.cnt = -1; // W_LastWeapon will not complain self.weapon = 0; @@ -1013,7 +917,12 @@ void PutClientInServer (void) if(!self.alivetime) self.alivetime = time; - } else if(self.classname == "observer" || (g_ca && !allowed_to_spawn)) { + + antilag_clear(self); + + if (autocvar_g_spawnsound) + soundat(world, self.origin, CH_TRIGGER, "misc/spawn.wav", VOL_BASE, ATTN_NORM); + } else if(self.classname == "observer") { PutObserverInServer (); } @@ -1056,6 +965,7 @@ float ClientInit_SendEntity(entity to, float sf) WriteByte(MSG_ENTITY, autocvar_g_balance_minelayer_limit); // minelayer max mines WriteByte(MSG_ENTITY, autocvar_g_balance_hagar_secondary_load_max); // hagar max loadable rockets WriteCoord(MSG_ENTITY, autocvar_g_trueaim_minrange); + WriteByte(MSG_ENTITY, autocvar_g_balance_porto_secondary); return TRUE; } @@ -1160,8 +1070,7 @@ void ClientKill_Now_TeamChange() { if(self.killindicator_teamchange == -1) { - self.team = -1; - JoinBestTeam( self, FALSE, FALSE ); + JoinBestTeam( self, FALSE, TRUE ); } else if(self.killindicator_teamchange == -2) { @@ -1209,7 +1118,7 @@ void KillIndicator_Think() return; } - if (!self.owner.modelindex) + if (self.owner.alpha < 0 && !self.owner.vehicle) { self.owner.killindicator = world; remove(self); @@ -1269,7 +1178,7 @@ void ClientKill_TeamChange (float targetteam) // 0 = don't change, -1 = auto, -2 if(!self.killindicator) { - if(self.modelindex && self.deadflag == DEAD_NO) + if(self.deadflag == DEAD_NO) { killtime = max(killtime, self.clientkill_nexttime - time); self.clientkill_nexttime = time + killtime + autocvar_g_balance_kill_antispam; @@ -1424,10 +1333,6 @@ float PlayerInIDList(entity p, string idlist) return 0; } -#ifndef NO_LEGACY_NETWORKING -.float iscsqcmodel; -#endif - /* ============= ClientConnect @@ -1450,7 +1355,7 @@ void ClientConnect (void) return; } - if(Ban_MaybeEnforceBan(self)) + if(Ban_MaybeEnforceBanOnce(self)) return; DecodeLevelParms(); @@ -1534,7 +1439,7 @@ void ClientConnect (void) } else { if(teamplay) { - if(autocvar_g_balance_teams || autocvar_g_balance_teams_force) + if(autocvar_g_balance_teams) { self.classname = "player"; campaign_bots_may_start = 1; @@ -1601,8 +1506,6 @@ void ClientConnect (void) else stuffcmd(self, "set _teams_available 0\n"); - stuffcmd(self, strcat("set gametype ", ftos(game), "\n")); - if(g_arena || g_ca) { self.classname = "observer"; @@ -1625,11 +1528,11 @@ void ClientConnect (void) } self.jointime = time; - self.allowedTimeouts = autocvar_sv_timeout_number; + self.allowed_timeouts = autocvar_sv_timeout_number; if(clienttype(self) == CLIENTTYPE_REAL) { - if(autocvar_g_bugrigs || g_weaponarena == WEPBIT_TUBA) + if(autocvar_g_bugrigs || WEPSET_EQ_AW(g_weaponarena_weapons, WEP_TUBA)) stuffcmd(self, "cl_cmd settemp chase_active 1\n"); } @@ -1661,7 +1564,6 @@ void ClientConnect (void) rr = CTS_RECORD; else rr = RACE_RECORD; - t = stof(db_get(ServerProgsDB, strcat(GetMapname(), rr, "time"))); msg_entity = self; race_send_recordtime(MSG_ONE); @@ -1687,19 +1589,15 @@ void ClientConnect (void) if(!autocvar_g_campaign) Send_CSQC_Centerprint_Generic(self, CPID_MOTD, getwelcomemessage(), autocvar_welcome_message_time, 0); -#ifndef NO_LEGACY_NETWORKING - if(autocvar_sv_use_csqc_players) - { - CSQCModel_LinkEntity(); - self.iscsqcmodel = 1; - } -#else - CSQCModel_LinkEntity(); -#endif + CSQCMODEL_AUTOINIT(); self.model_randomizer = random(); + + if(clienttype(self) != CLIENTTYPE_REAL) + return; + + sv_notice_join(); } - /* ============= ClientDisconnect @@ -1755,8 +1653,6 @@ void ClientDisconnect (void) RemoveGrapplingHook(self); if(self.flagcarried) DropFlag(self.flagcarried, world, world); - if(self.ballcarried && g_nexball) - DropBall(self.ballcarried, self.origin + self.ballcarried.origin, self.velocity); // Here, everything has been done that requires this player to be a client. @@ -1805,7 +1701,7 @@ void ClientDisconnect (void) void ChatBubbleThink() { self.nextthink = time; - if (!self.owner.modelindex || self.owner.chatbubbleentity != self) + if ((self.owner.alpha < 0) || self.owner.chatbubbleentity != self) { if(self.owner) // but why can that ever be world? self.owner.chatbubbleentity = world; @@ -1824,7 +1720,7 @@ void ChatBubbleThink() void UpdateChatBubble() { - if (!self.modelindex) + if (self.alpha < 0) return; // spawn a chatbubble entity if needed if (!self.chatbubbleentity) @@ -1861,31 +1757,24 @@ void UpdateChatBubble() else self.colormod = '1 1 1'; }*/ -.float oldcolormap; void respawn(void) { - if(self.modelindex != 0 && autocvar_g_respawn_ghosts) + if(self.alpha >= 0 && autocvar_g_respawn_ghosts) { self.solid = SOLID_NOT; self.takedamage = DAMAGE_NO; self.movetype = MOVETYPE_FLY; self.velocity = '0 0 1' * autocvar_g_respawn_ghosts_speed; self.avelocity = randomvec() * autocvar_g_respawn_ghosts_speed * 3 - randomvec() * autocvar_g_respawn_ghosts_speed * 3; - self.effects |= EF_ADDITIVE; - self.oldcolormap = self.colormap; - self.colormap = 0; // this originally was 512, but raises a warning in the engine, so get rid of it + self.effects |= CSQCMODEL_EF_RESPAWNGHOST; pointparticles(particleeffectnum("respawn_ghost"), self.origin, '0 0 0', 1); if(autocvar_g_respawn_ghosts_maxtime) SUB_SetFade (self, time + autocvar_g_respawn_ghosts_maxtime / 2 + random () * (autocvar_g_respawn_ghosts_maxtime - autocvar_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(); } @@ -1913,9 +1802,9 @@ void player_powerups (void) self.modelflags &~= MF_ROCKET; } - self.effects &~= (EF_DIMLIGHT | EF_RED | EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT | EF_FLAME | EF_NODEPTHTEST); + self.effects &~= (EF_RED | EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT | EF_FLAME | EF_NODEPTHTEST); - if(!self.modelindex || self.deadflag) // don't apply the flags if the player is gibbed + if(self.alpha < 0 || self.deadflag) // don't apply the flags if the player is gibbed return; Fire_ApplyDamage(self); @@ -1950,7 +1839,7 @@ void player_powerups (void) if (self.items & IT_INVINCIBLE) { play_countdown(self.invincible_finished, "misc/poweroff.wav"); - if (time > self.invincible_finished && autocvar_g_balance_powerup_timer) + if (time > self.invincible_finished) { self.items = self.items - (self.items & IT_INVINCIBLE); sprint(self, "^3Speed has worn off\n"); @@ -1971,7 +1860,7 @@ void player_powerups (void) { play_countdown(self.strength_finished, "misc/poweroff.wav"); self.effects = self.effects | (EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT); - if (time > self.strength_finished && autocvar_g_balance_powerup_timer) + if (time > self.strength_finished) { self.items = self.items - (self.items & IT_STRENGTH); sprint(self, "^3Strength has worn off\n"); @@ -1989,7 +1878,7 @@ void player_powerups (void) { play_countdown(self.invincible_finished, "misc/poweroff.wav"); self.effects = self.effects | (EF_RED | EF_ADDITIVE | EF_FULLBRIGHT); - if (time > self.invincible_finished && autocvar_g_balance_powerup_timer) + if (time > self.invincible_finished) { self.items = self.items - (self.items & IT_INVINCIBLE); sprint(self, "^3Shield has worn off\n"); @@ -2003,26 +1892,66 @@ void player_powerups (void) sprint(self, "^3Shield surrounds you\n"); } } + if (self.items & IT_SUPERWEAPON) + { + if (!WEPSET_CONTAINS_ANY_EA(self, WEPBIT_SUPERWEAPONS)) + { + self.superweapons_finished = 0; + self.items = self.items - (self.items & IT_SUPERWEAPON); + sprint(self, "^3Superweapons have been lost\n"); + } + else if (self.items & IT_UNLIMITED_SUPERWEAPONS) + { + // don't let them run out + } + else + { + play_countdown(self.superweapons_finished, "misc/poweroff.wav"); + if (time > self.superweapons_finished) + { + self.items = self.items - (self.items & IT_SUPERWEAPON); + WEPSET_ANDNOT_EA(self, WEPBIT_SUPERWEAPONS); + sprint(self, "^3Superweapons have broken down\n"); + } + } + } + else if(WEPSET_CONTAINS_ANY_EA(self, WEPBIT_SUPERWEAPONS)) + { + if (time < self.superweapons_finished || (self.items & IT_UNLIMITED_SUPERWEAPONS)) + { + self.items = self.items | IT_SUPERWEAPON; + sprint(self, "^3You now have a superweapon\n"); + } + else + { + self.superweapons_finished = 0; + WEPSET_ANDNOT_EA(self, WEPBIT_SUPERWEAPONS); + } + } + else + { + self.superweapons_finished = 0; + } + } + + if(autocvar_g_nodepthtestplayers) + self.effects = self.effects | EF_NODEPTHTEST; - if(autocvar_g_nodepthtestplayers) - self.effects = self.effects | EF_NODEPTHTEST; - - if(autocvar_g_fullbrightplayers) - self.effects = self.effects | EF_FULLBRIGHT; + if(autocvar_g_fullbrightplayers) + self.effects = self.effects | EF_FULLBRIGHT; - // midair gamemode: damage only while in the air - // if in midair mode, being on ground grants temporary invulnerability - // (this is so that multishot weapon don't clear the ground flag on the - // first damage in the frame, leaving the player vulnerable to the - // remaining hits in the same frame) - if (self.flags & FL_ONGROUND) - if (g_midair) - self.spawnshieldtime = max(self.spawnshieldtime, time + autocvar_g_midair_shieldtime); + // midair gamemode: damage only while in the air + // if in midair mode, being on ground grants temporary invulnerability + // (this is so that multishot weapon don't clear the ground flag on the + // first damage in the frame, leaving the player vulnerable to the + // remaining hits in the same frame) + if (self.flags & FL_ONGROUND) + if (g_midair) + self.spawnshieldtime = max(self.spawnshieldtime, time + autocvar_g_midair_shieldtime); - if (time >= game_starttime) - if (time < self.spawnshieldtime) - self.effects = self.effects | (EF_ADDITIVE | EF_FULLBRIGHT); - } + if (time >= game_starttime) + if (time < self.spawnshieldtime) + self.effects = self.effects | (EF_ADDITIVE | EF_FULLBRIGHT); MUTATOR_CALLHOOK(PlayerPowerups); } @@ -2193,6 +2122,15 @@ void GetPressedKeys(void) { self.pressedkeys |= KEY_CROUCH; else self.pressedkeys &~= KEY_CROUCH; + + if (self.BUTTON_ATCK) + self.pressedkeys |= KEY_ATCK; + else + self.pressedkeys &~= KEY_ATCK; + if (self.BUTTON_ATCK2) + self.pressedkeys |= KEY_ATCK2; + else + self.pressedkeys &~= KEY_ATCK2; } /* @@ -2223,7 +2161,7 @@ void SpectateCopy(entity spectatee) { self.strength_finished = spectatee.strength_finished; self.invincible_finished = spectatee.invincible_finished; self.pressedkeys = spectatee.pressedkeys; - self.weapons = spectatee.weapons; + WEPSET_COPY_EE(self, spectatee); self.switchweapon = spectatee.switchweapon; self.switchingweapon = spectatee.switchingweapon; self.weapon = spectatee.weapon; @@ -2233,29 +2171,24 @@ void SpectateCopy(entity spectatee) { self.minelayer_mines = spectatee.minelayer_mines; self.punchangle = spectatee.punchangle; self.view_ofs = spectatee.view_ofs; - self.v_angle = spectatee.v_angle; self.velocity = spectatee.velocity; self.dmg_take = spectatee.dmg_take; self.dmg_save = spectatee.dmg_save; self.dmg_inflictor = spectatee.dmg_inflictor; + self.v_angle = spectatee.v_angle; self.angles = spectatee.v_angle; if(!self.BUTTON_USE) self.fixangle = TRUE; setorigin(self, spectatee.origin); setsize(self, spectatee.mins, spectatee.maxs); SetZoomState(spectatee.zoomstate); - - anticheat_spectatecopy(spectatee); - - //self.vehicle = spectatee.vehicle; - + + anticheat_spectatecopy(spectatee); self.hud = spectatee.hud; if(spectatee.vehicle) { - setorigin(self, spectatee.origin); - self.velocity = spectatee.vehicle.velocity; - self.v_angle += spectatee.vehicle.angles; - //self.v_angle_x *= -1; + self.fixangle = FALSE; + //self.velocity = spectatee.vehicle.velocity; self.vehicle_health = spectatee.vehicle_health; self.vehicle_shield = spectatee.vehicle_shield; self.vehicle_energy = spectatee.vehicle_energy; @@ -2263,11 +2196,18 @@ void SpectateCopy(entity spectatee) { self.vehicle_ammo2 = spectatee.vehicle_ammo2; self.vehicle_reload1 = spectatee.vehicle_reload1; self.vehicle_reload2 = spectatee.vehicle_reload2; - + msg_entity = self; - WriteByte (MSG_ONE, SVC_SETVIEWPORT); - WriteEntity(MSG_ONE, spectatee); - //self.tur_head = spectatee.vehicle.vehicle_viewport; + + WriteByte (MSG_ONE, SVC_SETVIEWANGLES); + WriteAngle(MSG_ONE, spectatee.v_angle_x); + WriteAngle(MSG_ONE, spectatee.v_angle_y); + WriteAngle(MSG_ONE, spectatee.v_angle_z); + + //WriteByte (MSG_ONE, SVC_SETVIEW); + // WriteEntity(MSG_ONE, self); + //makevectors(spectatee.v_angle); + //setorigin(self, spectatee.origin - v_forward * 400 + v_up * 300);*/ } } @@ -2310,8 +2250,13 @@ entity CA_SpectateNext(entity start) { return other; } -float SpectateNext() { - other = find(self.enemy, classname, "player"); +float SpectateNext(entity _prefer) { + + if(_prefer) + other = _prefer; + else + other = find(self.enemy, classname, "player"); + if (g_ca && !autocvar_g_ca_spectate_enemies && self.caplayer) { // CA and ca players when spectating enemies is forbidden other = CA_SpectateNext(other); @@ -2325,17 +2270,19 @@ float SpectateNext() { self.enemy = other; if(self.enemy.classname == "player") { - if(self.enemy.vehicle) + /*if(self.enemy.vehicle) { + msg_entity = self; - WriteByte(MSG_ONE, SVC_SETVIEWPORT); + WriteByte(MSG_ONE, SVC_SETVIEW); WriteEntity(MSG_ONE, self.enemy); //stuffcmd(self, "set viewsize $tmpviewsize \n"); + self.movetype = MOVETYPE_NONE; accuracy_resend(self); } else - { + {*/ msg_entity = self; WriteByte(MSG_ONE, SVC_SETVIEW); WriteEntity(MSG_ONE, self.enemy); @@ -2345,7 +2292,7 @@ float SpectateNext() { if(!SpectateUpdate()) PutObserverInServer(); - } + //} return 1; } else { return 0; @@ -2366,13 +2313,13 @@ void ShowRespawnCountdown() return; else { - number = ceil(self.death_time - time); + number = ceil(self.respawn_time - time); if(number <= 0) return; if(number <= self.respawn_countdown) { self.respawn_countdown = number - 1; - if(ceil(self.death_time - (time + 0.5)) == number) // only say it if it is the same number even in 0.5s; to prevent overlapping sounds + if(ceil(self.respawn_time - (time + 0.5)) == number) // only say it if it is the same number even in 0.5s; to prevent overlapping sounds AnnounceTo(self, strcat(ftos(number), "")); } } @@ -2381,11 +2328,11 @@ void ShowRespawnCountdown() .float prevent_join_msgtime; void LeaveSpectatorMode() { - if(nJoinAllowed(1)) { + if(nJoinAllowed(self)) { if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || (self.wasplayer && autocvar_g_changeteam_banned) || self.team_forced > 0) { self.classname = "player"; - if(autocvar_g_campaign || autocvar_g_balance_teams || autocvar_g_balance_teams_force) + if(autocvar_g_campaign || autocvar_g_balance_teams) JoinBestTeam(self, FALSE, TRUE); if(autocvar_g_campaign) @@ -2431,26 +2378,36 @@ void LeaveSpectatorMode() * it checks whether the number of currently playing players exceeds g_maxplayers. * @return int number of free slots for players, 0 if none */ -float nJoinAllowed(float includeMe) { +float nJoinAllowed(entity ignore) { + if(!ignore) + // this is called that way when checking if anyone may be able to join (to build qcstatus) + // so report 0 free slots if restricted + { + if(autocvar_g_forced_team_otherwise == "spectate") + return 0; + if(autocvar_g_forced_team_otherwise == "spectator") + return 0; + } + if(self.team_forced < 0) - return FALSE; // forced spectators can never join + return 0; // forced spectators can never join // TODO simplify this entity e; - - float totalClients; + float totalClients = 0; FOR_EACH_CLIENT(e) - totalClients += 1; + if(e != ignore) + totalClients += 1; if (!autocvar_g_maxplayers) - return maxclients - totalClients + includeMe; + return maxclients - totalClients; - float currentlyPlaying; + float currentlyPlaying = 0; FOR_EACH_REALPLAYER(e) currentlyPlaying += 1; if(currentlyPlaying < autocvar_g_maxplayers) - return min(maxclients - totalClients + includeMe, autocvar_g_maxplayers - currentlyPlaying); + return min(maxclients - totalClients, autocvar_g_maxplayers - currentlyPlaying); return 0; } @@ -2513,7 +2470,7 @@ void ObserverThink() self.flags |= FL_SPAWNING; } else if(self.BUTTON_ATCK && !self.version_mismatch) { self.flags &~= FL_JUMPRELEASED; - if(SpectateNext() == 1) { + if(SpectateNext(world) == 1) { self.classname = "spectator"; } } else { @@ -2544,7 +2501,7 @@ void SpectatorThink() self.flags |= FL_SPAWNING; } else if(self.BUTTON_ATCK) { self.flags &~= FL_JUMPRELEASED; - if(SpectateNext() == 1) { + if(SpectateNext(world) == 1) { self.classname = "spectator"; } else { self.classname = "observer"; @@ -2708,7 +2665,7 @@ void PlayerPreThink (void) } //don't allow the player to turn around while game is paused! - if(timeoutStatus == 2) { + if(timeout_status == TIMEOUT_ACTIVE) { // FIXME turn this into CSQC stuff self.v_angle = self.lastV_angle; self.angles = self.lastV_angle; @@ -2748,9 +2705,9 @@ void PlayerPreThink (void) float button_pressed, force_respawn; if(self.personal && g_race_qualifying) { - if(time > self.death_time) + if(time > self.respawn_time) { - self.death_time = time + 1; // only retry once a second + self.respawn_time = time + 1; // only retry once a second respawn(); self.impulse = 141; } @@ -2780,9 +2737,9 @@ void PlayerPreThink (void) } else if (self.deadflag == DEAD_RESPAWNING) { - if(time > self.death_time) + if(time > self.respawn_time) { - self.death_time = time + 1; // only retry once a second + self.respawn_time = time + 1; // only retry once a second respawn(); } } @@ -2842,6 +2799,7 @@ void PlayerPreThink (void) self.prevorigin = self.origin; + if (!self.vehicle) if (((self.BUTTON_CROUCH && !self.hook.state) || self.health <= g_bloodloss) && self.animstate_startframe != self.anim_melee_x) // prevent crouching if using melee attack { if (!self.crouch) @@ -3028,10 +2986,8 @@ void PlayerPostThink (void) stuffcmd(self, strcat("name ", self.netname, substring(ftos(random()), 2, -1), "\n")); } - if(sv_maxidle && frametime) + if(sv_maxidle && frametime) // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero). { - // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero). - float timeleft; if (time - self.parm_idlesince < 1) // instead of (time == self.parm_idlesince) to support sv_maxidle <= 10 { if(self.idlekick_lasttimeleft) @@ -3039,34 +2995,37 @@ void PlayerPostThink (void) Send_CSQC_Centerprint_Generic_Expire(self, CPID_DISCONNECT_IDLING); self.idlekick_lasttimeleft = 0; } - return; - } - timeleft = ceil(sv_maxidle - (time - self.parm_idlesince)); - if(timeleft == min(10, sv_maxidle - 1)) // - 1 to support sv_maxidle <= 10 - { - if(!self.idlekick_lasttimeleft) - Send_CSQC_Centerprint_Generic(self, CPID_DISCONNECT_IDLING, "^3Stop idling!\n^3Disconnecting in %d seconds...", 1, timeleft); - } - if(timeleft <= 0) - { - bprint("^3", self.netname, "^3 was kicked for idling.\n"); - AnnounceTo(self, "terminated"); - dropclient(self); - return; } - else if(timeleft <= 10) + else { - if(timeleft != self.idlekick_lasttimeleft) - AnnounceTo(self, ftos(timeleft)); - self.idlekick_lasttimeleft = timeleft; + float timeleft; + timeleft = ceil(sv_maxidle - (time - self.parm_idlesince)); + if(timeleft == min(10, sv_maxidle - 1)) // - 1 to support sv_maxidle <= 10 + { + if(!self.idlekick_lasttimeleft) + Send_CSQC_Centerprint_Generic(self, CPID_DISCONNECT_IDLING, "^3Stop idling!\n^3Disconnecting in %d seconds...", 1, timeleft); + } + if(timeleft <= 0) + { + bprint("^3", self.netname, "^3 was kicked for idling.\n"); + AnnounceTo(self, "terminated"); + dropclient(self); + return; + } + else if(timeleft <= 10) + { + if(timeleft != self.idlekick_lasttimeleft) + AnnounceTo(self, ftos(timeleft)); + self.idlekick_lasttimeleft = timeleft; + } } } #ifdef TETRIS if(self.impulse == 100) ImpulseCommands(); - if (TetrisPostFrame()) - return; + if (!TetrisPostFrame()) + { #endif CheatFrame(); @@ -3087,6 +3046,10 @@ void PlayerPostThink (void) //do nothing } +#ifdef TETRIS + } +#endif + /* float i; for(i = 0; i < 1000; ++i) @@ -3103,8 +3066,6 @@ void PlayerPostThink (void) } */ - Arena_Warmup(); - //pointparticles(particleeffectnum("machinegun_impact"), self.origin + self.view_ofs + '0 0 7', '0 0 0', 1); if(self.waypointsprite_attachedforcarrier) @@ -3150,22 +3111,5 @@ void PlayerPostThink (void) dprint(sprintf("%f %.6f\n", time, race_GetFractionalLapCount(self))); */ -#ifndef NO_LEGACY_NETWORKING - if(autocvar_sv_use_csqc_players && !self.iscsqcmodel) - { - CSQCModel_LinkEntity(); - self.iscsqcmodel = 1; - } - - if(!autocvar_sv_use_csqc_players && self.iscsqcmodel) - { - CSQCModel_UnlinkEntity(); - self.iscsqcmodel = 0; - } - - if(self.iscsqcmodel) - CSQCModel_CheckUpdate(); -#else - CSQCModel_CheckUpdate(); -#endif + CSQCMODEL_AUTOUPDATE(); }