1 #include "sv_tmayhem.qh"
3 // TODO? rename to teammayhem? requires checking alias length
4 int autocvar_g_tmayhem_teams;
5 int autocvar_g_tmayhem_teams_override;
7 bool autocvar_g_tmayhem_regenerate;
8 string autocvar_g_tmayhem_weaponarena;
9 bool autocvar_g_tmayhem_powerups;
10 bool autocvar_g_tmayhem_selfdamage;
11 int autocvar_g_tmayhem_scoringmethod;
15 // code from here on is just to support maps that don't have team entities
16 void tmayhem_SpawnTeam (string teamname, int teamcolor)
18 entity this = new_pure(tmayhem_team);
19 this.netname = teamname;
20 this.cnt = teamcolor - 1;
21 this.team = teamcolor;
22 this.spawnfunc_checked = true;
23 //spawnfunc_tmayhem_team(this);
26 void tmayhem_DelayedInit(entity this)
28 // if no teams are found, spawn defaults
29 if(find(NULL, classname, "tmayhem_team") == NULL)
31 LOG_TRACE("No \"tmayhem_team\" entities found on this map, creating them anyway.");
33 int numteams = autocvar_g_tmayhem_teams_override;
34 if(numteams < 2) { numteams = autocvar_g_tmayhem_teams; }
36 int teams = BITS(bound(2, numteams, 4));
38 tmayhem_SpawnTeam("Red", NUM_TEAM_1);
40 tmayhem_SpawnTeam("Blue", NUM_TEAM_2);
42 tmayhem_SpawnTeam("Yellow", NUM_TEAM_3);
44 tmayhem_SpawnTeam("Pink", NUM_TEAM_4);
48 void tmayhem_Initialize()
50 if(autocvar_g_tmayhem_visual_score_limit != 0 && autocvar_g_tmayhem_fraglimit != 0)
51 tmayhempointmultiplier = autocvar_g_tmayhem_visual_score_limit / autocvar_g_tmayhem_fraglimit;
53 GameRules_teams(true);
54 GameRules_spawning_teams(autocvar_g_tmayhem_team_spawns);
55 GameRules_limit_score(autocvar_g_tmayhem_visual_score_limit);
56 GameRules_limit_lead(autocvar_g_tmayhem_score_leadlimit);
58 InitializeEntity(NULL, tmayhem_DelayedInit, INITPRIO_GAMETYPE);
61 MUTATOR_HOOKFUNCTION(tmayhem, TeamBalance_CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
63 M_ARGV(1, string) = "tmayhem_team";
66 MUTATOR_HOOKFUNCTION(tmayhem, Scores_CountFragsRemaining)
68 // announce remaining frags
72 MUTATOR_HOOKFUNCTION(tmayhem, SetStartItems)
74 start_items &= ~(IT_UNLIMITED_AMMO | IT_UNLIMITED_SUPERWEAPONS);
75 start_health = warmup_start_health = cvar("g_tmayhem_start_health");
76 start_armorvalue = warmup_start_armorvalue = cvar("g_tmayhem_start_armor");
77 start_ammo_shells = warmup_start_ammo_shells = cvar("g_tmayhem_start_ammo_shells");
78 start_ammo_nails = warmup_start_ammo_nails = cvar("g_tmayhem_start_ammo_nails");
79 start_ammo_rockets = warmup_start_ammo_rockets = cvar("g_tmayhem_start_ammo_rockets");
80 start_ammo_cells = warmup_start_ammo_cells = cvar("g_tmayhem_start_ammo_cells");
81 start_ammo_plasma = warmup_start_ammo_plasma = cvar("g_tmayhem_start_ammo_plasma");
82 start_ammo_fuel = warmup_start_ammo_fuel = cvar("g_tmayhem_start_ammo_fuel");
85 //this hook also enables rotting, as players spawn with more hp and armor than what default rot limits are set to this is a bad idea as of now
86 MUTATOR_HOOKFUNCTION(tmayhem, PlayerRegen)
88 if(autocvar_g_tmayhem_regenerate)
93 MUTATOR_HOOKFUNCTION(tmayhem, ForbidThrowCurrentWeapon)
98 MUTATOR_HOOKFUNCTION(tmayhem, SetWeaponArena)
100 if (M_ARGV(0, string) == "0" || M_ARGV(0, string) == "")
101 M_ARGV(0, string) = autocvar_g_tmayhem_weaponarena;
104 MUTATOR_HOOKFUNCTION(tmayhem, FilterItem)
106 entity item = M_ARGV(0, entity);
107 if (autocvar_g_powerups == 1){
108 if (item.flags & FL_POWERUP){
112 else if (autocvar_g_powerups == -1){
113 if (item.flags & FL_POWERUP){
114 if (autocvar_g_tmayhem_powerups){
119 if (autocvar_g_pickup_items <= 0)
123 MUTATOR_HOOKFUNCTION(tmayhem, Damage_Calculate)
125 entity frag_attacker = M_ARGV(1, entity);
126 entity frag_target = M_ARGV(2, entity);
127 float frag_deathtype = M_ARGV(3, float);
128 float frag_damage = M_ARGV(4, float);
129 float frag_mirrordamage = M_ARGV(5, float);
131 if (IS_PLAYER(frag_target))
132 if (!IS_DEAD(frag_target))
133 if ((autocvar_g_tmayhem_selfdamage == 0 && frag_target == frag_attacker) || frag_deathtype == DEATH_FALL.m_id)
136 frag_mirrordamage = 0;
138 M_ARGV(4, float) = frag_damage;
139 M_ARGV(5, float) = frag_mirrordamage;
142 MUTATOR_HOOKFUNCTION(tmayhem, PlayerDamage_SplitHealthArmor)
144 switch(autocvar_g_tmayhem_scoringmethod)
155 entity frag_attacker = M_ARGV(1, entity);
156 entity frag_target = M_ARGV(2, entity);
157 float frag_deathtype = M_ARGV(6, float);
158 float frag_damage = M_ARGV(7, float);
159 float damage_take = bound(0, M_ARGV(4, float), GetResource(frag_target, RES_HEALTH));
160 float damage_save = bound(0, M_ARGV(5, float), GetResource(frag_target, RES_ARMOR));
162 float excess = max(0, frag_damage - damage_take - damage_save);
164 if (frag_target != frag_attacker && IS_PLAYER(frag_attacker))
165 GameRules_scoring_add_team(frag_attacker, SCORE, (frag_damage - excess) * (1/(start_health + start_armorvalue)));
167 if (frag_target == frag_attacker && IS_PLAYER(frag_attacker))
168 GameRules_scoring_add_team(frag_target, SCORE, (-1 * (frag_damage - excess)) * (1/(start_health + start_armorvalue)));
170 //handle hazard suiciding, check first if player has a registered attacker who most likely pushed them there
171 if (!IS_PLAYER(frag_attacker) && (
172 frag_deathtype == DEATH_DROWN.m_id ||
173 frag_deathtype == DEATH_HURTTRIGGER.m_id ||
174 frag_deathtype == DEATH_CAMP.m_id ||
175 frag_deathtype == DEATH_LAVA.m_id ||
176 frag_deathtype == DEATH_SLIME.m_id))
177 GameRules_scoring_add_team(frag_target, SCORE, (-1 * (frag_damage - excess)) * (1/(start_health + start_armorvalue)));
179 //when hp and armor values are checked when suiciding for some reason they are 0.9 hp and 0 armor regardless that player suicided with 200+200
180 //AFAIK dynamic hp value checking is not possible, hardcoded start hp and armor
181 //FIXME: ^ , might require fixing hp+a check for suicides as a whole
182 if (frag_deathtype == DEATH_KILL.m_id)
183 GameRules_scoring_add_team(frag_target, SCORE, (-1 * (start_health + start_armorvalue)) * (1/(start_health + start_armorvalue)));
187 //combined damage and frags
191 entity frag_attacker = M_ARGV(1, entity);
192 entity frag_target = M_ARGV(2, entity);
193 float frag_deathtype = M_ARGV(6, float);
194 float frag_damage = M_ARGV(7, float);
195 float damage_take = bound(0, M_ARGV(4, float), GetResource(frag_target, RES_HEALTH));
196 float damage_save = bound(0, M_ARGV(5, float), GetResource(frag_target, RES_ARMOR));
198 float excess = max(0, frag_damage - damage_take - damage_save);
200 if (frag_target != frag_attacker && IS_PLAYER(frag_attacker))
201 GameRules_scoring_add_team(frag_attacker, SCORE, (frag_damage - excess) * 0.75 * tmayhempointmultiplier * (1/(start_health + start_armorvalue)));
203 if (frag_target == frag_attacker && IS_PLAYER(frag_attacker))
204 GameRules_scoring_add_team(frag_target, SCORE, (-1 * (frag_damage - excess)) * 0.75 * tmayhempointmultiplier * (1/(start_health + start_armorvalue)));
206 //handle hazard suiciding, check first if player has a registered attacker who most likely pushed them there
207 if (!IS_PLAYER(frag_attacker) && (
208 frag_deathtype == DEATH_DROWN.m_id ||
209 frag_deathtype == DEATH_HURTTRIGGER.m_id ||
210 frag_deathtype == DEATH_CAMP.m_id ||
211 frag_deathtype == DEATH_LAVA.m_id ||
212 frag_deathtype == DEATH_SLIME.m_id))
213 GameRules_scoring_add_team(frag_target, SCORE, (-1 * (frag_damage - excess)) * 0.75 * tmayhempointmultiplier * (1/(start_health + start_armorvalue)));
215 //when hp and armor values are checked when suiciding for some reason they are 0.9 hp and 0 armor regardless that player suicided with 200+200
216 //AFAIK dynamic hp value checking is not possible, hardcoded start hp and armor
217 //FIXME: ^ , might require fixing hp+a check for suicides as a whole
218 if (frag_deathtype == DEATH_KILL.m_id)
219 GameRules_scoring_add_team(frag_target, SCORE, (-1 * (start_health + start_armorvalue)) * 0.75 * tmayhempointmultiplier * (1/(start_health + start_armorvalue)));
225 MUTATOR_HOOKFUNCTION(tmayhem, GiveFragsForKill, CBC_ORDER_FIRST)
227 switch(autocvar_g_tmayhem_scoringmethod)
232 //fix 999 score from 30 kills for example
233 M_ARGV(2, float) = 1 * tmayhempointmultiplier * 1.0001;
240 M_ARGV(2, float) = 0;
244 //combined damage and frags
248 M_ARGV(2, float) = 0.25 * tmayhempointmultiplier * 1.0001;