X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fserver%2Fmutators%2Fmutator%2Fgamemode_ca.qc;h=fc06e50e29d73501a0e29d1c35d082325064fec3;hp=072fe90ddee9566093d39bd2de0577a8c7fdc3c1;hb=905ec2fbd2b610eeb2591cdddbf71ce24b7bb3ab;hpb=3cfb64730d883ae9ccf0315f365da19345270890 diff --git a/qcsrc/server/mutators/mutator/gamemode_ca.qc b/qcsrc/server/mutators/mutator/gamemode_ca.qc index 072fe90dd..fc06e50e2 100644 --- a/qcsrc/server/mutators/mutator/gamemode_ca.qc +++ b/qcsrc/server/mutators/mutator/gamemode_ca.qc @@ -1,72 +1,5 @@ #include "gamemode_ca.qh" -#ifndef GAMEMODE_CA_H -#define GAMEMODE_CA_H -int autocvar_g_ca_point_limit; -int autocvar_g_ca_point_leadlimit; -float autocvar_g_ca_round_timelimit; -bool autocvar_g_ca_team_spawns; -int autocvar_g_ca_teams; -int autocvar_g_ca_teams_override; -float autocvar_g_ca_warmup; - - -int ca_teams; -bool allowed_to_spawn; - -const int ST_CA_ROUNDS = 1; - -bool CA_CheckTeams(); -bool CA_CheckWinner(); -void CA_RoundStart(); -bool ca_isEliminated(entity e); - -void SetLimits(int fraglimit_override, int leadlimit_override, float timelimit_override, float qualifying_override); - -REGISTER_MUTATOR(ca, false) -{ - MUTATOR_ONADD - { - // game loads at time 1 - if (time > 1) error("This is a game type and it cannot be added at runtime."); - - allowed_to_spawn = true; - - ca_teams = autocvar_g_ca_teams_override; - if (ca_teams < 2) ca_teams = autocvar_g_ca_teams; - ca_teams = bound(2, ca_teams, 4); - ret_float = ca_teams; - - ScoreRules_basics(ca_teams, SFL_SORT_PRIO_PRIMARY, 0, true); - ScoreInfo_SetLabel_TeamScore(ST_CA_ROUNDS, "rounds", SFL_SORT_PRIO_PRIMARY); - ScoreRules_basics_end(); - - round_handler_Spawn(CA_CheckTeams, CA_CheckWinner, CA_RoundStart); - round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit); - - EliminatedPlayers_Init(ca_isEliminated); - - ActivateTeamplay(); - SetLimits(autocvar_g_ca_point_limit, autocvar_g_ca_point_leadlimit, autocvar_timelimit_override, -1); - - if (autocvar_g_ca_team_spawns) - have_team_spawns = -1; // request team spawns - } - - MUTATOR_ONREMOVE - { - LOG_INFO("This is a game type and it cannot be removed at runtime."); - return -1; - } - - return 0; -} - -// should be removed in the future, as other code should not have to care -.float caplayer; // 0.5 if scheduled to join the next round -#endif - -#ifdef IMPLEMENTATION float autocvar_g_ca_damage2score_multiplier; bool autocvar_g_ca_spectate_enemies; @@ -118,16 +51,18 @@ float CA_GetWinnerTeam() void nades_Clear(entity player); #define CA_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0)) -#define CA_ALIVE_TEAMS_OK() (CA_ALIVE_TEAMS() == ca_teams) +#define CA_ALIVE_TEAMS_OK() (CA_ALIVE_TEAMS() == NumTeams(ca_teams)) float CA_CheckWinner() { if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0) { - Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_OVER); - Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_OVER); + Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER); + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER); + FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(nades_Clear(it))); + allowed_to_spawn = false; + game_stopped = true; round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit); - FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(nades_Clear(it))); return 1; } @@ -138,17 +73,18 @@ float CA_CheckWinner() int winner_team = CA_GetWinnerTeam(); if(winner_team > 0) { - Send_Notification(NOTIF_ALL, world, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN)); - Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_WIN)); + Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN)); + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_WIN)); TeamScore_AddToTeam(winner_team, ST_CA_ROUNDS, +1); } else if(winner_team == -1) { - Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_TIED); - Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_TIED); + Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_TIED); + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_TIED); } allowed_to_spawn = false; + game_stopped = true; round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit); FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(nades_Clear(it))); @@ -169,23 +105,29 @@ bool CA_CheckTeams() if(CA_ALIVE_TEAMS_OK()) { if(prev_missing_teams_mask > 0) - Kill_Notification(NOTIF_ALL, world, MSG_CENTER, CPID_MISSING_TEAMS); + Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS); prev_missing_teams_mask = -1; return true; } if(total_players == 0) { if(prev_missing_teams_mask > 0) - Kill_Notification(NOTIF_ALL, world, MSG_CENTER, CPID_MISSING_TEAMS); + Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS); prev_missing_teams_mask = -1; return false; } - int missing_teams_mask = (!redalive) + (!bluealive) * 2; - if(ca_teams >= 3) missing_teams_mask += (!yellowalive) * 4; - if(ca_teams >= 4) missing_teams_mask += (!pinkalive) * 8; + int missing_teams_mask = 0; + if(ca_teams & BIT(0)) + missing_teams_mask += (!redalive) * 1; + if(ca_teams & BIT(1)) + missing_teams_mask += (!bluealive) * 2; + if(ca_teams & BIT(2)) + missing_teams_mask += (!yellowalive) * 4; + if(ca_teams & BIT(3)) + missing_teams_mask += (!pinkalive) * 8; if(prev_missing_teams_mask != missing_teams_mask) { - Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask); + Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask); prev_missing_teams_mask = missing_teams_mask; } return false; @@ -220,29 +162,42 @@ entity CA_SpectateNext(entity player, entity start) MUTATOR_HOOKFUNCTION(ca, PlayerSpawn) { - SELFPARAM(); - this.caplayer = 1; + entity player = M_ARGV(0, entity); + + player.caplayer = 1; if (!warmup_stage) eliminatedPlayers.SendFlags |= 1; } +MUTATOR_HOOKFUNCTION(ca, ForbidSpawn) +{ + entity player = M_ARGV(0, entity); + + // spectators / observers that weren't playing can join; they are + // immediately forced to observe in the PutClientInServer hook + // this way they are put in a team and can play in the next round + if (!allowed_to_spawn && player.caplayer) + return true; + return false; +} + MUTATOR_HOOKFUNCTION(ca, PutClientInServer) { - SELFPARAM(); - if (!allowed_to_spawn && IS_PLAYER(this)) // this is true even when player is trying to join + entity player = M_ARGV(0, entity); + + if (!allowed_to_spawn && IS_PLAYER(player)) // this is true even when player is trying to join { - TRANSMUTE(Observer, this); - if (this.jointime != time && !this.caplayer) // not when connecting + TRANSMUTE(Observer, player); + if (player.jointime != time && !player.caplayer) // not when connecting { - this.caplayer = 0.5; - Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_CA_JOIN_LATE); + player.caplayer = 0.5; + Send_Notification(NOTIF_ONE_ONLY, player, MSG_INFO, INFO_CA_JOIN_LATE); } } } MUTATOR_HOOKFUNCTION(ca, reset_map_players) { - SELFPARAM(); FOREACH_CLIENT(true, { it.killcount = 0; if (!it.caplayer && IS_BOT_CLIENT(it)) @@ -254,16 +209,18 @@ MUTATOR_HOOKFUNCTION(ca, reset_map_players) { TRANSMUTE(Player, it); it.caplayer = 1; - WITHSELF(it, PutClientInServer()); + PutClientInServer(it); } }); + bot_relinkplayerlist(); return true; } MUTATOR_HOOKFUNCTION(ca, ClientConnect) { - SELFPARAM(); - TRANSMUTE(Observer, this); + entity player = M_ARGV(0, entity); + + TRANSMUTE(Observer, player); return true; } @@ -273,15 +230,13 @@ MUTATOR_HOOKFUNCTION(ca, reset_map_global) return true; } -MUTATOR_HOOKFUNCTION(ca, GetTeamCount, CBC_ORDER_EXCLUSIVE) +MUTATOR_HOOKFUNCTION(ca, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE) { - ret_float = ca_teams; - return false; + M_ARGV(0, float) = ca_teams; } -entity ca_LastPlayerForTeam() +entity ca_LastPlayerForTeam(entity this) { - SELFPARAM(); entity last_pl = NULL; FOREACH_CLIENT(IS_PLAYER(it) && it != this, { if (!IS_DEAD(it)) @@ -294,12 +249,12 @@ entity ca_LastPlayerForTeam() return last_pl; } -void ca_LastPlayerForTeam_Notify() +void ca_LastPlayerForTeam_Notify(entity this) { if (round_handler_IsActive()) if (round_handler_IsRoundStarted()) { - entity pl = ca_LastPlayerForTeam(); + entity pl = ca_LastPlayerForTeam(this); if (pl) Send_Notification(NOTIF_ONE, pl, MSG_CENTER, CENTER_ALONE); } @@ -307,50 +262,53 @@ void ca_LastPlayerForTeam_Notify() MUTATOR_HOOKFUNCTION(ca, PlayerDies) { - ca_LastPlayerForTeam_Notify(); + entity frag_target = M_ARGV(2, entity); + + ca_LastPlayerForTeam_Notify(frag_target); if (!allowed_to_spawn) frag_target.respawn_flags = RESPAWN_SILENT; if (!warmup_stage) eliminatedPlayers.SendFlags |= 1; - return 1; + if(IS_BOT_CLIENT(frag_target)) + bot_clear(frag_target); + return true; } MUTATOR_HOOKFUNCTION(ca, ClientDisconnect) { - SELFPARAM(); - if (this.caplayer == 1) - ca_LastPlayerForTeam_Notify(); - return 1; -} + entity player = M_ARGV(0, entity); -MUTATOR_HOOKFUNCTION(ca, ForbidPlayerScore_Clear) -{ - return 1; + if (player.caplayer == 1) + ca_LastPlayerForTeam_Notify(player); + return true; } MUTATOR_HOOKFUNCTION(ca, MakePlayerObserver) { - SELFPARAM(); - if (!IS_DEAD(this)) - ca_LastPlayerForTeam_Notify(); - if (this.killindicator_teamchange == -2) - this.caplayer = 0; - if (this.caplayer) - this.frags = FRAGS_LMS_LOSER; + entity player = M_ARGV(0, entity); + + if (!IS_DEAD(player)) + ca_LastPlayerForTeam_Notify(player); + if (player.killindicator_teamchange == -2) // player wants to spectate + player.caplayer = 0; + if (player.caplayer) + player.frags = FRAGS_LMS_LOSER; if (!warmup_stage) eliminatedPlayers.SendFlags |= 1; + if (!player.caplayer) + return false; // allow team reset return true; // prevent team reset } MUTATOR_HOOKFUNCTION(ca, ForbidThrowCurrentWeapon) { - return 1; + return true; } MUTATOR_HOOKFUNCTION(ca, GiveFragsForKill, CBC_ORDER_FIRST) { - frag_score = 0; // score will be given to the winner team when the round ends - return 1; + M_ARGV(2, float) = 0; // score will be given to the winner team when the round ends + return true; } MUTATOR_HOOKFUNCTION(ca, SetStartItems) @@ -364,12 +322,16 @@ MUTATOR_HOOKFUNCTION(ca, SetStartItems) start_ammo_cells = warmup_start_ammo_cells = cvar("g_lms_start_ammo_cells"); start_ammo_plasma = warmup_start_ammo_plasma = cvar("g_lms_start_ammo_plasma"); start_ammo_fuel = warmup_start_ammo_fuel = cvar("g_lms_start_ammo_fuel"); - - return 0; } -MUTATOR_HOOKFUNCTION(ca, PlayerDamage_Calculate) +MUTATOR_HOOKFUNCTION(ca, Damage_Calculate) { + entity frag_attacker = M_ARGV(1, entity); + entity frag_target = M_ARGV(2, entity); + float frag_deathtype = M_ARGV(3, float); + float frag_damage = M_ARGV(4, float); + float frag_mirrordamage = M_ARGV(5, float); + if (IS_PLAYER(frag_target)) if (!IS_DEAD(frag_target)) if (frag_target == frag_attacker || SAME_TEAM(frag_target, frag_attacker) || frag_deathtype == DEATH_FALL.m_id) @@ -377,30 +339,34 @@ MUTATOR_HOOKFUNCTION(ca, PlayerDamage_Calculate) frag_mirrordamage = 0; - return false; + M_ARGV(4, float) = frag_damage; + M_ARGV(5, float) = frag_mirrordamage; } MUTATOR_HOOKFUNCTION(ca, FilterItem) { - SELFPARAM(); + entity item = M_ARGV(0, entity); + if (autocvar_g_powerups <= 0) - if (this.flags & FL_POWERUP) + if (item.flags & FL_POWERUP) return true; if (autocvar_g_pickup_items <= 0) return true; - - return false; } MUTATOR_HOOKFUNCTION(ca, PlayerDamage_SplitHealthArmor) { + entity frag_attacker = M_ARGV(1, entity); + entity frag_target = M_ARGV(2, entity); + float frag_damage = M_ARGV(7, float); + float damage_take = M_ARGV(4, float); + float damage_save = M_ARGV(5, float); + float excess = max(0, frag_damage - damage_take - damage_save); if (frag_target != frag_attacker && IS_PLAYER(frag_attacker)) PlayerTeamScore_Add(frag_attacker, SP_SCORE, ST_SCORE, (frag_damage - excess) * autocvar_g_ca_damage2score_multiplier); - - return false; } MUTATOR_HOOKFUNCTION(ca, PlayerRegen) @@ -417,41 +383,48 @@ MUTATOR_HOOKFUNCTION(ca, Scores_CountFragsRemaining) MUTATOR_HOOKFUNCTION(ca, SpectateSet) { - SELFPARAM(); - if (!autocvar_g_ca_spectate_enemies && this.caplayer) - if (DIFF_TEAM(spec_player, this)) + entity client = M_ARGV(0, entity); + entity targ = M_ARGV(1, entity); + + if (!autocvar_g_ca_spectate_enemies && client.caplayer) + if (DIFF_TEAM(targ, client)) return true; - return false; } MUTATOR_HOOKFUNCTION(ca, SpectateNext) { - SELFPARAM(); - if (!autocvar_g_ca_spectate_enemies && this.caplayer) + entity client = M_ARGV(0, entity); + + if (!autocvar_g_ca_spectate_enemies && client.caplayer) { - spec_player = CA_SpectateNext(this, spec_player); + entity targ = M_ARGV(1, entity); + M_ARGV(1, entity) = CA_SpectateNext(client, targ); return true; } - return false; } MUTATOR_HOOKFUNCTION(ca, SpectatePrev) { - SELFPARAM(); - if (!autocvar_g_ca_spectate_enemies && this.caplayer) + entity client = M_ARGV(0, entity); + entity targ = M_ARGV(1, entity); + entity first = M_ARGV(2, entity); + + if (!autocvar_g_ca_spectate_enemies && client.caplayer) { - do { spec_player = spec_player.chain; } - while(spec_player && DIFF_TEAM(spec_player, this)); + do { targ = targ.chain; } + while(targ && DIFF_TEAM(targ, client)); - if (!spec_player) + if (!targ) { - for (spec_player = spec_first; spec_player && DIFF_TEAM(spec_player, this); spec_player = spec_player.chain); + for (targ = first; targ && DIFF_TEAM(targ, client); targ = targ.chain); - if (spec_player == this.enemy) + if (targ == client.enemy) return MUT_SPECPREV_RETURN; } } + M_ARGV(1, entity) = targ; + return MUT_SPECPREV_FOUND; } @@ -459,20 +432,21 @@ MUTATOR_HOOKFUNCTION(ca, Bot_FixCount, CBC_ORDER_EXCLUSIVE) { FOREACH_CLIENT(IS_REAL_CLIENT(it), { if (IS_PLAYER(it) || it.caplayer == 1) - ++bot_activerealplayers; - ++bot_realplayers; + ++M_ARGV(0, int); + ++M_ARGV(1, int); }); return true; } MUTATOR_HOOKFUNCTION(ca, ClientCommand_Spectate) { - SELFPARAM(); - if (this.caplayer) + entity player = M_ARGV(0, entity); + + if (player.caplayer) { // they're going to spec, we can do other checks - if (autocvar_sv_spectate && (IS_SPEC(this) || IS_OBSERVER(this))) - Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_CA_LEAVE); + if (autocvar_sv_spectate && (IS_SPEC(player) || IS_OBSERVER(player))) + Send_Notification(NOTIF_ONE_ONLY, player, MSG_INFO, INFO_CA_LEAVE); return MUT_SPECCMD_FORCE; } @@ -481,19 +455,23 @@ MUTATOR_HOOKFUNCTION(ca, ClientCommand_Spectate) MUTATOR_HOOKFUNCTION(ca, WantWeapon) { - want_allguns = true; - return false; + M_ARGV(2, bool) = true; // all weapons +} + +MUTATOR_HOOKFUNCTION(ca, HideTeamNagger) +{ + return true; // doesn't work well with the whole spectator as player thing } MUTATOR_HOOKFUNCTION(ca, GetPlayerStatus) { - return set_player.caplayer == 1; + entity player = M_ARGV(0, entity); + + return player.caplayer == 1; } MUTATOR_HOOKFUNCTION(ca, SetWeaponArena) { // most weapons arena - if (ret_string == "0" || ret_string == "") ret_string = "most"; + if (M_ARGV(0, string) == "0" || M_ARGV(0, string) == "") M_ARGV(0, string) = "most"; } - -#endif