seta hud_panel_itemstime_progressbar_maxtime "30" "when left time is at least this amount, the status bar is full"
seta hud_panel_itemstime_hidespawned "1" "if 1 hide an item from the panel when all the occurrences of it are available again; if 2 hide it when at least one occurrence is available again"
-seta hud_panel_itemstime_hidelarge "0" "if 1 hide large armor and health from the panel"
+seta hud_panel_itemstime_hidebig "0" "if 1 hide big armor and health from the panel"
seta hud_panel_quickmenu_file "" "load the quick menu from this file (empty or 0 to disable)"
seta hud_panel_quickmenu_translatecommands 0 "when the game is translated, translate strings inside commands too (useful for chat commands)"
set g_pickup_armorbig 50
set g_pickup_armorbig_max 200
set g_pickup_armorbig_anyway 1
-set g_pickup_armorlarge 100
-set g_pickup_armorlarge_max 200
-set g_pickup_armorlarge_anyway 1
+set g_pickup_armormega 100
+set g_pickup_armormega_max 200
+set g_pickup_armormega_anyway 1
set g_pickup_healthsmall 5
set g_pickup_healthsmall_max 200
set g_pickup_healthsmall_anyway 1
set g_pickup_healthmedium 25
set g_pickup_healthmedium_max 200
set g_pickup_healthmedium_anyway 1
-set g_pickup_healthlarge 50
-set g_pickup_healthlarge_max 200
-set g_pickup_healthlarge_anyway 1
+set g_pickup_healthbig 50
+set g_pickup_healthbig_max 200
+set g_pickup_healthbig_anyway 1
set g_pickup_healthmega 100
set g_pickup_healthmega_max 200
set g_pickup_healthmega_anyway 1
set g_pickup_armorbig 50
set g_pickup_armorbig_max 999
set g_pickup_armorbig_anyway 0
-set g_pickup_armorlarge 100
-set g_pickup_armorlarge_max 999
-set g_pickup_armorlarge_anyway 0
+set g_pickup_armormega 100
+set g_pickup_armormega_max 999
+set g_pickup_armormega_anyway 0
set g_pickup_healthsmall 5
set g_pickup_healthsmall_max 999
set g_pickup_healthsmall_anyway 0
set g_pickup_healthmedium 25
set g_pickup_healthmedium_max 999
set g_pickup_healthmedium_anyway 0
-set g_pickup_healthlarge 50
-set g_pickup_healthlarge_max 999
-set g_pickup_healthlarge_anyway 0
+set g_pickup_healthbig 50
+set g_pickup_healthbig_max 999
+set g_pickup_healthbig_anyway 0
set g_pickup_healthmega 100
set g_pickup_healthmega_max 999
set g_pickup_healthmega_anyway 0
set g_pickup_armorbig 50
set g_pickup_armorbig_max 100
set g_pickup_armorbig_anyway 1
-set g_pickup_armorlarge 100
-set g_pickup_armorlarge_max 100
-set g_pickup_armorlarge_anyway 1
+set g_pickup_armormega 100
+set g_pickup_armormega_max 100
+set g_pickup_armormega_anyway 1
set g_pickup_healthsmall 5
set g_pickup_healthsmall_max 200
set g_pickup_healthsmall_anyway 1
set g_pickup_healthmedium 25
set g_pickup_healthmedium_max 200
set g_pickup_healthmedium_anyway 1
-set g_pickup_healthlarge 50
-set g_pickup_healthlarge_max 200
-set g_pickup_healthlarge_anyway 1
+set g_pickup_healthbig 50
+set g_pickup_healthbig_max 200
+set g_pickup_healthbig_anyway 1
set g_pickup_healthmega 100
set g_pickup_healthmega_max 200
set g_pickup_healthmega_anyway 0
set g_pickup_armorbig 50
set g_pickup_armorbig_max 200
set g_pickup_armorbig_anyway 1
-set g_pickup_armorlarge 100
-set g_pickup_armorlarge_max 200
-set g_pickup_armorlarge_anyway 1
+set g_pickup_armormega 100
+set g_pickup_armormega_max 200
+set g_pickup_armormega_anyway 1
set g_pickup_healthsmall 5
set g_pickup_healthsmall_max 200
set g_pickup_healthsmall_anyway 1
set g_pickup_healthmedium 25
set g_pickup_healthmedium_max 200
set g_pickup_healthmedium_anyway 1
-set g_pickup_healthlarge 50
-set g_pickup_healthlarge_max 200
-set g_pickup_healthlarge_anyway 1
+set g_pickup_healthbig 50
+set g_pickup_healthbig_max 200
+set g_pickup_healthbig_anyway 1
set g_pickup_healthmega 100
set g_pickup_healthmega_max 200
set g_pickup_healthmega_anyway 1
set g_pickup_armorbig 50
set g_pickup_armorbig_max 200
set g_pickup_armorbig_anyway 1
-set g_pickup_armorlarge 100
-set g_pickup_armorlarge_max 200
-set g_pickup_armorlarge_anyway 1
+set g_pickup_armormega 100
+set g_pickup_armormega_max 200
+set g_pickup_armormega_anyway 1
set g_pickup_healthsmall 5
set g_pickup_healthsmall_max 200
set g_pickup_healthsmall_anyway 1
set g_pickup_healthmedium 25
set g_pickup_healthmedium_max 200
set g_pickup_healthmedium_anyway 1
-set g_pickup_healthlarge 50
-set g_pickup_healthlarge_max 200
-set g_pickup_healthlarge_anyway 1
+set g_pickup_healthbig 50
+set g_pickup_healthbig_max 200
+set g_pickup_healthbig_anyway 1
set g_pickup_healthmega 100
set g_pickup_healthmega_max 200
set g_pickup_healthmega_anyway 1
set g_pickup_armorbig 50
set g_pickup_armorbig_max 200
set g_pickup_armorbig_anyway 1
-set g_pickup_armorlarge 100
-set g_pickup_armorlarge_max 200
-set g_pickup_armorlarge_anyway 1
+set g_pickup_armormega 100
+set g_pickup_armormega_max 200
+set g_pickup_armormega_anyway 1
set g_pickup_healthsmall 5
set g_pickup_healthsmall_max 200
set g_pickup_healthsmall_anyway 1
set g_pickup_healthmedium 25
set g_pickup_healthmedium_max 200
set g_pickup_healthmedium_anyway 1
-set g_pickup_healthlarge 50
-set g_pickup_healthlarge_max 200
-set g_pickup_healthlarge_anyway 1
+set g_pickup_healthbig 50
+set g_pickup_healthbig_max 200
+set g_pickup_healthbig_anyway 1
set g_pickup_healthmega 100
set g_pickup_healthmega_max 200
set g_pickup_healthmega_anyway 1
set g_pickup_armorbig 50
set g_pickup_armorbig_max 100
set g_pickup_armorbig_anyway 0
-set g_pickup_armorlarge 100
-set g_pickup_armorlarge_max 200
-set g_pickup_armorlarge_anyway 0
+set g_pickup_armormega 100
+set g_pickup_armormega_max 200
+set g_pickup_armormega_anyway 0
set g_pickup_healthsmall 5
set g_pickup_healthsmall_max 200
set g_pickup_healthsmall_anyway 0
set g_pickup_healthmedium 25
set g_pickup_healthmedium_max 100
set g_pickup_healthmedium_anyway 0
-set g_pickup_healthlarge 50
-set g_pickup_healthlarge_max 100
-set g_pickup_healthlarge_anyway 0
+set g_pickup_healthbig 50
+set g_pickup_healthbig_max 100
+set g_pickup_healthbig_anyway 0
set g_pickup_healthmega 100
set g_pickup_healthmega_max 200
set g_pickup_healthmega_anyway 0
set g_overkill_filter_healthmega 0
set g_overkill_filter_armormedium 0
set g_overkill_filter_armorbig 0
-set g_overkill_filter_armorlarge 0
+set g_overkill_filter_armormega 0
set g_overkill_ammo_charge 0
set g_overkill_ammo_charge_notice 1
seta notification_INFO_WEAPON_VAPORIZER_MURDER "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
seta notification_INFO_WEAPON_VORTEX_MURDER "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
-// MSG_CENTER notifications (count = 230):
+// MSG_CENTER notifications (count = 231):
seta notification_CENTER_ALONE "1" "0 = off, 1 = centerprint"
seta notification_CENTER_ASSAULT_ATTACKING "1" "0 = off, 1 = centerprint"
seta notification_CENTER_ASSAULT_DEFENDING "1" "0 = off, 1 = centerprint"
+seta notification_CENTER_ASSAULT_OBJ_DESTROYED "1" "0 = off, 1 = centerprint"
seta notification_CENTER_CAMPCHECK "1" "0 = off, 1 = centerprint"
seta notification_CENTER_COINTOSS "1" "0 = off, 1 = centerprint"
seta notification_CENTER_COUNTDOWN_BEGIN "1" "0 = off, 1 = centerprint"
seta notification_show_sprees_info_newline "1" "Show attacker spree information for MSG_INFO messages on a separate line than the death notification itself"
seta notification_show_sprees_info_specialonly "1" "Don't show attacker spree information in MSG_INFO messages if it isn't an achievement"
-// Notification counts (total = 820): MSG_ANNCE = 89, MSG_INFO = 320, MSG_CENTER = 230, MSG_MULTI = 153, MSG_CHOICE = 28
+// Notification counts (total = 821): MSG_ANNCE = 89, MSG_INFO = 320, MSG_CENTER = 231, MSG_MULTI = 153, MSG_CHOICE = 28
float uid2name_dialog;
-float gameover_time;
+float intermission_time;
.bool csqcmodel_isdead; // used by shownames and miscfunctions (entcs_IsDead) to know when a player is dead
InfoMessage(s);
}
+ MUTATOR_CALLHOOK(DrawInfoMessages, pos, mySize);
+
if(!warmup_stage && gametype == MAPINFO_TYPE_LMS)
{
entity sk;
mod_active = 1; // keyhunt should never hide the mod icons panel
// Read current state
-
int state = STAT(KH_KEYS);
+ if(!state) return;
+
int i, key_state;
int all_keys, team1_keys, team2_keys, team3_keys, team4_keys, dropped_keys, carrying_keys;
all_keys = team1_keys = team2_keys = team3_keys = team4_keys = dropped_keys = carrying_keys = 0;
}
// Calculate slot measurements
-
vector slot_size;
-
if(all_keys == 4 && mySize.x * 0.5 < mySize.y && mySize.y * 0.5 < mySize.x)
{
// Quadratic arrangement
// Make icons blink in case of RUN HERE
- float blink = 0.6 + sin(2*M_PI*time) / 2.5; // Oscillate between 0.2 and 1
- float alpha;
- alpha = 1;
-
+ float alpha = 1;
if(carrying_keys)
+ {
+ float blink = 0.6 + sin(2 * M_PI * time) * 0.4; // Oscillate between 0.2 and 1
switch(myteam)
{
case NUM_TEAM_1: if(team1_keys == all_keys) alpha = blink; break;
case NUM_TEAM_3: if(team3_keys == all_keys) alpha = blink; break;
case NUM_TEAM_4: if(team4_keys == all_keys) alpha = blink; break;
}
+ }
// Draw icons
{
int allItems = STAT(ITEMS);
int allBuffs = STAT(BUFFS);
- int strengthTime, shieldTime, superTime;
+ float strengthTime, shieldTime, superTime;
// Initialize items
if(!autocvar__hud_configure)
return;
if(STAT(HEALTH) <= 0 && autocvar_hud_panel_powerups_hide_ondeath)
return;
- if(!(allItems & (ITEM_Strength.m_itemid | ITEM_Shield.m_itemid | IT_SUPERWEAPON)) && !allBuffs) return;
+ //if(!(allItems & (ITEM_Strength.m_itemid | ITEM_Shield.m_itemid | IT_SUPERWEAPON)) && !allBuffs) return;
strengthTime = bound(0, STAT(STRENGTH_FINISHED) - time, 99);
shieldTime = bound(0, STAT(INVINCIBLE_FINISHED) - time, 99);
else
{
vector c0, c1, c2, c3, span;
- c0 = rotate(mi_min, teamradar_angle * DEG2RAD);
- c1 = rotate(mi_max, teamradar_angle * DEG2RAD);
- c2 = rotate('1 0 0' * mi_min.x + '0 1 0' * mi_max.y, teamradar_angle * DEG2RAD);
- c3 = rotate('1 0 0' * mi_max.x + '0 1 0' * mi_min.y, teamradar_angle * DEG2RAD);
+ c0 = Rotate(mi_min, teamradar_angle * DEG2RAD);
+ c1 = Rotate(mi_max, teamradar_angle * DEG2RAD);
+ c2 = Rotate('1 0 0' * mi_min.x + '0 1 0' * mi_max.y, teamradar_angle * DEG2RAD);
+ c3 = Rotate('1 0 0' * mi_max.x + '0 1 0' * mi_min.y, teamradar_angle * DEG2RAD);
span = '0 0 0';
span.x = max(c0_x, c1_x, c2_x, c3_x) - min(c0_x, c1_x, c2_x, c3_x);
span.y = max(c0_y, c1_y, c2_y, c3_y) - min(c0_y, c1_y, c2_y, c3_y);
}
vector timer_color;
- if(gameover_time || minutesLeft >= 5 || warmup_stage || timelimit == 0)
+ if(intermission_time || minutesLeft >= 5 || warmup_stage || timelimit == 0)
timer_color = '1 1 1'; //white
else if(minutesLeft >= 1)
timer_color = '1 1 0'; //yellow
else
timer_color = '1 0 0'; //red
- if (gameover_time) {
- timer = seconds_tostring(max(0, floor(gameover_time - STAT(GAMESTARTTIME))));
+ if (intermission_time) {
+ timer = seconds_tostring(max(0, floor(intermission_time - STAT(GAMESTARTTIME))));
} else if (autocvar_hud_panel_timer_increment || (!warmup_stage && timelimit == 0) || (warmup_stage && warmup_timeleft <= 0)) {
if (time < STAT(GAMESTARTTIME))
timer = seconds_tostring(0); //while restart is still active, show 00:00
float PreviewExists(string name);
-vector rotate(vector v, float a);
+vector Rotate(vector v, float a);
#define IS_DEAD(s) (((s).classname == "csqcmodel") ? (s).csqcmodel_isdead : ((s).health <= 0))
/** Return true to not draw scoreboard */
MUTATOR_HOOKABLE(DrawScoreboard, EV_NO_ARGS);
+
+/** Called when drawing info messages, allows adding new info messages */
+#define EV_DrawInfoMessages(i, o) \
+ /** pos */ i(vector, MUTATOR_ARGV_0_vector) \
+ /** mySize */ i(vector, MUTATOR_ARGV_1_vector) \
+ /**/
+MUTATOR_HOOKABLE(DrawInfoMessages, EV_DrawInfoMessages);
vector out;
in -= teamradar_origin3d_in_texcoord;
- out = rotate(in, teamradar_angle * DEG2RAD);
+ out = Rotate(in, teamradar_angle * DEG2RAD);
out.y = - out.y; // screen space is reversed
out = out * teamradar_size;
out = out / teamradar_size;
out_y = - out_y; // screen space is reversed
- out = rotate(out, -teamradar_angle * DEG2RAD);
+ out = Rotate(out, -teamradar_angle * DEG2RAD);
out += teamradar_origin3d_in_texcoord;
{
if(autocvar_cl_orthoview)
return false;
- if(intermission)
+ if(STAT(GAMEOVER) || intermission)
return true;
if(this.viewloc)
return true;
{
float f, i, j;
vector v;
- if(!scoreboard_active && !camera_active && intermission != 2 &&
+ if(!scoreboard_active && !camera_active && intermission != 2 && !STAT(GAMEOVER) &&
spectatee_status != -1 && !csqcplayer.viewloc && !MUTATOR_CALLHOOK(DrawCrosshair) &&
!HUD_MinigameMenu_IsOpened() )
{
if(!postinit)
PostInit();
- if(intermission && !gameover_time)
- gameover_time = time;
+ if(intermission && !intermission_time)
+ intermission_time = time;
if(intermission && !isdemo() && !(calledhooks & HOOK_END))
{
#endif
return output;
}
+
+string Item_Sound(string it_snd)
+{
+ string output = strcat("misc/", it_snd);
+#ifdef SVQC
+ MUTATOR_CALLHOOK(ItemSound, it_snd, output);
+ return M_ARGV(1, string);
+#else
+ return output;
+#endif
+}
#ifdef GAMEQC
MODEL(ArmorSmall_ITEM, Item_Model("item_armor_small.md3"));
-SOUND(ArmorSmall, "misc/armor1");
+SOUND(ArmorSmall, Item_Sound("armor1"));
#endif
REGISTER_ITEM(ArmorSmall, Armor) {
#ifdef GAMEQC
MODEL(ArmorMedium_ITEM, Item_Model("item_armor_medium.md3"));
-SOUND(ArmorMedium, "misc/armor10");
+SOUND(ArmorMedium, Item_Sound("armor10"));
#endif
REGISTER_ITEM(ArmorMedium, Armor) {
}
#ifdef GAMEQC
-MODEL(ArmorLarge_ITEM, Item_Model("item_armor_big.md3"));
-SOUND(ArmorLarge, "misc/armor17_5");
+MODEL(ArmorBig_ITEM, Item_Model("item_armor_big.md3"));
+SOUND(ArmorBig, Item_Sound("armor17_5"));
#endif
-REGISTER_ITEM(ArmorLarge, Armor) {
+REGISTER_ITEM(ArmorBig, Armor) {
#ifdef GAMEQC
- this.m_model = MDL_ArmorLarge_ITEM;
- this.m_sound = SND_ArmorLarge;
+ this.m_model = MDL_ArmorBig_ITEM;
+ this.m_sound = SND_ArmorBig;
#endif
this.m_name = "50 Armor";
this.m_icon = "armor";
this.m_color = '0 1 0';
- this.m_waypoint = _("Large armor");
+ this.m_waypoint = _("Big armor");
#ifdef SVQC
this.m_botvalue = 20000; // FIXME: higher than BOT_PICKUP_RATING_HIGH?
this.m_itemid = IT_ARMOR;
#ifdef GAMEQC
MODEL(ArmorMega_ITEM, Item_Model("item_armor_large.md3"));
-SOUND(ArmorMega, "misc/armor25");
+SOUND(ArmorMega, Item_Sound("armor25"));
#endif
REGISTER_ITEM(ArmorMega, Armor) {
#ifdef GAMEQC
MODEL(HealthSmall_ITEM, Item_Model("g_h1.md3"));
-SOUND(HealthSmall, "misc/minihealth");
+SOUND(HealthSmall, Item_Sound("minihealth"));
#endif
REGISTER_ITEM(HealthSmall, Health) {
#ifdef GAMEQC
MODEL(HealthMedium_ITEM, Item_Model("g_h25.md3"));
-SOUND(HealthMedium, "misc/mediumhealth");
+SOUND(HealthMedium, Item_Sound("mediumhealth"));
#endif
REGISTER_ITEM(HealthMedium, Health) {
}
#ifdef GAMEQC
-MODEL(HealthLarge_ITEM, Item_Model("g_h50.md3"));
-SOUND(HealthLarge, "misc/mediumhealth");
+MODEL(HealthBig_ITEM, Item_Model("g_h50.md3"));
+SOUND(HealthBig, Item_Sound("mediumhealth"));
#endif
-REGISTER_ITEM(HealthLarge, Health) {
+REGISTER_ITEM(HealthBig, Health) {
#ifdef GAMEQC
- this.m_model = MDL_HealthLarge_ITEM;
- this.m_sound = SND_HealthLarge;
+ this.m_model = MDL_HealthBig_ITEM;
+ this.m_sound = SND_HealthBig;
#endif
this.m_name = "50 Health";
this.m_icon = "health";
this.m_color = '1 0 0';
- this.m_waypoint = _("Large health");
+ this.m_waypoint = _("Big health");
#ifdef SVQC
this.m_botvalue = BOT_PICKUP_RATING_MID;
this.m_itemid = IT_25HP;
#ifdef GAMEQC
MODEL(HealthMega_ITEM, Item_Model("g_h100.md3"));
-SOUND(HealthMega, "misc/megahealth");
+SOUND(HealthMega, Item_Sound("megahealth"));
#endif
REGISTER_ITEM(HealthMega, Health) {
#ifdef GAMEQC
MODEL(Strength_ITEM, Item_Model("g_strength.md3"));
-SOUND(Strength, "misc/powerup");
+SOUND(Strength, Item_Sound("powerup"));
#endif
REGISTER_ITEM(Strength, Powerup) {
#ifdef GAMEQC
MODEL(Shield_ITEM, Item_Model("g_invincible.md3"));
-SOUND(Shield, "misc/powerup_shield");
+SOUND(Shield, Item_Sound("powerup_shield"));
#endif
REGISTER_ITEM(Shield, Powerup) {
#endif
#ifdef SVQC
.float speed;
-spawnfunc(item_health_large);
+spawnfunc(item_health_big);
METHOD(Mage, mr_setup, bool(Mage this, entity actor))
{
TC(Mage, this);
if(!actor.stopspeed) { actor.stopspeed = (autocvar_g_monster_mage_speed_stop); }
if(!actor.damageforcescale) { actor.damageforcescale = (autocvar_g_monster_mage_damageforcescale); }
- actor.monster_loot = spawnfunc_item_health_large;
+ actor.monster_loot = spawnfunc_item_health_big;
actor.monster_attackfunc = M_Mage_Attack;
return true;
if(!this.candrop || !this.monster_loot)
return;
- vector org = this.origin + ((this.mins + this.maxs) * 0.5);
+ vector org = CENTER_OR_VIEWOFS(this);
entity e = new(droppedweapon); // use weapon handling to remove it on touch
e.spawnfunc_checked = true;
if((targ == this)
|| (autocvar_g_monsters_lineofsight && !checkpvs(this.origin + this.view_ofs, targ)) // enemy cannot be seen
- || (IS_VEHICLE(targ) && !((get_monsterinfo(this.monsterid)).spawnflags & MON_FLAG_RANGED)) // melee vs vehicle is useless
+ || (IS_VEHICLE(targ) && !((Monsters_from(this.monsterid)).spawnflags & MON_FLAG_RANGED)) // melee vs vehicle is useless
|| (time < game_starttime) // monsters do nothing before match has started
|| (targ.takedamage == DAMAGE_NO)
|| (targ.items & IT_INVISIBILITY)
if(autocvar_g_monsters_target_infront || (this.spawnflags & MONSTERFLAG_INFRONT))
if(this.enemy != targ)
{
- float dot;
-
makevectors (this.angles);
- dot = normalize (targ.origin - this.origin) * v_forward;
+ float dot = normalize (targ.origin - this.origin) * v_forward;
if(dot <= autocvar_g_monsters_target_infront_range) { return false; }
}
return true; // this target is valid!
}
-entity Monster_FindTarget(entity mon)
+entity Monster_FindTarget(entity this)
{
- if(MUTATOR_CALLHOOK(MonsterFindTarget)) { return mon.enemy; } // Handled by a mutator
+ if(MUTATOR_CALLHOOK(MonsterFindTarget)) { return this.enemy; } // Handled by a mutator
entity closest_target = NULL;
+ vector my_center = CENTER_OR_VIEWOFS(this);
// find the closest acceptable target to pass to
- FOREACH_ENTITY_RADIUS(mon.origin, mon.target_range, it.monster_attack,
+ FOREACH_ENTITY_RADIUS(this.origin, this.target_range, it.monster_attack,
{
- if(Monster_ValidTarget(mon, it))
+ if(Monster_ValidTarget(this, it))
{
// if it's a player, use the view origin as reference (stolen from RadiusDamage functions in g_damage.qc)
- vector head_center = CENTER_OR_VIEWOFS(it);
- vector ent_center = CENTER_OR_VIEWOFS(mon);
+ vector targ_center = CENTER_OR_VIEWOFS(it);
if(closest_target)
{
vector closest_target_center = CENTER_OR_VIEWOFS(closest_target);
- if(vlen2(ent_center - head_center) < vlen2(ent_center - closest_target_center))
+ if(vlen2(my_center - targ_center) < vlen2(my_center - closest_target_center))
{ closest_target = it; }
}
else { closest_target = it; }
return closest_target;
}
-void monster_setupcolors(entity mon)
+void monster_setupcolors(entity this)
{
- if(IS_PLAYER(mon.realowner))
- mon.colormap = mon.realowner.colormap;
- else if(teamplay && mon.team)
- mon.colormap = 1024 + (mon.team - 1) * 17;
+ if(IS_PLAYER(this.realowner))
+ this.colormap = this.realowner.colormap;
+ else if(teamplay && this.team)
+ this.colormap = 1024 + (this.team - 1) * 17;
else
{
- if(mon.monster_skill <= MONSTER_SKILL_EASY)
- mon.colormap = 1029;
- else if(mon.monster_skill <= MONSTER_SKILL_MEDIUM)
- mon.colormap = 1027;
- else if(mon.monster_skill <= MONSTER_SKILL_HARD)
- mon.colormap = 1038;
- else if(mon.monster_skill <= MONSTER_SKILL_INSANE)
- mon.colormap = 1028;
- else if(mon.monster_skill <= MONSTER_SKILL_NIGHTMARE)
- mon.colormap = 1032;
+ if(this.monster_skill <= MONSTER_SKILL_EASY)
+ this.colormap = 1029;
+ else if(this.monster_skill <= MONSTER_SKILL_MEDIUM)
+ this.colormap = 1027;
+ else if(this.monster_skill <= MONSTER_SKILL_HARD)
+ this.colormap = 1038;
+ else if(this.monster_skill <= MONSTER_SKILL_INSANE)
+ this.colormap = 1028;
+ else if(this.monster_skill <= MONSTER_SKILL_NIGHTMARE)
+ this.colormap = 1032;
else
- mon.colormap = 1024;
+ this.colormap = 1024;
}
}
-void monster_changeteam(entity ent, float newteam)
+void monster_changeteam(entity this, int newteam)
{
if(!teamplay) { return; }
- ent.team = newteam;
- ent.monster_attack = true; // new team, activate attacking
- monster_setupcolors(ent);
+ this.team = newteam;
+ this.monster_attack = true; // new team, activate attacking
+ monster_setupcolors(this);
- if(ent.sprite)
+ if(this.sprite)
{
- WaypointSprite_UpdateTeamRadar(ent.sprite, RADARICON_DANGER, ((newteam) ? Team_ColorRGB(newteam) : '1 0 0'));
+ WaypointSprite_UpdateTeamRadar(this.sprite, RADARICON_DANGER, ((newteam) ? Team_ColorRGB(newteam) : '1 0 0'));
- ent.sprite.team = newteam;
- ent.sprite.SendFlags |= 1;
+ this.sprite.team = newteam;
+ this.sprite.SendFlags |= 1;
}
}
bool Monster_Sounds_Load(entity this, string f, int first)
{
- float fh;
string s;
var .string field;
- fh = fopen(f, FILE_READ);
+ float fh = fopen(f, FILE_READ);
if(fh < 0)
{
LOG_TRACE("Monster sound file not found: ", f);
Monster_Sounds_Load(this, get_monster_model_datafilename(this.model, 0, "sounds"), 0);
}
-void Monster_Sound(entity this, .string samplefield, float sound_delay, float delaytoo, float chan)
+void Monster_Sound(entity this, .string samplefield, float sound_delay, bool delaytoo, float chan)
{
if(!autocvar_g_monsters_sounds) { return; }
this.velocity = vel;
tracetoss(this, this);
this.velocity = old;
- if (trace_ent != this.enemy)
+ if(trace_ent != this.enemy)
return false;
return true;
setanim(this, anm, false, true, false);
- if(this.animstate_endtime > time && (this.flags & FL_MONSTER))
+ if(this.animstate_endtime > time && IS_MONSTER(this))
this.attack_finished_single[0] = this.anim_finished = this.animstate_endtime;
else
this.attack_finished_single[0] = this.anim_finished = time + animtime;
- if(this.flags & FL_MONSTER)
+ if(IS_MONSTER(this))
this.state = MONSTER_ATTACK_RANGED;
settouch(this, touchfunc);
this.origin_z += 1;
void Monster_Attack_Check(entity this, entity targ)
{
- if((this == NULL || targ == NULL)
+ if((!this || !targ)
|| (!this.monster_attackfunc)
|| (time < this.attack_finished_single[0])
) { return; }
if(vdist(targ.origin - this.origin, <=, this.attack_range))
{
- bool attack_success = this.monster_attackfunc(MONSTER_ATTACK_MELEE, this, targ);
+ int attack_success = this.monster_attackfunc(MONSTER_ATTACK_MELEE, this, targ);
if(attack_success == 1)
Monster_Sound(this, monstersound_melee, 0, false, CH_VOICE);
else if(attack_success > 0)
if(vdist(targ.origin - this.origin, >, this.attack_range))
{
- float attack_success = this.monster_attackfunc(MONSTER_ATTACK_RANGED, this, targ);
+ int attack_success = this.monster_attackfunc(MONSTER_ATTACK_RANGED, this, targ);
if(attack_success == 1)
Monster_Sound(this, monstersound_melee, 0, false, CH_VOICE);
else if(attack_success > 0)
this.anim_die2 = animfixfps(this, '9 1 0.01', '0 0 0');*/
// then get the real values
- Monster mon = get_monsterinfo(this.monsterid);
+ Monster mon = Monsters_from(this.monsterid);
mon.mr_anim(mon, this);
}
targ_origin = WarpZone_RefSys_TransformOrigin(this.enemy, this, targ_origin); // origin of target as seen by the monster (us)
WarpZone_TraceLine(this.origin, targ_origin, MOVE_NOMONSTERS, this);
- if((this.enemy == NULL)
+ // cases where the enemy may have changed their state (don't need to check everything here)
+ if((!this.enemy)
|| (IS_DEAD(this.enemy) || this.enemy.health < 1)
|| (STAT(FROZEN, this.enemy))
|| (this.enemy.flags & FL_NOTARGET)
// update goal entity if lost
if(this.target2 && this.goalentity.targetname != this.target2) { this.goalentity = find(NULL, targetname, this.target2); }
- entity targ;
-
if(STAT(FROZEN, this) == 2)
{
this.revive_progress = bound(0, this.revive_progress + this.ticrate * this.revive_speed, 1);
}
}
- targ = this.goalentity;
+ entity targ = this.goalentity;
if (MUTATOR_CALLHOOK(MonsterMove, this, runspeed, walkspeed, targ)
|| gameover
runspeed = bound(0, M_ARGV(1, float) * MONSTER_SKILLMOD(this), runspeed * 2.5); // limit maxspeed to prevent craziness
walkspeed = bound(0, M_ARGV(2, float) * MONSTER_SKILLMOD(this), walkspeed * 2.5); // limit maxspeed to prevent craziness
- if(teamplay)
- if(autocvar_g_monsters_teams)
+ if(teamplay && autocvar_g_monsters_teams)
if(DIFF_TEAM(this.monster_follow, this))
this.monster_follow = NULL;
if(vdist(this.origin - this.moveto, >, 100))
{
- float do_run = (this.enemy || this.monster_moveto);
+ bool do_run = (this.enemy || this.monster_moveto);
if(IS_ONGROUND(this) || ((this.flags & FL_FLY) || (this.flags & FL_SWIM)))
Monster_CalculateVelocity(this, this.moveto, this.origin, true, ((do_run) ? runspeed : walkspeed));
- if(time > this.pain_finished) // TODO: use anim_finished instead!
+ if(time > this.pain_finished && time > this.anim_finished) // TODO: use anim_finished instead!?
if(!this.state)
- if(time > this.anim_finished)
if(vdist(this.velocity, >, 10))
setanim(this, ((do_run) ? this.anim_run : this.anim_walk), true, false, false);
else
this.target2 = e.target;
movelib_brake_simple(this, stpspeed);
- if(time > this.anim_finished)
- if(time > this.pain_finished)
+ if(time > this.anim_finished && time > this.pain_finished)
if(!this.state)
if(vdist(this.velocity, <=, 30))
setanim(this, this.anim_idle, true, false, false);
CSQCModel_UnlinkEntity(this);
- Monster mon = get_monsterinfo(this.monsterid);
+ Monster mon = Monsters_from(this.monsterid);
mon.mr_death(mon, this);
if(this.candrop && this.weapon)
if(deathtype == DEATH_FALL.m_id && this.draggedby != NULL)
return;
- vector v;
- float take, save;
-
- v = healtharmor_applydamage(100, this.armorvalue / 100, deathtype, damage);
- take = v_x;
- save = v_y;
+ vector v = healtharmor_applydamage(100, this.armorvalue / 100, deathtype, damage);
+ float take = v.x;
+ //float save = v.y;
- Monster mon = get_monsterinfo(this.monsterid);
+ Monster mon = Monsters_from(this.monsterid);
take = mon.mr_pain(mon, this, take, attacker, deathtype);
if(take)
movelib_move_simple_gravity(this, v_forward, mspeed, 1);
- if(time > this.pain_finished)
- if(time > this.attack_finished_single[0])
+ if(time > this.pain_finished && time > this.attack_finished_single[0])
if(vdist(this.velocity, >, 10))
setanim(this, this.anim_walk, true, false, false);
else
setthink(this, Monster_Think);
this.nextthink = time + this.ticrate;
- if(this.monster_lifetime)
- if(time >= this.monster_lifetime)
+ if(this.monster_lifetime && time >= this.monster_lifetime)
{
Damage(this, this, this, this.health + this.max_health, DEATH_KILL.m_id, this.origin, this.origin);
return;
}
- Monster mon = get_monsterinfo(this.monsterid);
+ Monster mon = Monsters_from(this.monsterid);
if(mon.mr_think(mon, this))
Monster_Move(this, this.speed2, this.speed, this.stopspeed);
#ifdef GAMEQC
MODEL(VaporizerCells_ITEM, Item_Model("a_cells.md3"));
-SOUND(VaporizerCells, "misc/itempickup");
+SOUND(VaporizerCells, Item_Sound("itempickup"));
#endif
REGISTER_ITEM(VaporizerCells, Ammo) {
#ifdef GAMEQC
MODEL(ExtraLife_ITEM, Item_Model("g_h100.md3"));
-SOUND(ExtraLife, "misc/megahealth");
+SOUND(ExtraLife, Item_Sound("megahealth"));
#endif
REGISTER_ITEM(ExtraLife, Powerup) {
#ifdef GAMEQC
MODEL(Invisibility_ITEM, Item_Model("g_strength.md3"));
-SOUND(Invisibility, "misc/powerup");
+SOUND(Invisibility, Item_Sound("powerup"));
#endif
REGISTER_ITEM(Invisibility, Powerup) {
#ifdef GAMEQC
MODEL(Speed_ITEM, Item_Model("g_invincible.md3"));
-SOUND(Speed, "misc/powerup_shield");
+SOUND(Speed, Item_Sound("powerup_shield"));
#endif
REGISTER_ITEM(Speed, Powerup) {
string autocvar_hud_panel_itemstime_progressbar_name = "progressbar";
float autocvar_hud_panel_itemstime_progressbar_reduced;
bool autocvar_hud_panel_itemstime_hidespawned = 1;
-bool autocvar_hud_panel_itemstime_hidelarge = false;
+bool autocvar_hud_panel_itemstime_hidebig = false;
int autocvar_hud_panel_itemstime_text = 1;
-#define hud_panel_itemstime_hidelarge autocvar_hud_panel_itemstime_hidelarge
+#define hud_panel_itemstime_hidebig autocvar_hud_panel_itemstime_hidebig
#else
-#define hud_panel_itemstime_hidelarge false
+#define hud_panel_itemstime_hidebig false
#endif
bool Item_ItemsTime_SpectatorOnly(GameItem it)
{
return (false
- || it == ITEM_ArmorMega || (it == ITEM_ArmorLarge && !hud_panel_itemstime_hidelarge)
- || it == ITEM_HealthMega || (it == ITEM_HealthLarge && !hud_panel_itemstime_hidelarge)
+ || it == ITEM_ArmorMega || (it == ITEM_ArmorBig && !hud_panel_itemstime_hidebig)
+ || it == ITEM_HealthMega || (it == ITEM_HealthBig && !hud_panel_itemstime_hidebig)
);
}
{
entity player = M_ARGV(0, entity);
- if(!intermission_running)
+ if(!gameover)
if(!IS_DEAD(player))
if(IS_PLAYER(player))
NIX_GiveCurrentWeapon(player);
bool autocvar_g_overkill_filter_healthmega;
bool autocvar_g_overkill_filter_armormedium;
bool autocvar_g_overkill_filter_armorbig;
-bool autocvar_g_overkill_filter_armorlarge;
+bool autocvar_g_overkill_filter_armormega;
.float ok_lastwep;
.float ok_item;
MUTATOR_HOOKFUNCTION(ok, PlayerPreThink)
{
- if(intermission_running || gameover)
+ if(gameover)
return;
entity player = M_ARGV(0, entity);
{
case ITEM_HealthMega: return autocvar_g_overkill_filter_healthmega;
case ITEM_ArmorMedium: return autocvar_g_overkill_filter_armormedium;
- // WARNING: next two statements look wrong because of inconsistency between cvar names and code
- // armor cvars need renaming to be consistent with their health counterparts
- case ITEM_ArmorLarge: return autocvar_g_overkill_filter_armorbig;
- case ITEM_ArmorMega: return autocvar_g_overkill_filter_armorlarge;
+ case ITEM_ArmorBig: return autocvar_g_overkill_filter_armorbig;
+ case ITEM_ArmorMega: return autocvar_g_overkill_filter_armormega;
}
return true;
REGISTER_WAYPOINT(RaceStart, _("Start"), '1 0.5 0', 1);
REGISTER_WAYPOINT(RaceStartFinish, _("Start"), '1 0.5 0', 1);
-REGISTER_WAYPOINT(Assault, _("<placeholder>"), '1 0.5 0', 1);
REGISTER_WAYPOINT(AssaultDefend, _("Defend"), '1 0.5 0', 1);
REGISTER_WAYPOINT(AssaultDestroy, _("Destroy"), '1 0.5 0', 1);
REGISTER_WAYPOINT(AssaultPush, _("Push"), '1 0.5 0', 1);
// rotate them, and make them absolute
rot = -rot; // rotate by the opposite angle, as our coordinate system is reversed
- v1 = rotate(v1, rot) + org;
- v2 = rotate(v2, rot) + org;
- v3 = rotate(v3, rot) + org;
- v4 = rotate(v4, rot) + org;
+ v1 = Rotate(v1, rot) + org;
+ v2 = Rotate(v2, rot) + org;
+ v3 = Rotate(v3, rot) + org;
+ v4 = Rotate(v4, rot) + org;
// draw them
R_BeginPolygon(pic, f);
up = '0 1 0';
rot = -rot; // rotate by the opposite angle, as our coordinate system is reversed
- o = rotate(o, rot) + org;
- ri = rotate(ri, rot);
- up = rotate(up, rot);
+ o = Rotate(o, rot) + org;
+ ri = Rotate(ri, rot);
+ up = Rotate(up, rot);
owidth = width + 2 * border;
o = o - up * (margin + border + theheight) + ri * (sz.x - owidth) * 0.5;
R_BeginPolygon("", DRAWFLAG_NORMAL);
R_PolygonVertex(o, '0 0 0', '0 0 0', a);
- R_PolygonVertex(o + rotate(arrowY - borderX, ang), '0 0 0', '0 0 0', a);
- R_PolygonVertex(o + rotate(borderY - borderX, ang), '0 0 0', '0 0 0', a);
- R_PolygonVertex(o + rotate(borderY + borderX, ang), '0 0 0', '0 0 0', a);
- R_PolygonVertex(o + rotate(arrowY + borderX, ang), '0 0 0', '0 0 0', a);
+ R_PolygonVertex(o + Rotate(arrowY - borderX, ang), '0 0 0', '0 0 0', a);
+ R_PolygonVertex(o + Rotate(borderY - borderX, ang), '0 0 0', '0 0 0', a);
+ R_PolygonVertex(o + Rotate(borderY + borderX, ang), '0 0 0', '0 0 0', a);
+ R_PolygonVertex(o + Rotate(arrowY + borderX, ang), '0 0 0', '0 0 0', a);
R_EndPolygon();
R_BeginPolygon("", DRAWFLAG_ADDITIVE);
- R_PolygonVertex(o + rotate(eY * borderDiag, ang), '0 0 0', rgb, a);
- R_PolygonVertex(o + rotate(arrowY - arrowX, ang), '0 0 0', rgb, a);
- R_PolygonVertex(o + rotate(arrowY + arrowX, ang), '0 0 0', rgb, a);
+ R_PolygonVertex(o + Rotate(eY * borderDiag, ang), '0 0 0', rgb, a);
+ R_PolygonVertex(o + Rotate(arrowY - arrowX, ang), '0 0 0', rgb, a);
+ R_PolygonVertex(o + Rotate(arrowY + arrowX, ang), '0 0 0', rgb, a);
R_EndPolygon();
- return o + rotate(eY * (borderDiag+size+margin), ang);
+ return o + Rotate(eY * (borderDiag+size+margin), ang);
}
// returns location of sprite healthbar
MSG_CENTER_NOTIF(ASSAULT_ATTACKING, 1, 0, 0, "", CPID_ASSAULT_ROLE, "0 0", _("^BGYou are attacking!"), "")
MSG_CENTER_NOTIF(ASSAULT_DEFENDING, 1, 0, 0, "", CPID_ASSAULT_ROLE, "0 0", _("^BGYou are defending!"), "")
+ MSG_CENTER_NOTIF(ASSAULT_OBJ_DESTROYED, 1, 0, 1, "f1time", CPID_ASSAULT_ROLE, "0 0", _("^BGObjective destroyed in ^F4%s^BG!"), "")
MSG_CENTER_NOTIF(COUNTDOWN_BEGIN, 1, 0, 0, "", CPID_ROUND, "2 0", _("^F4Begin!"), "")
MSG_CENTER_NOTIF(COUNTDOWN_GAMESTART, 1, 0, 1, "", CPID_ROUND, "1 f1", _("^F4Game starts in ^COUNT"), "")
#ifdef SVQC
this.pm_frametime = frametime;
+#elif defined(CSQC)
+ if((ITEMS_STAT(this) & IT_USING_JETPACK) && !IS_DEAD(this) && !intermission)
+ this.csqcmodel_modelflags |= MF_ROCKET;
+ else
+ this.csqcmodel_modelflags &= ~MF_ROCKET;
#endif
}
#include "../teams.qh"
string W_Sound(string w_snd);
+string Item_Sound(string it_snd);
SOUND(ARC_FIRE, W_Sound("arc_fire"));
SOUND(ARC_LOOP, W_Sound("arc_loop"));
SOUND(BUFF_LOST, "relics/relic_effect");
-SOUND(POWEROFF, "misc/poweroff");
-SOUND(POWERUP, "misc/powerup");
-SOUND(SHIELD_RESPAWN, "misc/shield_respawn");
-SOUND(STRENGTH_RESPAWN, "misc/strength_respawn");
+SOUND(POWEROFF, Item_Sound("poweroff"));
+SOUND(POWERUP, Item_Sound("powerup"));
+SOUND(SHIELD_RESPAWN, Item_Sound("shield_respawn"));
+SOUND(STRENGTH_RESPAWN, Item_Sound("strength_respawn"));
-SOUND(ARMOR25, "misc/armor25");
+SOUND(ARMOR25, Item_Sound("armor25"));
SOUND(ARMORIMPACT, "misc/armorimpact");
SOUND(BODYIMPACT1, "misc/bodyimpact1");
SOUND(BODYIMPACT2, "misc/bodyimpact2");
-SOUND(ITEMPICKUP, "misc/itempickup");
-SOUND(ITEMRESPAWNCOUNTDOWN, "misc/itemrespawncountdown");
-SOUND(ITEMRESPAWN, "misc/itemrespawn");
-SOUND(MEGAHEALTH, "misc/megahealth");
+SOUND(ITEMPICKUP, Item_Sound("itempickup"));
+SOUND(ITEMRESPAWNCOUNTDOWN, Item_Sound("itemrespawncountdown"));
+SOUND(ITEMRESPAWN, Item_Sound("itemrespawn"));
+SOUND(MEGAHEALTH, Item_Sound("megahealth"));
SOUND(LAVA, "player/lava");
SOUND(SLIME, "player/slime");
REGISTER_STAT(WEAPONS, vectori)
REGISTER_STAT(WEAPONSINMAP, vectori)
-REGISTER_STAT(PL_VIEW_OFS, vector, autocvar_sv_player_viewoffset)
-REGISTER_STAT(PL_CROUCH_VIEW_OFS, vector, autocvar_sv_player_crouch_viewoffset)
+REGISTER_STAT(PL_VIEW_OFS, vector)
+REGISTER_STAT(PL_CROUCH_VIEW_OFS, vector)
-REGISTER_STAT(PL_MIN, vector, autocvar_sv_player_mins)
-REGISTER_STAT(PL_CROUCH_MIN, vector, autocvar_sv_player_crouch_mins)
+REGISTER_STAT(PL_MIN, vector)
+REGISTER_STAT(PL_CROUCH_MIN, vector)
-REGISTER_STAT(PL_MAX, vector, autocvar_sv_player_maxs)
-REGISTER_STAT(PL_CROUCH_MAX, vector, autocvar_sv_player_crouch_maxs)
+REGISTER_STAT(PL_MAX, vector)
+REGISTER_STAT(PL_CROUCH_MAX, vector)
REGISTER_STAT(KH_KEYS, int)
#ifdef SVQC
SPECTATE_COPYFIELD(_STAT(WEAPON_NEXTTHINK))
float W_WeaponRateFactor(entity this);
+float gameover;
#endif
REGISTER_STAT(WEAPONRATEFACTOR, float, W_WeaponRateFactor(this))
-
+REGISTER_STAT(GAMEOVER, int, gameover)
REGISTER_STAT(GAMESTARTTIME, float)
REGISTER_STAT(STRENGTH_FINISHED, float)
REGISTER_STAT(INVINCIBLE_FINISHED, float)
this.max_armorvalue = g_pickup_armorbig_max;
if(!this.pickup_anyway)
this.pickup_anyway = g_pickup_armorbig_anyway;
- StartItem(this, ITEM_ArmorLarge);
+ StartItem(this, ITEM_ArmorBig);
}
-spawnfunc(item_armor_large)
+spawnfunc(item_armor_mega)
{
if(!this.armorvalue)
- this.armorvalue = g_pickup_armorlarge;
+ this.armorvalue = g_pickup_armormega;
if(!this.max_armorvalue)
- this.max_armorvalue = g_pickup_armorlarge_max;
+ this.max_armorvalue = g_pickup_armormega_max;
if(!this.pickup_anyway)
- this.pickup_anyway = g_pickup_armorlarge_anyway;
+ this.pickup_anyway = g_pickup_armormega_anyway;
StartItem(this, ITEM_ArmorMega);
}
StartItem(this, ITEM_HealthMedium);
}
-spawnfunc(item_health_large)
+spawnfunc(item_health_big)
{
if(!this.max_health)
- this.max_health = g_pickup_healthlarge_max;
+ this.max_health = g_pickup_healthbig_max;
if(!this.health)
- this.health = g_pickup_healthlarge;
+ this.health = g_pickup_healthbig;
if(!this.pickup_anyway)
- this.pickup_anyway = g_pickup_healthlarge_anyway;
- StartItem(this, ITEM_HealthLarge);
+ this.pickup_anyway = g_pickup_healthbig_anyway;
+ StartItem(this, ITEM_HealthBig);
}
spawnfunc(item_health_mega)
// support old misnamed entities
spawnfunc(item_armor1) { spawnfunc_item_armor_small(this); } // FIXME: in Quake this is green armor, in Xonotic maps it is an armor shard
-spawnfunc(item_armor25) { spawnfunc_item_armor_large(this); }
+spawnfunc(item_armor25) { spawnfunc_item_armor_mega(this); }
+spawnfunc(item_armor_large) { spawnfunc_item_armor_mega(this); }
spawnfunc(item_health1) { spawnfunc_item_health_small(this); }
spawnfunc(item_health25) { spawnfunc_item_health_medium(this); }
+spawnfunc(item_health_large) { spawnfunc_item_health_big(this); }
spawnfunc(item_health100) { spawnfunc_item_health_mega(this); }
spawnfunc(item_strength)
return sdir * vs + '0 0 1' * vz;
}
-void trigger_push_touch(entity this, entity toucher)
+bool jumppad_push(entity this, entity targ)
{
- if (this.active == ACTIVE_NOT)
- return;
-
- if (!isPushable(toucher))
- return;
-
- if(this.team)
- if(((this.spawnflags & 4) == 0) == (DIFF_TEAM(this, toucher)))
- return;
-
- EXACTTRIGGER_TOUCH(this, toucher);
+ if (!isPushable(targ))
+ return false;
if(this.enemy)
{
- toucher.velocity = trigger_push_calculatevelocity(toucher.origin, this.enemy, this.height);
+ targ.velocity = trigger_push_calculatevelocity(targ.origin, this.enemy, this.height);
}
else if(this.target && this.target != "")
{
else
RandomSelection_AddEnt(e, 1, 1);
}
- toucher.velocity = trigger_push_calculatevelocity(toucher.origin, RandomSelection_chosen_ent, this.height);
+ targ.velocity = trigger_push_calculatevelocity(targ.origin, RandomSelection_chosen_ent, this.height);
}
else
{
- toucher.velocity = this.movedir;
+ targ.velocity = this.movedir;
}
- UNSET_ONGROUND(toucher);
+ UNSET_ONGROUND(targ);
#ifdef CSQC
- if (toucher.flags & FL_PROJECTILE)
+ if (targ.flags & FL_PROJECTILE)
{
- toucher.angles = vectoangles (toucher.velocity);
- switch(toucher.move_movetype)
+ targ.angles = vectoangles (targ.velocity);
+ switch(targ.move_movetype)
{
case MOVETYPE_FLY:
- set_movetype(toucher, MOVETYPE_TOSS);
- toucher.gravity = 1;
+ set_movetype(targ, MOVETYPE_TOSS);
+ targ.gravity = 1;
break;
case MOVETYPE_BOUNCEMISSILE:
- set_movetype(toucher, MOVETYPE_BOUNCE);
- toucher.gravity = 1;
+ set_movetype(targ, MOVETYPE_BOUNCE);
+ targ.gravity = 1;
break;
}
}
#endif
#ifdef SVQC
- if (IS_PLAYER(toucher))
+ if (IS_PLAYER(targ))
{
// reset tracking of oldvelocity for impact damage (sudden velocity changes)
- toucher.oldvelocity = toucher.velocity;
+ targ.oldvelocity = targ.velocity;
if(this.pushltime < time) // prevent "snorring" sound when a player hits the jumppad more than once
{
// flash when activated
- Send_Effect(EFFECT_JUMPPAD, toucher.origin, toucher.velocity, 1);
- _sound (toucher, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
+ Send_Effect(EFFECT_JUMPPAD, targ.origin, targ.velocity, 1);
+ _sound (targ, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
this.pushltime = time + 0.2;
}
- if(IS_REAL_CLIENT(toucher) || IS_BOT_CLIENT(toucher))
+ if(IS_REAL_CLIENT(targ) || IS_BOT_CLIENT(targ))
{
bool found = false;
- for(int i = 0; i < toucher.jumppadcount && i < NUM_JUMPPADSUSED; ++i)
- if(toucher.(jumppadsused[i]) == this)
+ for(int i = 0; i < targ.jumppadcount && i < NUM_JUMPPADSUSED; ++i)
+ if(targ.(jumppadsused[i]) == this)
found = true;
if(!found)
{
- toucher.(jumppadsused[toucher.jumppadcount % NUM_JUMPPADSUSED]) = this;
- toucher.jumppadcount = toucher.jumppadcount + 1;
+ targ.(jumppadsused[targ.jumppadcount % NUM_JUMPPADSUSED]) = this;
+ targ.jumppadcount = targ.jumppadcount + 1;
}
- if(IS_REAL_CLIENT(toucher))
+ if(IS_REAL_CLIENT(targ))
{
if(this.message)
- centerprint(toucher, this.message);
+ centerprint(targ, this.message);
}
else
- toucher.lastteleporttime = time;
+ targ.lastteleporttime = time;
- if (!IS_DEAD(toucher))
- animdecide_setaction(toucher, ANIMACTION_JUMP, true);
+ if (!IS_DEAD(targ))
+ animdecide_setaction(targ, ANIMACTION_JUMP, true);
}
else
- toucher.jumppadcount = true;
+ targ.jumppadcount = true;
// reset tracking of who pushed you into a hazard (for kill credit)
- toucher.pushltime = 0;
- toucher.istypefrag = 0;
+ targ.pushltime = 0;
+ targ.istypefrag = 0;
}
if(this.enemy.target)
- SUB_UseTargets(this.enemy, toucher, toucher); // TODO: do we need toucher as trigger too?
+ SUB_UseTargets(this.enemy, targ, targ); // TODO: do we need targ as trigger too?
- if (toucher.flags & FL_PROJECTILE)
+ if (targ.flags & FL_PROJECTILE)
{
- toucher.angles = vectoangles (toucher.velocity);
- toucher.com_phys_gravity_factor = 1;
- switch(toucher.move_movetype)
+ targ.angles = vectoangles (targ.velocity);
+ targ.com_phys_gravity_factor = 1;
+ switch(targ.move_movetype)
{
case MOVETYPE_FLY:
- set_movetype(toucher, MOVETYPE_TOSS);
- toucher.gravity = 1;
+ set_movetype(targ, MOVETYPE_TOSS);
+ targ.gravity = 1;
break;
case MOVETYPE_BOUNCEMISSILE:
- set_movetype(toucher, MOVETYPE_BOUNCE);
- toucher.gravity = 1;
+ set_movetype(targ, MOVETYPE_BOUNCE);
+ targ.gravity = 1;
break;
}
- UpdateCSQCProjectile(toucher);
+ UpdateCSQCProjectile(targ);
}
+#endif
- /*if (toucher.flags & FL_ITEM)
- {
- ItemUpdate(toucher);
- toucher.SendFlags |= ISF_DROP;
- }*/
+ return true;
+}
+
+void trigger_push_touch(entity this, entity toucher)
+{
+ if (this.active == ACTIVE_NOT)
+ return;
- if (this.spawnflags & PUSH_ONCE)
+ if(this.team)
+ if(((this.spawnflags & 4) == 0) == (DIFF_TEAM(this, toucher)))
+ return;
+
+ EXACTTRIGGER_TOUCH(this, toucher);
+
+ noref bool success = jumppad_push(this, toucher);
+
+#ifdef SVQC
+ if (success && (this.spawnflags & PUSH_ONCE))
{
settouch(this, func_null);
setthink(this, SUB_Remove);
#endif
void trigger_push_findtarget(entity this)
{
- entity t;
- vector org;
-
// first calculate a typical start point for the jump
- org = (this.absmin + this.absmax) * 0.5;
+ vector org = (this.absmin + this.absmax) * 0.5;
org_z = this.absmax.z - STAT(PL_MIN, NULL).z;
if (this.target)
{
- float n = 0;
- for(t = NULL; (t = find(t, targetname, this.target)); )
+ int n = 0;
+ for(entity t = NULL; (t = find(t, targetname, this.target)); )
{
++n;
#ifdef SVQC
delete(e);
}
- trigger_push_link(this);
defer(this, 0.1, trigger_push_updatelink);
#endif
}
this.noise = "misc/jumppad.wav";
precache_sound (this.noise);
+ trigger_push_link(this); // link it now
+
// this must be called to spawn the teleport waypoints for bots
InitializeEntity(this, trigger_push_findtarget, INITPRIO_FINDTARGET);
}
return true;
}
+void target_push_use(entity this, entity actor, entity trigger)
+{
+ jumppad_push(this, actor);
+}
+
void target_push_link(entity this)
{
BITSET_ASSIGN(this.effects, EF_NODEPTHTEST);
target_push_link(this);
}
-spawnfunc(target_push) { target_push_init(this); }
+void target_push_init2(entity this)
+{
+ if(this.target && this.target != "") // we have an old style pusher!
+ {
+ InitializeEntity(this, trigger_push_findtarget, INITPRIO_FINDTARGET);
+ this.use = target_push_use;
+ }
+
+ target_push_init(this); // normal push target behaviour can be combined with a legacy pusher?
+}
+
+spawnfunc(target_push) { target_push_init2(this); }
spawnfunc(info_notnull) { target_push_init(this); }
spawnfunc(target_position) { target_push_init(this); }
entity vehic = this.vehicle;
return = true;
- if(intermission_running)
+ if(gameover)
{
vehic.solid = SOLID_NOT;
vehic.takedamage = DAMAGE_NO;
entity vehic = this.vehicle;
return = true;
- if(intermission_running)
+ if(gameover)
{
vehic.solid = SOLID_NOT;
vehic.takedamage = DAMAGE_NO;
entity vehic = this.vehicle;
return = true;
- if(intermission_running)
+ if(gameover)
{
vehic.solid = SOLID_NOT;
vehic.takedamage = DAMAGE_NO;
entity vehic = this.vehicle;
return = true;
- if(intermission_running)
+ if(gameover)
{
vehic.solid = SOLID_NOT;
vehic.takedamage = DAMAGE_NO;
noref vector _vec3;
#define vec3(_x, _y, _z) (_vec3.x = (_x), _vec3.y = (_y), _vec3.z = (_z), _vec3)
-vector rotate(vector v, float a)
+vector Rotate(vector v, float a)
{
float a_sin = sin(a), a_cos = cos(a);
vector r = '0 0 0';
me.TR(me);
me.TD(me, 1, 4, e = makeXonoticCheckBox(0, "hud_panel_itemstime_hidespawned", _("Hide spawned items")));
me.TR(me);
- me.TD(me, 1, 4, e = makeXonoticCheckBox(0, "hud_panel_itemstime_hidelarge", _("Hide large armor and health")));
+ me.TD(me, 1, 4, e = makeXonoticCheckBox(0, "hud_panel_itemstime_hidebig", _("Hide big armor and health")));
me.TR(me);
me.TD(me, 1, 4, e = makeXonoticCheckBox(0, "hud_panel_itemstime_dynamicsize", _("Dynamic size")));
}
bool bot_fixcount();
void bot_list_commands();
void bot_queuecommand(entity bot, string cmdstring);
+void bot_clear(entity this);
void bot_relinkplayerlist();
void bot_resetqueues();
void bot_serverframe();
void waypoint_spawnforteleporter(entity e, vector destination, float timetaken);
void waypoint_spawnforteleporter_v(entity e, vector org, vector destination, float timetaken);
entity waypoint_spawn(vector m1, vector m2, float f);
+
+.entity goalcurrent;
+void navigation_clearroute(entity this);
void bot_endgame()
{
- entity e;
- //dprint("bot_endgame\n");
- e = bot_list;
+ bot_relinkplayerlist();
+ entity e = bot_list;
while (e)
{
setcolor(e, e.bot_preferredcolors);
this.playerskin_freeme = string_null;
if(this.bot_cmd_current)
delete(this.bot_cmd_current);
- if(bot_waypoint_queue_owner==this)
+ if(bot_waypoint_queue_owner == this)
bot_waypoint_queue_owner = NULL;
}
return true;
}
+void bot_remove_from_bot_list(entity this)
+{
+ entity e = bot_list;
+ entity prev_bot = NULL;
+ while (e)
+ {
+ if(e == this)
+ {
+ if(!prev_bot)
+ bot_list = this.nextbot;
+ else
+ prev_bot.nextbot = this.nextbot;
+ if(bot_strategytoken == this)
+ {
+ bot_strategytoken = this.nextbot;
+ bot_strategytoken_taken = true;
+ }
+ this.nextbot = NULL;
+ break;
+ }
+ prev_bot = e;
+ e = e.nextbot;
+ }
+}
+
+void bot_clear(entity this)
+{
+ bot_remove_from_bot_list(this);
+ if(bot_waypoint_queue_owner == this)
+ bot_waypoint_queue_owner = NULL;
+ this.aistatus &= ~AI_STATUS_STUCK; // otherwise bot_waypoint_queue_owner will be set again to this by navigation_unstuck
+}
+
void bot_serverframe()
{
- if (intermission_running)
+ if (gameover)
return;
if (time < 2)
void bot_custom_weapon_priority_setup();
void bot_endgame();
void bot_relinkplayerlist();
+void bot_clear(entity this);
void bot_clientdisconnect(entity this);
void bot_clientconnect(entity this);
void bot_removefromlargestteam();
if(bot_execute_commands(this))
return;
- if(this.goalcurrent)
- if(wasfreed(this.goalcurrent))
+ while(this.goalcurrent && wasfreed(this.goalcurrent))
+ {
navigation_poproute(this);
+ if(!this.goalcurrent)
+ this.bot_strategytime = 0;
+ }
if (bot_strategytoken == this)
if (!bot_strategytoken_taken)
//heading = this.velocity;
//dprint(this.goalstack01.classname,etos(this.goalstack01),"\n");
if(
- this.goalstack01 != this && this.goalstack01 != NULL && ((this.aistatus & AI_STATUS_RUNNING) == 0) &&
+ this.goalstack01 != this && this.goalstack01 && !wasfreed(this.goalstack01) && ((this.aistatus & AI_STATUS_RUNNING) == 0) &&
!(this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
)
next = ((this.goalstack01.absmin + this.goalstack01.absmax) * 0.5) - (this.origin + this.view_ofs);
if(this.goalcurrent.classname=="waypoint")
if (!(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL))
if(fabs(gco.z - this.origin.z) < this.maxs.z - this.mins.z)
- if(this.goalstack01!=NULL)
+ if(this.goalstack01 && !wasfreed(this.goalstack01))
{
gno = (this.goalstack01.absmin + this.goalstack01.absmax) * 0.5;
deviation = vectoangles(gno - this.origin) - vectoangles(gco - this.origin);
}
// If for some reason the bot is closer to the next goal, pop the current one
- if(this.goalstack01)
+ if(this.goalstack01 && !wasfreed(this.goalstack01))
if(vlen2(this.goalcurrent.origin - this.origin) > vlen2(this.goalstack01.origin - this.origin))
if(checkpvs(this.origin + this.view_ofs, this.goalstack01))
if(tracewalk(this, this.origin, this.mins, this.maxs, (this.goalstack01.absmin + this.goalstack01.absmax) * 0.5, bot_navigation_movemode))
float bot_cmd_continue(entity this)
{
+ bot_relinkplayerlist();
this.bot_exec_status &= ~BOT_EXEC_STATUS_PAUSED;
return CMD_STATUS_FINISHED;
}
this.movement = '0 0 0';
this.bot_cmd_keys = BOT_CMD_KEY_NONE;
+ bot_clear(this);
this.bot_exec_status |= BOT_EXEC_STATUS_PAUSED;
return CMD_STATUS_FINISHED;
}
#include <lib/warpzone/common.qh>
#include <lib/warpzone/util_server.qh>
+void waypoint_setupmodel(entity wp)
+{
+ if (autocvar_g_waypointeditor)
+ {
+ // TODO: add some sort of visible box in edit mode for box waypoints
+ vector m1 = wp.mins;
+ vector m2 = wp.maxs;
+ setmodel(wp, MDL_WAYPOINT);
+ setsize(wp, m1, m2);
+ wp.effects = EF_LOWPRECISION;
+ if (wp.wpflags & WAYPOINTFLAG_ITEM)
+ wp.colormod = '1 0 0';
+ else if (wp.wpflags & WAYPOINTFLAG_GENERATED)
+ wp.colormod = '1 1 0';
+ else
+ wp.colormod = '1 1 1';
+ }
+ else
+ wp.model = "";
+}
+
// create a new spawnfunc_waypoint and automatically link it to other waypoints, and link
// them back to it as well
// (suitable for spawnfunc_waypoint editor)
waypoint_clearlinks(w);
//waypoint_schedulerelink(w);
- if (autocvar_g_waypointeditor)
- {
- m1 = w.mins;
- m2 = w.maxs;
- setmodel(w, MDL_WAYPOINT); w.effects = EF_LOWPRECISION;
- setsize(w, m1, m2);
- if (w.wpflags & WAYPOINTFLAG_ITEM)
- w.colormod = '1 0 0';
- else if (w.wpflags & WAYPOINTFLAG_GENERATED)
- w.colormod = '1 1 0';
- else
- w.colormod = '1 1 1';
- }
- else
- w.model = "";
+ waypoint_setupmodel(w);
return w;
}
{
if (wp == NULL)
return;
- // TODO: add some sort of visible box in edit mode for box waypoints
- if (autocvar_g_waypointeditor)
- {
- vector m1, m2;
- m1 = wp.mins;
- m2 = wp.maxs;
- setmodel(wp, MDL_WAYPOINT); wp.effects = EF_LOWPRECISION;
- setsize(wp, m1, m2);
- if (wp.wpflags & WAYPOINTFLAG_ITEM)
- wp.colormod = '1 0 0';
- else if (wp.wpflags & WAYPOINTFLAG_GENERATED)
- wp.colormod = '1 1 0';
- else
- wp.colormod = '1 1 1';
- }
- else
- wp.model = "";
+
+ waypoint_setupmodel(wp);
wp.wpisbox = vdist(wp.size, >, 0);
wp.enemy = NULL;
if (!(wp.wpflags & WAYPOINTFLAG_PERSONAL))
if (this.killcount != FRAGS_SPECTATOR)
{
Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_SPECTATE, this.netname);
- if(!intermission_running)
- if(autocvar_g_chat_nospectators == 1 || (!(warmup_stage || gameover) && autocvar_g_chat_nospectators == 2))
+ if(!gameover)
+ if(autocvar_g_chat_nospectators == 1 || (!warmup_stage && autocvar_g_chat_nospectators == 2))
Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_CHAT_NOSPECTATORS);
if(this.just_joined == false) {
if (IS_PLAYER(this)) {
CheckRules_Player(this);
- if (intermission_running) {
- IntermissionThink(this);
+ if (gameover || intermission_running) {
+ if(intermission_running)
+ IntermissionThink(this);
return;
}
this.dmg_team = max(0, this.dmg_team - autocvar_g_teamdamage_resetspeed * frametime);
}
- else if (gameover) {
- if (intermission_running) IntermissionThink(this);
+ else if (gameover || intermission_running) {
+ if(intermission_running)
+ IntermissionThink(this);
return;
}
else if (IS_OBSERVER(this)) {
CheatFrame(this);
//CheckPlayerJump();
+ if (gameover)
+ {
+ this.solid = SOLID_NOT;
+ this.takedamage = DAMAGE_NO;
+ set_movetype(this, MOVETYPE_NONE);
+ }
if (IS_PLAYER(this)) {
DrownPlayer(this);
CheckRules_Player(this);
UpdateChatBubble(this);
if (this.impulse) ImpulseCommands(this);
- if (intermission_running) return; // intermission or finale
+ if (gameover)
+ {
+ CSQCMODEL_AUTOUPDATE(this);
+ return;
+ }
GetPressedKeys(this);
}
return sprintf("^7Maps in list: %s\n", maplist);
}
-
+const int LSMAPS_MAX = 250;
string getlsmaps()
{
string lsmaps = "", col;
- float i, newmaps = 0;
+ bool newmaps = false;
+ int added = 0;
- for (i = 0; i < MapInfo_count; ++i)
+ for (int i = 0; i < MapInfo_count; ++i)
{
if ((MapInfo_Get_ByID(i)) && !(MapInfo_Map_flags & MapInfo_ForbiddenFlags()))
{
+ ++added;
+
+ if(added > LSMAPS_MAX)
+ continue; // we still get the added count, but skip the actual processing
+
// todo: Check by play count of maps for other game types?
if (
(g_race && !stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "time"))))
}
}
+ if(added > LSMAPS_MAX)
+ lsmaps = sprintf("%s^7(%d not listed)", lsmaps, added - LSMAPS_MAX);
+
MapInfo_ClearTemps();
- return sprintf("^7Maps available (%d)%s: %s\n", tokenize_console(lsmaps), (newmaps ? " (New maps have asterisks marked in blue)" : ""), lsmaps);
+ return sprintf("^7Maps available (%d)%s: %s\n", added, (newmaps ? " (New maps have asterisks marked in blue)" : ""), lsmaps);
}
string getmonsterlist()
{
- string monsterlist = "", col;
+ string monsterlist = "";
- for (int i = MON_FIRST; i <= MON_LAST; ++i)
+ FOREACH(Monsters, it != MON_Null,
{
- if (i % 2) col = "^2"; else col = "^3";
- monsterlist = sprintf("%s%s%s ", monsterlist, col, (get_monsterinfo(i)).netname);
- }
+ string col = ((i % 2) ? "^2" : "^3");
+ monsterlist = sprintf("%s%s%s ", monsterlist, col, it.netname);
+ });
return sprintf("^7Monsters available: %s\n", monsterlist);
}
}
else
{
- // let's start at token 2 so we can skip sv_cmd bot_cmd
- bot = find_bot_by_number(stof(argv(2)));
- if (bot == NULL) bot = find_bot_by_name(argv(2));
- if (bot) bot_queuecommand(bot, substring(s, argv_start_index(3), -1));
+ if(argv(2) == "*" || argv(2) == "all")
+ FOREACH_CLIENT(IS_BOT_CLIENT(it), {
+ bot_queuecommand(it, substring(s, argv_start_index(3), -1));
+ });
+ else
+ {
+ bot = find_bot_by_number(stof(argv(2)));
+ if (bot == NULL) bot = find_bot_by_name(argv(2));
+ if (bot) bot_queuecommand(bot, substring(s, argv_start_index(3), -1));
+ }
}
}
else
}
else if (argc >= 3) // this comes last
{
- bot = find_bot_by_number(stof(argv(1)));
- if (bot == NULL) bot = find_bot_by_name(argv(1));
- if (bot)
+ if(argv(1) == "*" || argv(1) == "all")
{
- LOG_INFO(strcat("Command '", substring(command, argv_start_index(2), -1), "' sent to bot ", bot.netname, "\n"));
- bot_queuecommand(bot, substring(command, argv_start_index(2), -1));
+ int bot_num = 0;
+ FOREACH_CLIENT(IS_BOT_CLIENT(it), {
+ bot_queuecommand(it, substring(command, argv_start_index(2), -1));
+ bot_num++;
+ });
+ if(bot_num)
+ LOG_INFO(strcat("Command '", substring(command, argv_start_index(2), -1), "' sent to all bots (", ftos(bot_num), ")\n"));
return;
}
else
{
- LOG_INFO(strcat("Error: Can't find bot with the name or id '", argv(1), "' - Did you mistype the command?\n")); // don't return so that usage is shown
+ bot = find_bot_by_number(stof(argv(1)));
+ if (bot == NULL) bot = find_bot_by_name(argv(1));
+ if (bot)
+ {
+ LOG_INFO(strcat("Command '", substring(command, argv_start_index(2), -1), "' sent to bot ", bot.netname, "\n"));
+ bot_queuecommand(bot, substring(command, argv_start_index(2), -1));
+ return;
+ }
+ else
+ {
+ LOG_INFO(strcat("Error: Can't find bot with the name or id '", argv(1), "' - Did you mistype the command?\n")); // don't return so that usage is shown
+ }
}
}
}
case CMD_REQUEST_USAGE:
{
LOG_INFO("\nUsage:^3 sv_cmd bot_cmd client command [argument]\n");
- LOG_INFO(" 'client' can be either the name or entity id of the bot\n");
+ LOG_INFO(" 'client' can be either the name of the bot or a progressive number (not the entity number!)\n");
+ LOG_INFO(" can also be '*' or 'all' to allow sending the command to all the bots\n");
LOG_INFO(" For full list of commands, see bot_cmd help [command].\n");
- LOG_INFO("Examples: sv_cmd bot_cmd client cc \"say something\"\n");
- LOG_INFO(" sv_cmd bot_cmd client presskey jump\n");
+ LOG_INFO("Examples: sv_cmd bot_cmd 1 cc \"say something\"\n");
+ LOG_INFO(" sv_cmd bot_cmd 1 presskey jump\n");
+ LOG_INFO(" sv_cmd bot_cmd * pause\n");
return;
}
}
void ReadyRestart()
{
- // no assault support yet...
- if (g_assault | gameover | intermission_running | race_completing) localcmd("restart\n");
+ if (MUTATOR_CALLHOOK(ReadyRestart_Deny) || gameover || race_completing) localcmd("restart\n");
else localcmd("\nsv_hook_gamerestart\n");
// Reset ALL scores, but only do that at the beginning of the countdown if sv_ready_restart_after_countdown is off!
void weapon_defaultspawnfunc(entity this, Weapon e);
-float gameover;
float intermission_running;
float intermission_exittime;
float alreadychangedlevel;
error("Owner lost the hook!\n");
return;
}
- if(LostMovetypeFollow(this) || intermission_running || (round_handler_IsActive() && !round_handler_IsRoundStarted()) || ((this.aiment.flags & FL_PROJECTILE) && this.aiment.classname != "nade"))
+ if(LostMovetypeFollow(this) || gameover || (round_handler_IsActive() && !round_handler_IsRoundStarted()) || ((this.aiment.flags & FL_PROJECTILE) && this.aiment.classname != "nade"))
{
RemoveGrapplingHook(this.realowner);
return;
void IntermissionThink(entity this)
{
FixIntermissionClient(this);
- CSQCMODEL_AUTOUPDATE(this); // PlayerPostThink returns before calling this during intermission, so run it here
float server_screenshot = (autocvar_sv_autoscreenshot && this.cvar_cl_autoscreenshot);
float client_screenshot = (this.cvar_cl_autoscreenshot == 2);
e.autoscreenshot = time + 0.8; // used for autoscreenshot
e.health = -2342;
// first intermission phase; voting phase has positive health (used to decide whether to send SVC_FINALE or not)
- e.solid = SOLID_NOT;
- set_movetype(e, MOVETYPE_NONE);
- e.takedamage = DAMAGE_NO;
for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{
.entity weaponentity = weaponentities[slot];
intermission_running = 1;
-// enforce a wait time before allowing changelevel
+ // enforce a wait time before allowing changelevel
if(player_count > 0)
intermission_exittime = time + autocvar_sv_mapchange_delay;
else
SetDefaultAlpha();
- if (gameover) // someone else quit the game already
+ if (intermission_running) // someone else quit the game already
{
if(player_count == 0) // Nobody there? Then let's go to the next map
MapVote_Start();
void MapVote_WriteMask()
{
- float i;
if ( mapvote_count < 24 )
{
- float mask,power;
- mask = 0;
- for(i = 0, power = 1; i < mapvote_count; ++i, power *= 2)
- if(mapvote_maps_flags[i] & GTV_AVAILABLE )
- mask |= power;
+ int mask = 0;
+ for(int j = 0; j < mapvote_count; ++j)
+ {
+ if(mapvote_maps_flags[j] & GTV_AVAILABLE)
+ mask |= BIT(j);
+ }
if(mapvote_count < 8)
WriteByte(MSG_ENTITY, mask);
}
else
{
- for ( i = 0; i < mapvote_count; ++i )
- WriteByte(MSG_ENTITY, mapvote_maps_flags[i]);
+ for (int j = 0; j < mapvote_count; ++j)
+ WriteByte(MSG_ENTITY, mapvote_maps_flags[j]);
}
}
string playername(entity p)
{
string t;
- if (teamplay && !intermission_running && IS_PLAYER(p))
+ if (teamplay && !gameover && IS_PLAYER(p))
{
t = Team_ColorCode(p.team);
return strcat(t, strdecolorize(p.netname));
float g_pickup_armorbig;
float g_pickup_armorbig_max;
float g_pickup_armorbig_anyway;
-float g_pickup_armorlarge;
-float g_pickup_armorlarge_max;
-float g_pickup_armorlarge_anyway;
+float g_pickup_armormega;
+float g_pickup_armormega_max;
+float g_pickup_armormega_anyway;
float g_pickup_healthsmall;
float g_pickup_healthsmall_max;
float g_pickup_healthsmall_anyway;
float g_pickup_healthmedium;
float g_pickup_healthmedium_max;
float g_pickup_healthmedium_anyway;
-float g_pickup_healthlarge;
-float g_pickup_healthlarge_max;
-float g_pickup_healthlarge_anyway;
+float g_pickup_healthbig;
+float g_pickup_healthbig_max;
+float g_pickup_healthbig_anyway;
float g_pickup_healthmega;
float g_pickup_healthmega_max;
float g_pickup_healthmega_anyway;
g_pickup_armorbig = cvar("g_pickup_armorbig");
g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
g_pickup_armorbig_anyway = cvar("g_pickup_armorbig_anyway");
- g_pickup_armorlarge = cvar("g_pickup_armorlarge");
- g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
- g_pickup_armorlarge_anyway = cvar("g_pickup_armorlarge_anyway");
+ g_pickup_armormega = cvar("g_pickup_armormega");
+ g_pickup_armormega_max = cvar("g_pickup_armormega_max");
+ g_pickup_armormega_anyway = cvar("g_pickup_armormega_anyway");
g_pickup_healthsmall = cvar("g_pickup_healthsmall");
g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
g_pickup_healthsmall_anyway = cvar("g_pickup_healthsmall_anyway");
g_pickup_healthmedium = cvar("g_pickup_healthmedium");
g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
g_pickup_healthmedium_anyway = cvar("g_pickup_healthmedium_anyway");
- g_pickup_healthlarge = cvar("g_pickup_healthlarge");
- g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
- g_pickup_healthlarge_anyway = cvar("g_pickup_healthlarge_anyway");
+ g_pickup_healthbig = cvar("g_pickup_healthbig");
+ g_pickup_healthbig_max = cvar("g_pickup_healthbig_max");
+ g_pickup_healthbig_anyway = cvar("g_pickup_healthbig_anyway");
g_pickup_healthmega = cvar("g_pickup_healthmega");
g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
g_pickup_healthmega_anyway = cvar("g_pickup_healthmega_anyway");
/**/
MUTATOR_HOOKABLE(ItemModel, EV_ItemModel);
+/** called when an item sound is about to be played, allows custom paths etc. */
+#define EV_ItemSound(i, o) \
+ /** sound */ i(string, MUTATOR_ARGV_0_string) \
+ /** output */ i(string, MUTATOR_ARGV_1_string) \
+ /**/ o(string, MUTATOR_ARGV_1_string) \
+ /**/
+MUTATOR_HOOKABLE(ItemSound, EV_ItemSound);
+
/** called when someone was fragged by "self", and is expected to change frag_score to adjust scoring for the kill */
#define EV_GiveFragsForKill(i, o) \
/** attacker */ i(entity, MUTATOR_ARGV_0_entity) \
/** sender */ i(entity, MUTATOR_ARGV_1_entity) \
/**/
MUTATOR_HOOKABLE(ChatMessageTo, EV_ChatMessageTo);
+
+/** return true to just restart the match, for modes that don't support readyrestart */
+MUTATOR_HOOKABLE(ReadyRestart_Deny, EV_NO_ARGS);
#include "gamemode_assault.qh"
.entity sprite;
+#define AS_ROUND_DELAY 5
// random functions
void assault_objective_use(entity this, entity actor, entity trigger)
it.sprite = NULL; // TODO: just unsetting it?!
}
- spr = WaypointSprite_SpawnFixed(WP_Assault, 0.5 * (it.absmin + it.absmax), it, assault_sprite, RADARICON_OBJECTIVE);
+ spr = WaypointSprite_SpawnFixed(WP_AssaultDefend, 0.5 * (it.absmin + it.absmax), it, assault_sprite, RADARICON_OBJECTIVE);
spr.assault_decreaser = this;
spr.waypointsprite_visible_for_player = assault_decreaser_sprite_visible;
spr.classname = "sprite_waypoint";
});
// reset the level with a countdown
- cvar_set("timelimit", ftos(ceil(time - game_starttime) / 60));
+ cvar_set("timelimit", ftos(ceil(time - AS_ROUND_DELAY - game_starttime) / 60));
ReadyRestart_force(); // sets game_starttime
}
+entity as_round;
+.entity ent_winning;
+void as_round_think()
+{
+ gameover = false;
+ assault_new_round(as_round.ent_winning);
+ delete(as_round);
+ as_round = NULL;
+}
+
// Assault winning condition: If the attackers triggered a round end (by fulfilling all objectives)
// they win. Otherwise the defending team wins once the timelimit passes.
int WinningCondition_Assault()
{
+ if(as_round)
+ return WINNING_NO;
+
WinningConditionHelper(NULL); // set worldstatus
int status = WINNING_NO;
{
if(ent.winning) // round end has been triggered by attacking team
{
- bprint("ASSAULT: round completed...\n");
+ bprint("Assault: round completed.\n");
SetWinners(team, assault_attacker_team);
TeamScore_AddToTeam(assault_attacker_team, ST_ASSAULT_OBJECTIVES, 666 - TeamScore_AddToTeam(assault_attacker_team, ST_ASSAULT_OBJECTIVES, 0));
}
else
{
- assault_new_round(ent);
+ Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ASSAULT_OBJ_DESTROYED, ceil(time - game_starttime));
+ as_round = new(as_round);
+ as_round.think = as_round_think;
+ as_round.ent_winning = ent;
+ as_round.nextthink = time + AS_ROUND_DELAY;
+ gameover = true;
+
+ // make sure timelimit isn't hit while the game is blocked
+ if(autocvar_timelimit > 0)
+ if(time + AS_ROUND_DELAY >= game_starttime + autocvar_timelimit * 60)
+ cvar_set("timelimit", ftos(autocvar_timelimit + AS_ROUND_DELAY / 60));
}
}
}
}
}
+MUTATOR_HOOKFUNCTION(as, ReadyRestart_Deny)
+{
+ // readyrestart not supported (yet)
+ return true;
+}
+
// scoreboard setup
void assault_ScoreRules()
{
PutClientInServer(it);
}
});
+ bot_relinkplayerlist();
return true;
}
frag_target.respawn_flags = RESPAWN_SILENT;
if (!warmup_stage)
eliminatedPlayers.SendFlags |= 1;
+ if(IS_BOT_CLIENT(frag_target))
+ bot_clear(frag_target);
return true;
}
}
}
+bool ctf_Immediate_Return_Allowed(entity flag, entity toucher)
+{
+ int num_perteam = 0;
+ FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(toucher, it), { ++num_perteam; });
+
+ // automatically return if there's only 1 player on the team
+ return ((autocvar_g_ctf_flag_return || num_perteam <= 1 || (autocvar_g_ctf_flag_return_carrying && toucher.flagcarried))
+ && flag.team);
+}
+
bool ctf_Return_Customize(entity this, entity client)
{
// only to the carrier
if(ITEM_DAMAGE_NEEDKILL(deathtype))
{
if(autocvar_g_ctf_flag_return_damage_delay)
- {
- this.ctf_flagdamaged = true;
- }
+ this.ctf_flagdamaged_byworld = true;
else
{
this.health = 0;
LOG_TRACE("wtf the flag got squashed?");
tracebox(this.origin, CTF_FLAG.m_mins, CTF_FLAG.m_maxs, this.origin, MOVE_NOMONSTERS, this);
if(!trace_startsolid || this.noalign) // can we resize it without getting stuck?
- setsize(this, CTF_FLAG.m_mins, CTF_FLAG.m_maxs); }
-
- switch(this.ctf_status) // reset flag angles in case warpzones adjust it
- {
- case FLAG_DROPPED:
- {
- this.angles = '0 0 0';
- break;
- }
-
- default: break;
+ setsize(this, CTF_FLAG.m_mins, CTF_FLAG.m_maxs);
}
// main think method
case FLAG_DROPPED:
{
+ this.angles = '0 0 0'; // reset flag angles in case warpzones adjust it
+
if(autocvar_g_ctf_flag_dropped_floatinwater)
{
vector midpoint = ((this.absmin + this.absmax) * 0.5);
return;
}
}
- if(this.ctf_flagdamaged)
+ if(this.ctf_flagdamaged_byworld)
{
this.health -= ((this.max_flag_health / autocvar_g_ctf_flag_return_damage_delay) * FLAG_THINKRATE);
ctf_CheckFlagReturn(this, RETURN_NEEDKILL);
flag.health = 0;
ctf_CheckFlagReturn(flag, RETURN_NEEDKILL);
}
- if(!flag.ctf_flagdamaged) { return; }
+ if(!flag.ctf_flagdamaged_byworld) { return; }
}
- int num_perteam = 0;
- FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(toucher, it), LAMBDA(++num_perteam));
-
// special touch behaviors
if(STAT(FROZEN, toucher)) { return; }
else if(IS_VEHICLE(toucher))
case FLAG_DROPPED:
{
- if(CTF_SAMETEAM(toucher, flag) && (autocvar_g_ctf_flag_return || num_perteam <= 1 || (autocvar_g_ctf_flag_return_carrying && toucher.flagcarried)) && flag.team) // automatically return if there's only 1 player on the team
+ if(CTF_SAMETEAM(toucher, flag) && ctf_Immediate_Return_Allowed(flag, toucher))
ctf_Handle_Return(flag, toucher); // toucher just returned his own flag
else if(is_not_monster && (!toucher.flagcarried) && ((toucher != flag.ctf_dropper) || (time > flag.ctf_droptime + autocvar_g_ctf_flag_collect_delay)))
ctf_Handle_Pickup(flag, toucher, PICKUP_DROPPED); // toucher just picked up a dropped enemy flag
if((IS_PLAYER(toucher)) && !IS_DEAD(toucher) && (toucher != flag.pass_sender))
{
if(DIFF_TEAM(toucher, flag.pass_sender))
- ctf_Handle_Return(flag, toucher);
+ {
+ if(ctf_Immediate_Return_Allowed(flag, toucher))
+ ctf_Handle_Return(flag, toucher);
+ else if(is_not_monster && (!toucher.flagcarried))
+ ctf_Handle_Pickup(flag, toucher, PICKUP_DROPPED);
+ }
else
ctf_Handle_Retrieve(flag, toucher);
}
flag.ctf_dropper = NULL;
flag.ctf_pickuptime = 0;
flag.ctf_droptime = 0;
- flag.ctf_flagdamaged = 0;
+ flag.ctf_flagdamaged_byworld = false;
ctf_CheckStalemate();
}
mf = havocbot_ctf_find_flag(this);
if(mf.ctf_status==FLAG_BASE)
{
+ if(this.goalcurrent == mf)
+ {
+ navigation_clearroute(this);
+ this.bot_strategytime = 0;
+ }
havocbot_ctf_reset_role(this);
return;
}
.entity ctf_dropper; // don't allow spam of dropping the flag
.int max_flag_health;
.float next_take_time;
-.bool ctf_flagdamaged;
+.bool ctf_flagdamaged_byworld;
int ctf_teams;
// passing/throwing properties
void kh_WaitForPlayers();
void kh_Controller_Think(entity this) // called a lot
{
- if(intermission_running)
+ if(gameover)
return;
if(this.cnt > 0)
{
void kh_Scores_Event(entity player, entity key, string what, float frags_player, float frags_owner) // update the score when a key is captured
{
string s;
- if(intermission_running)
+ if(gameover)
return;
if(frags_player)
void kh_Key_Touch(entity this, entity toucher) // runs many, many times when a key has been dropped and can be picked up
{
- if(intermission_running)
+ if(gameover)
return;
if(this.owner) // already carried
void kh_Key_Think(entity this) // runs all the time
{
- if(intermission_running)
+ if(gameover)
return;
if(this.owner)
FOREACH_CLIENT(IS_PLAYER(it), { pl_cnt++; });
if (player.lms_spectate_warning != 2)
{
+ if(IS_BOT_CLIENT(player))
+ bot_clear(player);
player.frags = FRAGS_LMS_LOSER;
PlayerScore_Add(player, SP_LMS_RANK, pl_cnt + 1);
}
{
int pl_cnt = 0;
FOREACH_CLIENT(IS_PLAYER(it), { pl_cnt++; });
+ if(IS_BOT_CLIENT(frag_target))
+ bot_clear(frag_target);
frag_target.frags = FRAGS_LMS_LOSER;
PlayerScore_Add(frag_target, SP_LMS_RANK, pl_cnt);
}
teamsay = false;
}
- if(intermission_running)
+ if(gameover)
teamsay = false;
if (!source) {
if (!privatesay && source && !IS_PLAYER(source))
{
- if (!intermission_running)
- if(teamsay || (autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !(warmup_stage || gameover)))
- teamsay = -1; // spectators
+ if (!gameover)
+ if (teamsay || (autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !warmup_stage))
+ teamsay = -1; // spectators
}
if(flood)
spawnfunc(target_checkpoint) // defrag entity
{
- vector o;
if(!g_race && !g_cts) { delete(this); return; }
defrag_ents = 1;
- EXACTTRIGGER_INIT;
+ // if this is targeted, then it probably isn't a trigger
+ bool is_trigger = !boolean(!this.nottargeted && this.targetname != "");
+
+ if(is_trigger)
+ EXACTTRIGGER_INIT;
this.use = checkpoint_use;
- if (!(this.spawnflags & 1))
+ if (is_trigger && !(this.spawnflags & 1))
settouch(this, checkpoint_touch);
- o = (this.absmin + this.absmax) * 0.5;
- tracebox(o, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), o - '0 0 1' * (o.z - this.absmin.z), MOVE_NORMAL, this);
- waypoint_spawnforitem_force(this, trace_endpos);
- this.nearestwaypointtimeout = time + 1000000000;
+ vector org = this.origin;
+
+ // bots should only pathfind to this if it is a valid touchable trigger
+ if(is_trigger)
+ {
+ org = (this.absmin + this.absmax) * 0.5;
+ tracebox(org, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), org - '0 0 1' * (org.z - this.absmin.z), MOVE_NORMAL, this);
+ waypoint_spawnforitem_force(this, trace_endpos);
+ this.nearestwaypointtimeout = time + 1000000000;
+ }
if(this.message == "")
this.message = "went backwards";
race_timed_checkpoint = 1;
if(this.race_checkpoint == 0)
- WaypointSprite_SpawnFixed(WP_RaceStart, o, this, sprite, RADARICON_NONE);
+ WaypointSprite_SpawnFixed(WP_RaceStart, org, this, sprite, RADARICON_NONE);
else
- WaypointSprite_SpawnFixed(WP_RaceCheckpoint, o, this, sprite, RADARICON_NONE);
+ WaypointSprite_SpawnFixed(WP_RaceCheckpoint, org, this, sprite, RADARICON_NONE);
this.sprite.waypointsprite_visible_for_player = race_waypointsprite_visible_for_player;
}
if (gameover)
+ gameover = false;
+
+ if (intermission_running)
{
round_handler_Reset(0);
round_handler_Remove();
// schedule a new round
this.wait = true;
this.nextthink = time + this.delay;
+ gameover = true;
}
else
{
spawnfunc(weapon_hagar);
spawnfunc(weapon_machinegun);
spawnfunc(item_bullets);
-spawnfunc(item_armor_large);
-spawnfunc(item_armor_large);
+spawnfunc(item_armor_mega);
spawnfunc(item_health_mega);
spawnfunc(item_health_medium);
spawnfunc(item_spikes) {spawnfunc_item_bullets(this);}
//spawnfunc(item_armor1) {spawnfunc_item_armor_medium(this);} // FIXME: in Quake this is green armor, in Xonotic maps it is an armor shard
-spawnfunc(item_armor2) {spawnfunc_item_armor_large(this);}
-spawnfunc(item_armorInv) {spawnfunc_item_armor_large(this);} // TODO: make sure we actually want this
+spawnfunc(item_armor2) {spawnfunc_item_armor_mega(this);}
+spawnfunc(item_armorInv) {spawnfunc_item_armor_mega(this);} // TODO: make sure we actually want this
spawnfunc(item_health) {if (this.spawnflags & 2) spawnfunc_item_health_mega(this);else spawnfunc_item_health_medium(this);}
//spawnfunc_item_spikes
spawnfunc(item_jetpack);
spawnfunc(item_armor_big);
-spawnfunc(item_armor_large);
+spawnfunc(item_armor_mega);
spawnfunc(item_armor_small);
spawnfunc(item_health_medium);
spawnfunc(ammo_rockets) { spawnfunc_item_rockets(this); }
// Armor
-spawnfunc(item_armor_body) { spawnfunc_item_armor_large(this); }
+spawnfunc(item_armor_body) { spawnfunc_item_armor_mega(this); }
spawnfunc(item_armor_combat) { spawnfunc_item_armor_big(this); }
spawnfunc(item_armor_shard) { spawnfunc_item_armor_small(this); }
spawnfunc(item_enviro) { spawnfunc_item_invincible(this); }
void Weapon_whereis(Weapon this, entity cl)
{
if (!autocvar_g_showweaponspawns) return;
- IL_EACH(g_items, it.weapon == this.m_id && (it.ItemStatus & ITS_AVAILABLE),
+ IL_EACH(g_items, it.weapon == this.m_id && (!it.team || (it.ItemStatus & ITS_AVAILABLE)),
{
if (it.classname == "droppedweapon" && autocvar_g_showweaponspawns < 2)
continue;
void CL_Weaponentity_Think(entity this)
{
this.nextthink = time;
- if (intermission_running) this.frame = this.anim_idle.x;
+ if (gameover) this.frame = this.anim_idle.x;
.entity weaponentity = this.weaponentity_fld;
if (this.owner.(weaponentity) != this)
{