X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fmutators%2Fgamemode_freezetag.qc;h=5280e559bbceab46554144dadbace4d92f41b63e;hb=49e5f5d2c7423c3c4536a57e6740d79d9b8eec94;hp=ead918c4498f2230baa916b1435a3f1fc1219a94;hpb=d820bc6acfe936141e2fc15d0d3bbcf98ad278ab;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/mutators/gamemode_freezetag.qc b/qcsrc/server/mutators/gamemode_freezetag.qc index ead918c44..5280e559b 100644 --- a/qcsrc/server/mutators/gamemode_freezetag.qc +++ b/qcsrc/server/mutators/gamemode_freezetag.qc @@ -1,6 +1,7 @@ .float freezetag_frozen_time; .float freezetag_frozen_timeout; .float freezetag_revive_progress; +.entity freezetag_ice; #define ICE_MAX_ALPHA 1 #define ICE_MIN_ALPHA 0.1 float freezetag_teams; @@ -13,22 +14,22 @@ void freezetag_count_alive_players() if(e.team == NUM_TEAM_1 && e.health >= 1) { ++total_players; - if (e.frozen != 1) ++redalive; + if (!e.freezetag_frozen) ++redalive; } else if(e.team == NUM_TEAM_2 && e.health >= 1) { ++total_players; - if (e.frozen != 1) ++bluealive; + if (!e.freezetag_frozen) ++bluealive; } else if(e.team == NUM_TEAM_3 && e.health >= 1) { ++total_players; - if (e.frozen != 1) ++yellowalive; + if (!e.freezetag_frozen) ++yellowalive; } else if(e.team == NUM_TEAM_4 && e.health >= 1) { ++total_players; - if (e.frozen != 1) ++pinkalive; + if (!e.freezetag_frozen) ++pinkalive; } } FOR_EACH_REALCLIENT(e) { @@ -41,27 +42,30 @@ void freezetag_count_alive_players() #define FREEZETAG_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0)) #define FREEZETAG_ALIVE_TEAMS_OK() (FREEZETAG_ALIVE_TEAMS() == freezetag_teams) -float prev_total_players; +float prev_missing_teams_mask; float freezetag_CheckTeams() { if(FREEZETAG_ALIVE_TEAMS_OK()) { - if(prev_total_players > 0) + if(prev_missing_teams_mask > 0) Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_MISSING_TEAMS); - prev_total_players = -1; + prev_missing_teams_mask = -1; return 1; } - if(prev_total_players != total_players) + if(total_players == 0) { - float p1 = 0, p2 = 0, p3 = 0, p4 = 0; - if(!redalive) p1 = NUM_TEAM_1; - if(!bluealive) p2 = NUM_TEAM_2; - if(freezetag_teams >= 3) - if(!yellowalive) p3 = NUM_TEAM_3; - if(freezetag_teams >= 4) - if(!pinkalive) p4 = NUM_TEAM_4; - Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_MISSING_TEAMS, p1, p2, p3, p4); - prev_total_players = total_players; + if(prev_missing_teams_mask > 0) + Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_MISSING_TEAMS); + prev_missing_teams_mask = -1; + return 0; + } + float missing_teams_mask = (!redalive) + (!bluealive) * 2; + if(freezetag_teams >= 3) missing_teams_mask += (!yellowalive) * 4; + if(freezetag_teams >= 4) 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); + prev_missing_teams_mask = missing_teams_mask; } return 0; } @@ -99,7 +103,10 @@ float freezetag_CheckWinner() Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_OVER); Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_OVER); FOR_EACH_PLAYER(e) + { e.freezetag_frozen_timeout = 0; + e.freezetag_revive_progress = 0; + } round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit); return 1; } @@ -122,11 +129,51 @@ float freezetag_CheckWinner() } FOR_EACH_PLAYER(e) + { e.freezetag_frozen_timeout = 0; + e.freezetag_revive_progress = 0; + } round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit); return 1; } +entity freezetag_LastPlayerForTeam() +{ + entity pl, last_pl = world; + FOR_EACH_PLAYER(pl) + { + if(pl.health >= 1) + if(!pl.freezetag_frozen) + if(pl != self) + if(pl.team == self.team) + if(!last_pl) + last_pl = pl; + else + return world; + } + return last_pl; +} + +void freezetag_LastPlayerForTeam_Notify() +{ + if(round_handler_IsActive()) + if(round_handler_IsRoundStarted()) + { + entity pl = freezetag_LastPlayerForTeam(); + if(pl) + Send_Notification(NOTIF_ONE, pl, MSG_CENTER, CENTER_ALONE); + } +} + +// this is needed to allow the player to turn his view around (fixangle can't +// be used to freeze his view, as that also changes the angles), while not +// turning that ice object with the player +void freezetag_Ice_Think() +{ + setorigin(self, self.owner.origin - '0 0 16'); + self.nextthink = time; +} + void freezetag_Add_Score(entity attacker) { if(attacker == self) @@ -147,24 +194,54 @@ void freezetag_Add_Score(entity attacker) void freezetag_Freeze(entity attacker) { - if(self.frozen) + if(self.freezetag_frozen) return; - - Freeze(self, 0, 1, TRUE); - + self.freezetag_frozen = 1; + self.freezetag_frozen_time = time; + self.freezetag_revive_progress = 0; + self.health = 1; + if(autocvar_g_freezetag_frozen_maxtime > 0) + self.freezetag_frozen_timeout = time + autocvar_g_freezetag_frozen_maxtime; + freezetag_count_alive_players(); + entity ice; + ice = spawn(); + ice.owner = self; + ice.classname = "freezetag_ice"; + ice.think = freezetag_Ice_Think; + ice.nextthink = time; + ice.frame = floor(random() * 21); // ice model has 20 different looking frames + ice.alpha = ICE_MAX_ALPHA; + ice.colormod = Team_ColorRGB(self.team); + ice.glowmod = ice.colormod; + setmodel(ice, "models/ice/ice.md3"); + + self.freezetag_ice = ice; + + RemoveGrapplingHook(self); + + // add waypoint + WaypointSprite_Spawn("freezetag_frozen", 0, 0, self, '0 0 64', world, self.team, self, waypointsprite_attached, TRUE, RADARICON_WAYPOINT, '0.25 0.90 1'); + freezetag_Add_Score(attacker); } void freezetag_Unfreeze(entity attacker) { + self.freezetag_frozen = 0; self.freezetag_frozen_time = 0; self.freezetag_frozen_timeout = 0; - - Unfreeze(self); + self.freezetag_revive_progress = 0; + + remove(self.freezetag_ice); + self.freezetag_ice = world; + + if(self.waypointsprite_attached) + WaypointSprite_Kill(self.waypointsprite_attached); } + // ================ // Bot player logic // ================ @@ -181,7 +258,7 @@ void havocbot_goalrating_freeplayers(float ratingscale, vector org, float sradiu { if ((head != self) && (head.team == self.team)) { - if (head.frozen == 1) + if (head.freezetag_frozen) { distance = vlen(head.origin - org); if (distance > sradius) @@ -213,12 +290,12 @@ void havocbot_role_ft_offense() unfrozen = 0; FOR_EACH_PLAYER(head) { - if ((head.team == self.team) && (head.frozen != 1)) + if ((head.team == self.team) && (!head.freezetag_frozen)) unfrozen++; } // If only one left on team or if role has timed out then start trying to free players. - if (((unfrozen == 0) && (!self.frozen)) || (time > self.havocbot_role_timeout)) + if (((unfrozen == 0) && (!self.freezetag_frozen)) || (time > self.havocbot_role_timeout)) { dprint("changing role to freeing\n"); self.havocbot_role = havocbot_role_ft_freeing; @@ -276,6 +353,8 @@ void havocbot_role_ft_freeing() MUTATOR_HOOKFUNCTION(freezetag_RemovePlayer) { self.health = 0; // neccessary to update correctly alive stats + if(!self.freezetag_frozen) + freezetag_LastPlayerForTeam_Notify(); freezetag_Unfreeze(world); freezetag_count_alive_players(); return 1; @@ -286,7 +365,7 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerDies) if(round_handler_IsActive()) if(round_handler_CountdownRunning()) { - if(self.frozen) + if(self.freezetag_frozen) freezetag_Unfreeze(world); freezetag_count_alive_players(); return 1; // let the player die so that he can respawn whenever he wants @@ -298,10 +377,11 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerDies) || frag_deathtype == DEATH_TEAMCHANGE || frag_deathtype == DEATH_AUTOTEAMCHANGE) { // let the player die, he will be automatically frozen when he respawns - if(self.frozen != 1) + if(!self.freezetag_frozen) { freezetag_Add_Score(frag_attacker); freezetag_count_alive_players(); + freezetag_LastPlayerForTeam_Notify(); } else freezetag_Unfreeze(world); // remove ice @@ -309,10 +389,11 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerDies) return 1; } - if(self.frozen) + if(self.freezetag_frozen) return 1; freezetag_Freeze(frag_attacker); + freezetag_LastPlayerForTeam_Notify(); if(frag_attacker == frag_target || frag_attacker == world) { @@ -329,6 +410,8 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerDies) Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_FREEZE, frag_target.netname, frag_attacker.netname); } + frag_target.health = 1; // "respawn" the player :P + return 1; } @@ -359,7 +442,8 @@ MUTATOR_HOOKFUNCTION(freezetag_reset_map_players) { FOR_EACH_PLAYER(self) { - if (self.frozen) + self.killcount = 0; + if (self.freezetag_frozen) freezetag_Unfreeze(world); self.freezetag_frozen_timeout = -1; PutClientInServer(); @@ -383,7 +467,7 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerPreThink) if(gameover) return 1; - if(self.frozen == 1) + if(self.freezetag_frozen) { // keep health = 1 self.pauseregen_finished = time + autocvar_g_balance_pause_health_regen; @@ -396,7 +480,7 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerPreThink) entity o; o = world; if(self.freezetag_frozen_timeout > 0 && time < self.freezetag_frozen_timeout) - self.iceblock.alpha = ICE_MIN_ALPHA + (ICE_MAX_ALPHA - ICE_MIN_ALPHA) * (self.freezetag_frozen_timeout - time) / (self.freezetag_frozen_timeout - self.freezetag_frozen_time); + self.freezetag_ice.alpha = ICE_MIN_ALPHA + (ICE_MAX_ALPHA - ICE_MIN_ALPHA) * (self.freezetag_frozen_timeout - time) / (self.freezetag_frozen_timeout - self.freezetag_frozen_time); if(self.freezetag_frozen_timeout > 0 && time >= self.freezetag_frozen_timeout) n = -1; @@ -406,7 +490,7 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerPreThink) n = 0; FOR_EACH_PLAYER(other) if(self != other) { - if(!other.frozen) + if(other.freezetag_frozen == 0) { if(other.team == self.team) { @@ -414,7 +498,7 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerPreThink) { if(!o) o = other; - if(self.frozen == 1) + if(self.freezetag_frozen) other.reviving = TRUE; ++n; } @@ -423,12 +507,15 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerPreThink) } } - if(n && self.frozen == 1) // OK, there is at least one teammate reviving us + if(n && self.freezetag_frozen) // OK, there is at least one teammate reviving us { - self.revive_progress = bound(0, self.revive_progress + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1); - self.health = max(1, self.revive_progress * autocvar_g_balance_health_start); + self.freezetag_revive_progress = bound(0, self.freezetag_revive_progress + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1); + if(warmup_stage) + self.health = max(1, self.freezetag_revive_progress * warmup_start_health); + else + self.health = max(1, self.freezetag_revive_progress * start_health); - if(self.revive_progress >= 1) + if(self.freezetag_revive_progress >= 1) { freezetag_Unfreeze(self); freezetag_count_alive_players(); @@ -459,27 +546,48 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerPreThink) { if(other.reviving) { - other.revive_progress = self.revive_progress; + other.freezetag_revive_progress = self.freezetag_revive_progress; other.reviving = FALSE; } } } - else if(!n && self.frozen == 1) // only if no teammate is nearby will we reset + else if(!n && self.freezetag_frozen) // only if no teammate is nearby will we reset { - self.revive_progress = bound(0, self.revive_progress - frametime * autocvar_g_freezetag_revive_clearspeed, 1); - self.health = max(1, self.revive_progress * autocvar_g_balance_health_start); + self.freezetag_revive_progress = bound(0, self.freezetag_revive_progress - frametime * autocvar_g_freezetag_revive_clearspeed, 1); + if(warmup_stage) + self.health = max(1, self.freezetag_revive_progress * warmup_start_health); + else + self.health = max(1, self.freezetag_revive_progress * start_health); } - else if(!n && !self.frozen) + else if(!n) { - self.revive_progress = 0; // thawing nobody + self.freezetag_revive_progress = 0; // thawing nobody } return 1; } +MUTATOR_HOOKFUNCTION(freezetag_PlayerPhysics) +{ + if(self.freezetag_frozen) + { + if(autocvar_sv_dodging_frozen && IS_REAL_CLIENT(self)) + { + self.movement_x = bound(-5, self.movement_x, 5); + self.movement_y = bound(-5, self.movement_y, 5); + self.movement_z = bound(-5, self.movement_z, 5); + } + else + self.movement = '0 0 0'; + + self.disableclientprediction = 1; + } + return 1; +} + MUTATOR_HOOKFUNCTION(freezetag_PlayerDamage_Calculate) { - if(frag_target.frozen == 1 && frag_deathtype != DEATH_HURTTRIGGER) + if(frag_target.freezetag_frozen && frag_deathtype != DEATH_HURTTRIGGER) { if(autocvar_g_freezetag_revive_falldamage > 0) if(frag_deathtype == DEATH_FALL) @@ -491,16 +599,38 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerDamage_Calculate) Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_REVIVED_FALL, frag_target.netname); Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_REVIVE_FALL); } - + frag_damage = 0; frag_force = frag_force * autocvar_g_freezetag_frozen_force; } return 1; } +MUTATOR_HOOKFUNCTION(freezetag_PlayerJump) +{ + if(self.freezetag_frozen) + return TRUE; // no jumping in freezetag when frozen + + return FALSE; +} + +MUTATOR_HOOKFUNCTION(freezetag_ForbidThrowCurrentWeapon) +{ + if (self.freezetag_frozen) + return 1; + return 0; +} + +MUTATOR_HOOKFUNCTION(freezetag_ItemTouch) +{ + if (other.freezetag_frozen) + return MUT_ITEMTOUCH_RETURN; + return MUT_ITEMTOUCH_CONTINUE; +} + MUTATOR_HOOKFUNCTION(freezetag_BotRoles) { - if not(self.deadflag) + if (!self.deadflag) { if (random() < 0.5) self.havocbot_role = havocbot_role_ft_freeing; @@ -511,20 +641,36 @@ MUTATOR_HOOKFUNCTION(freezetag_BotRoles) return TRUE; } +MUTATOR_HOOKFUNCTION(freezetag_SpectateCopy) +{ + self.freezetag_frozen = other.freezetag_frozen; + self.freezetag_revive_progress = other.freezetag_revive_progress; + return 0; +} + MUTATOR_HOOKFUNCTION(freezetag_GetTeamCount) { - freezetag_teams = autocvar_g_freezetag_teams_override; - if(freezetag_teams < 2) - freezetag_teams = autocvar_g_freezetag_teams; - freezetag_teams = bound(2, freezetag_teams, 4); ret_float = freezetag_teams; return 0; } +MUTATOR_HOOKFUNCTION(freezetag_VehicleTouch) +{ + if(other.freezetag_frozen) + return TRUE; + + return FALSE; +} + void freezetag_Initialize() { precache_model("models/ice/ice.md3"); - ScoreRules_freezetag(); + + freezetag_teams = autocvar_g_freezetag_teams_override; + if(freezetag_teams < 2) + freezetag_teams = autocvar_g_freezetag_teams; + freezetag_teams = bound(2, freezetag_teams, 4); + ScoreRules_freezetag(freezetag_teams); round_handler_Spawn(freezetag_CheckTeams, freezetag_CheckWinner, func_null); round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit); @@ -533,6 +679,9 @@ void freezetag_Initialize() addstat(STAT_BLUEALIVE, AS_INT, bluealive_stat); addstat(STAT_YELLOWALIVE, AS_INT, yellowalive_stat); addstat(STAT_PINKALIVE, AS_INT, pinkalive_stat); + + addstat(STAT_FROZEN, AS_INT, freezetag_frozen); + addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, freezetag_revive_progress); } MUTATOR_DEFINITION(gamemode_freezetag) @@ -544,9 +693,15 @@ MUTATOR_DEFINITION(gamemode_freezetag) MUTATOR_HOOK(reset_map_players, freezetag_reset_map_players, CBC_ORDER_ANY); MUTATOR_HOOK(GiveFragsForKill, freezetag_GiveFragsForKill, CBC_ORDER_FIRST); MUTATOR_HOOK(PlayerPreThink, freezetag_PlayerPreThink, CBC_ORDER_FIRST); + MUTATOR_HOOK(PlayerPhysics, freezetag_PlayerPhysics, CBC_ORDER_FIRST); MUTATOR_HOOK(PlayerDamage_Calculate, freezetag_PlayerDamage_Calculate, CBC_ORDER_ANY); - MUTATOR_HOOK(HavocBot_ChooseRule, freezetag_BotRoles, CBC_ORDER_ANY); + MUTATOR_HOOK(PlayerJump, freezetag_PlayerJump, CBC_ORDER_ANY); + MUTATOR_HOOK(ForbidThrowCurrentWeapon, freezetag_ForbidThrowCurrentWeapon, CBC_ORDER_ANY); + MUTATOR_HOOK(ItemTouch, freezetag_ItemTouch, CBC_ORDER_ANY); + MUTATOR_HOOK(HavocBot_ChooseRole, freezetag_BotRoles, CBC_ORDER_ANY); + MUTATOR_HOOK(SpectateCopy, freezetag_SpectateCopy, CBC_ORDER_ANY); MUTATOR_HOOK(GetTeamCount, freezetag_GetTeamCount, CBC_ORDER_EXCLUSIVE); + MUTATOR_HOOK(VehicleTouch, freezetag_VehicleTouch, CBC_ORDER_ANY); MUTATOR_ONADD {