- wget -O data/maps/stormkeep.waypoints https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints
- wget -O data/maps/stormkeep.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints.cache
- make
- - EXPECT=ed9be8d1b1a544f89bcdd7d36876fede
+ - EXPECT=3fb0c7a99263dd44e026804c12da2fa2
- HASH=$(${ENGINE} -noconfig -nohome +exec serverbench.cfg
| tee /dev/stderr
| grep '^:'
set sv_jumpspeedcap_max "" "upper bound on the baseline velocity of a jump; final velocity will be <= (jumpheight * max + jumpheight)"
set sv_jumpspeedcap_max_disable_on_ramps 0 "disable upper baseline velocity bound on ramps to preserve the old rampjump style"
set sv_track_canjump 0 "track if the player released the jump key between 2 jumps to decide if they are able to jump or not"
+set sv_jumpvelocity_crouch 0 "jump height while crouching, set to 0 to use regular jump height"
set sv_precacheplayermodels 1
set sv_precacheweapons 0
set sv_dodging_air_dodging 0
set sv_dodging_wall_dodging 0 "allow dodging off walls"
-set sv_dodging_delay 0.5 "determines how long a player has to wait to be able to dodge again after dodging"
+set sv_dodging_delay 0.6 "determines how long a player has to wait to be able to dodge again after dodging"
set sv_dodging_up_speed 200 "the jump velocity of the dodge"
-set sv_dodging_horiz_speed 400 "the horizontal velocity of the dodge"
-set sv_dodging_horiz_speed_frozen 200 "the horizontal velocity of the dodge while frozen"
+set sv_dodging_horiz_speed_min 200 "the lower bound of current velocity for force scaling"
+set sv_dodging_horiz_speed_max 1000 "the upper bound of current velocity for force scaling"
+set sv_dodging_horiz_force_slowest 400 "the horizontal velocity of the dodge when current velocity is <= sv_dodging_horiz_speed_min, values between min and max are linearly scaled"
+set sv_dodging_horiz_force_fastest 400 "the horizontal velocity of the dodge when current velocity is >= sv_dodging_horiz_speed_max, values between min and max are linearly scaled"
+set sv_dodging_horiz_force_frozen 200 "the horizontal velocity of the dodge while frozen"
set sv_dodging_ramp_time 0.1 "a ramp so that the horizontal part of the dodge is added smoothly (seconds)"
set sv_dodging_height_threshold 10 "the maximum height above ground where to allow dodging"
set sv_dodging_wall_distance_threshold 10 "the maximum distance from a wall that still allows dodging"
set sv_dodging_sound 1 "if 1 dodging makes a sound. if 0 dodging is silent"
set sv_dodging_frozen 0 "allow dodging while frozen"
set sv_dodging_frozen_doubletap 0
-set sv_dodging_maxspeed 450 "maximum speed a player can be moving at before they dodge again"
+set sv_dodging_maxspeed 350 "maximum speed a player can be moving at to use the standard dodging from an (almost) standstill"
+set sv_dodging_air_maxspeed 450 "maximum speed a player can be moving at before they dodge again when air dodging is enabled"
// ===========
set g_instagib_ammo_convert_cells 0 "convert normal cell ammo packs to insta cell ammo packs"
set g_instagib_ammo_convert_rockets 0 "convert rocket ammo packs to insta cell ammo packs"
set g_instagib_ammo_convert_shells 0 "convert shell ammo packs to insta cell ammo packs"
+set g_instagib_invisibility_time 30 "Time of ivisibility powerup in seconds."
set g_instagib_invis_alpha 0.15
+set g_instagib_speed_time 30 "Time of speed powerup in seconds."
set g_instagib_speed_highspeed 1.5 "speed-multiplier that applies while you carry the invincibility powerup"
set g_instagib_damagedbycontents 1 "allow damage from lava pits in instagib"
set g_instagib_blaster_keepdamage 0 "allow secondary fire to hurt players"
set g_dynamic_handicap_exponent 1 "The exponent used to calculate handicap. 1 means linear scale. Values more than 1 mean stronger non-linear handicap. Values less than 1 mean weaker non-linear handicap"
set g_dynamic_handicap_min 0 "The minimum value of the handicap."
set g_dynamic_handicap_max 0 "The maximum value of the handicap."
+
+// ===============
+// kick teamkiller
+// ===============
+set g_kick_teamkiller_rate 0 "Limit for teamkills per minute before the client gets dropped. 0 means that the teamkillers don't get kicked automatically"
+set g_kick_teamkiller_lower_limit 5 "Minimum number of teamkills before the teamkill rate is considered"
+
+// =====================
+// stale-move negation
+// =====================
+set g_smneg 0 "Stale-move negation: penalize repeated use of the same weapon"
+set g_smneg_bonus 1 "Stale-move negation: allow weapons to become stronger than their baseline"
+set g_smneg_bonus_asymptote 4 "Stale-move negation: damage = infinity at this bonus level"
+set g_smneg_cooldown_factor 0.25 "Stale-move negation: penalty cooldown factor"
+
+// ==============
+// random items
+// ==============
+set g_random_items 0 "Whether to enable random items."
+set g_random_loot 0 "Whether to enable random loot."
+exec randomitems-xonotic.cfg
set g_physics_xonotic_airspeedlimit_nonqw 900
set g_physics_xonotic_maxspeed 360
set g_physics_xonotic_jumpvelocity 260
+set g_physics_xonotic_jumpvelocity_crouch 0
set g_physics_xonotic_maxairstrafespeed 100
set g_physics_xonotic_maxairspeed 360
set g_physics_xonotic_airstrafeaccelerate 18
set g_physics_nexuiz_airspeedlimit_nonqw 0
set g_physics_nexuiz_maxspeed 400
set g_physics_nexuiz_jumpvelocity 300 "333 to match xonotic physics"
+set g_physics_nexuiz_jumpvelocity_crouch 0 "333 to match xonotic physics"
set g_physics_nexuiz_maxairstrafespeed 0
set g_physics_nexuiz_maxairspeed 220
set g_physics_nexuiz_airstrafeaccelerate 0
set g_physics_quake_airspeedlimit_nonqw 0
set g_physics_quake_maxspeed 320
set g_physics_quake_jumpvelocity 270
+set g_physics_quake_jumpvelocity_crouch 0
set g_physics_quake_maxairstrafespeed 0
set g_physics_quake_maxairspeed 30
set g_physics_quake_airstrafeaccelerate 0
set g_physics_warsow_airspeedlimit_nonqw 0
set g_physics_warsow_maxspeed 320
set g_physics_warsow_jumpvelocity 280
+set g_physics_warsow_jumpvelocity_crouch 0
set g_physics_warsow_maxairstrafespeed 30
set g_physics_warsow_maxairspeed 320
set g_physics_warsow_airstrafeaccelerate 70
set g_physics_defrag_airspeedlimit_nonqw 0
set g_physics_defrag_maxspeed 320
set g_physics_defrag_jumpvelocity 270
+set g_physics_defrag_jumpvelocity_crouch 0
set g_physics_defrag_maxairstrafespeed 30
set g_physics_defrag_maxairspeed 320
set g_physics_defrag_airstrafeaccelerate 70
set g_physics_quake3_airspeedlimit_nonqw 0
set g_physics_quake3_maxspeed 320
set g_physics_quake3_jumpvelocity 270
+set g_physics_quake3_jumpvelocity_crouch 0
set g_physics_quake3_maxairstrafespeed 0
set g_physics_quake3_maxairspeed 320
set g_physics_quake3_airstrafeaccelerate 0
set g_physics_vecxis_airspeedlimit_nonqw 0
set g_physics_vecxis_maxspeed 400
set g_physics_vecxis_jumpvelocity 300 "333 to match xonotic physics"
+set g_physics_vecxis_jumpvelocity_crouch 0 "333 to match xonotic physics"
set g_physics_vecxis_maxairstrafespeed 0
set g_physics_vecxis_maxairspeed 220
set g_physics_vecxis_airstrafeaccelerate 0
set g_physics_quake2_airspeedlimit_nonqw 0
set g_physics_quake2_maxspeed 300
set g_physics_quake2_jumpvelocity 270
+set g_physics_quake2_jumpvelocity_crouch 0
set g_physics_quake2_maxairstrafespeed 0
set g_physics_quake2_maxairspeed 300
set g_physics_quake2_airstrafeaccelerate 0
set g_physics_bones_airspeedlimit_nonqw 0
set g_physics_bones_maxspeed 320
set g_physics_bones_jumpvelocity 270
+set g_physics_bones_jumpvelocity_crouch 0
set g_physics_bones_maxairstrafespeed 30
set g_physics_bones_maxairspeed 320
set g_physics_bones_airstrafeaccelerate 70
set g_physics_overkill_airspeedlimit_nonqw 900
set g_physics_overkill_maxspeed 400
set g_physics_overkill_jumpvelocity 260
+set g_physics_overkill_jumpvelocity_crouch 0
set g_physics_overkill_maxairstrafespeed 100
set g_physics_overkill_maxairspeed 360
set g_physics_overkill_airstrafeaccelerate 24
edgefriction 1
sv_stepheight 18
sv_jumpvelocity 270
+sv_jumpvelocity_crouch 0
sv_wateraccelerate 4
sv_waterfriction 1
sv_airaccel_sideways_friction 0
edgefriction 1
sv_stepheight 34
sv_jumpvelocity 270
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0 // breaks strafing?
edgefriction 1
sv_stepheight 34
sv_jumpvelocity 300
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0.65
// actually, what we want is 266.6666 for 180bpm
// but 260 takes same amount of frames and is nicer to mappers
sv_jumpvelocity 260
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0 // breaks strafing?
// actually, what we want is 266.6666 for 180bpm
// but 260 takes same amount of frames and is nicer to mappers
sv_jumpvelocity 260
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0
edgefriction 1 // div0 says no! lol
sv_stepheight 26
sv_jumpvelocity 304
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0 // pain in the ass to tweak without screwing up the strafing
edgefriction 1
sv_stepheight 34
sv_jumpvelocity 310
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0.35
edgefriction 1
sv_stepheight 34
sv_jumpvelocity 300
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0
edgefriction 1
sv_stepheight 34
sv_jumpvelocity 300
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0
edgefriction 1
sv_stepheight 34
sv_jumpvelocity 300
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0
edgefriction 1
sv_stepheight 34
sv_jumpvelocity 300
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0
edgefriction 1
sv_stepheight 34
sv_jumpvelocity 300
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0
edgefriction 1
sv_stepheight 34
sv_jumpvelocity 300
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0.3
edgefriction 1
sv_stepheight 34
sv_jumpvelocity 300
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0.35
edgefriction 1
sv_stepheight 34
sv_jumpvelocity 300
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0.35
// actually, what we want is 266.6666 for 180bpm
// but 260 takes same amount of frames and is nicer to mappers
sv_jumpvelocity 260
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0
// this is smaller than 112 qu, so a 112 qu high corridor (7 of 8 grid units in
// the 16 grid, and the 8th unit used for wall/floor) just lets a player jump!
sv_jumpvelocity 260
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0
edgefriction 1
sv_stepheight 18
sv_jumpvelocity 270
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0
edgefriction 1
sv_stepheight 18
sv_jumpvelocity 270
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction 1
sv_airaccel_sideways_friction 0
edgefriction 1
sv_stepheight 18
sv_jumpvelocity 270
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction 1
sv_airaccel_sideways_friction 0
edgefriction 1
sv_stepheight 18
sv_jumpvelocity 270
+sv_jumpvelocity_crouch 0
sv_wateraccelerate 4
sv_waterfriction 1
sv_airaccel_sideways_friction 0
edgefriction 1
sv_stepheight 34
sv_jumpvelocity 300
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0.8
edgefriction 1
sv_stepheight 34
sv_jumpvelocity 300
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0.5
edgefriction 1
sv_stepheight 34
sv_jumpvelocity 300
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0.3
edgefriction 1
sv_stepheight 18
sv_jumpvelocity 280
+sv_jumpvelocity_crouch 0
sv_wateraccelerate 10
sv_waterfriction 1
sv_airaccel_sideways_friction 0
edgefriction 1
sv_stepheight 18
sv_jumpvelocity 280
+sv_jumpvelocity_crouch 0
sv_wateraccelerate 10
sv_waterfriction 1
sv_airaccel_sideways_friction 0
edgefriction 1
sv_stepheight 18
sv_jumpvelocity 280
+sv_jumpvelocity_crouch 0
sv_wateraccelerate 10
sv_waterfriction 1
sv_airaccel_sideways_friction 0
// this is smaller than 112 qu, so a 112 qu high corridor (7 of 8 grid units in
// the 16 grid, and the 8th unit used for wall/floor) just lets a player jump!
sv_jumpvelocity 260
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0
// actually, what we want is 266.6666 for 180bpm
// but 260 takes same amount of frames and is nicer to mappers
sv_jumpvelocity 260
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0
// this is smaller than 112 qu, so a 112 qu high corridor (7 of 8 grid units in
// the 16 grid, and the 8th unit used for wall/floor) just lets a player jump!
sv_jumpvelocity 260
+sv_jumpvelocity_crouch 0
sv_wateraccelerate -1
sv_waterfriction -1
sv_airaccel_sideways_friction 0
sv_stepheight 26
// CPMA: 18
sv_jumpvelocity 270
+sv_jumpvelocity_crouch 0
sv_wateraccelerate 4
sv_waterfriction 1
sv_airaccel_sideways_friction 0
sv_stepheight 26
// CPMA: 18
sv_jumpvelocity 270
+sv_jumpvelocity_crouch 0
sv_wateraccelerate 4
sv_waterfriction 1
sv_airaccel_sideways_friction 0
const int acc_decimals = 2;
if(time > physics_update_time)
{
+ discrete_acceleration = acceleration;
// workaround for ftos_decimals returning a negative 0
if(discrete_acceleration > -1 / (10 ** acc_decimals) && discrete_acceleration < 0)
discrete_acceleration = 0;
- discrete_acceleration = acceleration;
discrete_speed = speed;
physics_update_time += autocvar_hud_panel_physics_update_interval;
if(physics_update_time < time)
case "kd": return CTX(_("SCO^k/d"));
case "kdr": return CTX(_("SCO^kdr"));
case "kills": return CTX(_("SCO^kills"));
+ case "teamkills": return CTX(_("SCO^teamkills"));
case "laps": return CTX(_("SCO^laps"));
case "lives": return CTX(_("SCO^lives"));
case "losses": return CTX(_("SCO^losses"));
LOG_INFO(_("^3deaths^7 Number of deaths"));
LOG_INFO(_("^3suicides^7 Number of suicides"));
LOG_INFO(_("^3frags^7 kills - suicides"));
+ LOG_INFO(_("^3teamkills^7 Number of teamkills"));
LOG_INFO(_("^3kd^7 The kill-death ratio"));
LOG_INFO(_("^3dmg^7 The total damage done"));
LOG_INFO(_("^3dmgtaken^7 The total damage taken"));
" -teams,rc,cts,inv,lms/kills +ft,tdm/kills ?+rc,inv/kills" \
" -teams,lms/deaths +ft,tdm/deaths" \
" -teams,lms,rc,cts,inv,ka/suicides +ft,tdm/suicides ?+rc,inv/suicides" \
+" +teams/teamkills"\
" -cts,dm,tdm,ka,ft/frags" /* tdm already has this in "score" */ \
" -rc,cts,nb/dmg -rc,cts,nb/dmgtaken" \
" +ctf/caps +ctf/pickups +ctf/fckills +ctf/returns +ons/caps +ons/takes" \
#include "mutators/events.qh"
#include <common/animdecide.qh>
+#include <common/deathtypes/all.qh>
#include <common/ent_cs.qh>
#include <common/anim.qh>
#include <common/constants.qh>
case 2: // crosshair_color_by_health
{
- float hp = health_stat;
+ vector v = healtharmor_maxdamage(health_stat, STAT(ARMOR), armorblockpercent, DEATH_WEAPON.m_id);
+ float hp = floor(v.x + 1);
//x = red
//y = green
{
entity item = M_ARGV(0, entity);
- if(item.classname == "droppedweapon")
+ if(Item_IsLoot(item))
if(item.weapon == WEP_NEXBALL.m_id)
return true;
#pragma once
#include "all.qh"
-#include "item/pickup.qh"
CLASS(Inventory, Object)
/** Stores counts of items, the id being the index */
if (!(minorBits & BIT(j))) { \
continue; \
} \
- const GameItem it = Items_from(Inventory_groups_minor * maj + j); \
+ const entity it = Items_from(Inventory_groups_minor * maj + j); \
WriteByte(MSG_ENTITY, data.inv_items[it.m_id]); \
} \
} \
#pragma once
-#include <common/t_items.qh>
#ifdef GAMEQC
+#include <common/models/all.qh>
#include <common/sounds/all.qh>
#include <common/sounds/all.inc>
+#include <common/stats.qh>
#endif
const int IT_UNLIMITED_WEAPON_AMMO = BIT(0); // when this bit is set, using a weapon does not reduce ammo. Checkpoints can give this powerup.
#ifdef SVQC
.float strength_finished = _STAT(STRENGTH_FINISHED);
.float invincible_finished = _STAT(INVINCIBLE_FINISHED);
+
+#define SPAWNFUNC_ITEM(name, item) \
+ spawnfunc(name) { StartItem(this, item); }
+
+#else
+
+#define SPAWNFUNC_ITEM(name, item)
+
#endif
+enum
+{
+ ITEM_FLAG_NORMAL = BIT(0), ///< Item is usable during normal gameplay.
+ ITEM_FLAG_INSTAGIB = BIT(1), ///< Item is usable in instagib.
+ ITEM_FLAG_OVERKILL = BIT(2), ///< Item is usable in overkill.
+ ITEM_FLAG_MUTATORBLOCKED = BIT(3)
+};
+
#define ITEM_HANDLE(signal, ...) __Item_Send_##signal(__VA_ARGS__)
CLASS(GameItem, Object)
ATTRIB(GameItem, m_id, int, 0);
+ /** the canonical spawnfunc name */
+ ATTRIB(GameItem, m_canonical_spawnfunc, string);
+ METHOD(GameItem, m_spawnfunc_hookreplace, GameItem(GameItem this, entity e)) { return this; }
ATTRIB(GameItem, m_name, string);
ATTRIB(GameItem, m_icon, string);
ATTRIB(GameItem, m_color, vector, '1 1 1');
#include "ammo.qh"
+
+#ifdef SVQC
+
+METHOD(Bullets, m_spawnfunc_hookreplace, GameItem(Bullets this, entity e))
+{
+ if (autocvar_sv_q3acompat_machineshotgunswap && !Item_IsLoot(e))
+ {
+ return ITEM_Shells;
+ }
+ return this;
+}
+
+METHOD(Shells, m_spawnfunc_hookreplace, GameItem(Shells this, entity e))
+{
+ if (autocvar_sv_q3acompat_machineshotgunswap && !Item_IsLoot(e))
+ {
+ return ITEM_Bullets;
+ }
+ return this;
+}
+
+#endif
#pragma once
#include "pickup.qh"
+#ifdef SVQC
+ #include <common/t_items.qh>
+#endif
+
+.int ammo_none;
+.int ammo_shells;
+.int ammo_nails;
+.int ammo_rockets;
+.int ammo_cells;
+#ifdef SVQC
+.int ammo_plasma = _STAT(PLASMA);
+.int ammo_fuel = _STAT(FUEL);
+#else
+.int ammo_plasma;
+.int ammo_fuel;
+#endif
+
#ifdef SVQC
PROPERTY(float, g_pickup_ammo_anyway);
#endif
#endif
ENDCLASS(Ammo)
-#ifdef SVQC
- #include <common/t_items.qh>
-#endif
#ifdef GAMEQC
MODEL(Bullets_ITEM, Item_Model("a_bullets.mdl"));
item.ammo_nails = g_pickup_nails;
}
#endif
-REGISTER_ITEM(Bullets, Ammo) {
+
+CLASS(Bullets, Ammo)
+ENDCLASS(Bullets)
+
+REGISTER_ITEM(Bullets, Bullets) {
+ this.m_canonical_spawnfunc = "item_bullets";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_model = MDL_Bullets_ITEM;
#endif
this.netname = "bullets";
#endif
}
+SPAWNFUNC_ITEM(item_bullets, ITEM_Bullets)
+
#ifdef GAMEQC
MODEL(Cells_ITEM, Item_Model("a_cells.md3"));
#endif
}
#endif
REGISTER_ITEM(Cells, Ammo) {
+ this.m_canonical_spawnfunc = "item_cells";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_model = MDL_Cells_ITEM;
#endif
this.netname = "cells";
#endif
}
+SPAWNFUNC_ITEM(item_cells, ITEM_Cells)
+
#ifdef GAMEQC
MODEL(Plasma_ITEM, Item_Model("a_cells.md3"));
#endif
}
#endif
REGISTER_ITEM(Plasma, Ammo) {
+ this.m_canonical_spawnfunc = "item_plasma";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_model = MDL_Plasma_ITEM;
#endif
this.netname = "plasma";
#endif
}
+SPAWNFUNC_ITEM(item_plasma, ITEM_Plasma)
+
#ifdef GAMEQC
MODEL(Rockets_ITEM, Item_Model("a_rockets.md3"));
#endif
}
#endif
REGISTER_ITEM(Rockets, Ammo) {
+ this.m_canonical_spawnfunc = "item_rockets";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_model = MDL_Rockets_ITEM;
#endif
this.netname = "rockets";
#endif
}
+SPAWNFUNC_ITEM(item_rockets, ITEM_Rockets)
+
#ifdef GAMEQC
MODEL(Shells_ITEM, Item_Model("a_shells.md3"));
#endif
item.ammo_shells = g_pickup_shells;
}
#endif
-REGISTER_ITEM(Shells, Ammo) {
+
+CLASS(Shells, Ammo)
+ENDCLASS(Shells)
+
+REGISTER_ITEM(Shells, Shells) {
+ this.m_canonical_spawnfunc = "item_shells";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_model = MDL_Shells_ITEM;
#endif
this.netname = "shells";
this.m_iteminit = ammo_shells_init;
#endif
}
+
+SPAWNFUNC_ITEM(item_shells, ITEM_Shells)
#endif
REGISTER_ITEM(ArmorSmall, Armor) {
+ this.m_canonical_spawnfunc = "item_armor_small";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_OVERKILL;
this.m_model = MDL_ArmorSmall_ITEM;
this.m_sound = SND_ArmorSmall;
#endif
#endif
}
+SPAWNFUNC_ITEM(item_armor_small, ITEM_ArmorSmall)
+
#ifdef GAMEQC
MODEL(ArmorMedium_ITEM, Item_Model("item_armor_medium.md3"));
SOUND(ArmorMedium, Item_Sound("armor10"));
#endif
REGISTER_ITEM(ArmorMedium, Armor) {
+ this.m_canonical_spawnfunc = "item_armor_medium";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_OVERKILL;
this.m_model = MDL_ArmorMedium_ITEM;
this.m_sound = SND_ArmorMedium;
#endif
#endif
}
+SPAWNFUNC_ITEM(item_armor_medium, ITEM_ArmorMedium)
+
#ifdef GAMEQC
MODEL(ArmorBig_ITEM, Item_Model("item_armor_big.md3"));
SOUND(ArmorBig, Item_Sound("armor17_5"));
#endif
REGISTER_ITEM(ArmorBig, Armor) {
+ this.m_canonical_spawnfunc = "item_armor_big";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_OVERKILL;
this.m_model = MDL_ArmorBig_ITEM;
this.m_sound = SND_ArmorBig;
#endif
#endif
}
+SPAWNFUNC_ITEM(item_armor_big, ITEM_ArmorBig)
+
#ifdef GAMEQC
MODEL(ArmorMega_ITEM, Item_Model("item_armor_large.md3"));
SOUND(ArmorMega, Item_Sound("armor25"));
#endif
REGISTER_ITEM(ArmorMega, Armor) {
+ this.m_canonical_spawnfunc = "item_armor_mega";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_OVERKILL;
this.m_model = MDL_ArmorMega_ITEM;
this.m_sound = SND_ArmorMega;
#endif
this.m_iteminit = item_armormega_init;
#endif
}
+
+SPAWNFUNC_ITEM(item_armor_mega, ITEM_ArmorMega)
#endif
REGISTER_ITEM(HealthSmall, Health) {
+ this.m_canonical_spawnfunc = "item_health_small";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_model = MDL_HealthSmall_ITEM;
this.m_sound = SND_HealthSmall;
#endif
#endif
}
+SPAWNFUNC_ITEM(item_health_small, ITEM_HealthSmall)
+
#ifdef GAMEQC
MODEL(HealthMedium_ITEM, Item_Model("g_h25.md3"));
SOUND(HealthMedium, Item_Sound("mediumhealth"));
#endif
REGISTER_ITEM(HealthMedium, Health) {
+ this.m_canonical_spawnfunc = "item_health_medium";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_model = MDL_HealthMedium_ITEM;
this.m_sound = SND_HealthMedium;
#endif
#endif
}
+SPAWNFUNC_ITEM(item_health_medium, ITEM_HealthMedium)
+
#ifdef GAMEQC
MODEL(HealthBig_ITEM, Item_Model("g_h50.md3"));
SOUND(HealthBig, Item_Sound("mediumhealth"));
#endif
REGISTER_ITEM(HealthBig, Health) {
+ this.m_canonical_spawnfunc = "item_health_big";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_model = MDL_HealthBig_ITEM;
this.m_sound = SND_HealthBig;
#endif
#endif
}
+SPAWNFUNC_ITEM(item_health_big, ITEM_HealthBig)
+
#ifdef GAMEQC
MODEL(HealthMega_ITEM, Item_Model("g_h100.md3"));
SOUND(HealthMega, Item_Sound("megahealth"));
#endif
REGISTER_ITEM(HealthMega, Health) {
+ this.m_canonical_spawnfunc = "item_health_mega";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_OVERKILL;
this.m_model = MDL_HealthMega_ITEM;
this.m_sound = SND_HealthMega;
#endif
this.m_iteminit = item_healthmega_init;
#endif
}
+
+SPAWNFUNC_ITEM(item_health_mega, ITEM_HealthMega)
#include "jetpack.qh"
+
+#ifdef SVQC
+
+METHOD(Jetpack, m_spawnfunc_hookreplace, GameItem(Jetpack this, entity e))
+{
+ if(start_items & ITEM_Jetpack.m_itemid)
+ {
+ return ITEM_JetpackFuel;
+ }
+ return this;
+}
+
+METHOD(JetpackRegen, m_spawnfunc_hookreplace, GameItem(JetpackRegen this, entity e))
+{
+ if (start_items & ITEM_JetpackRegen.m_itemid)
+ {
+ return ITEM_JetpackFuel;
+ }
+ return this;
+}
+
+#endif
item.ammo_fuel = g_pickup_fuel_jetpack;
}
#endif
+
+CLASS(Jetpack, Powerup)
+ENDCLASS(Jetpack)
+
REGISTER_ITEM(Jetpack, Powerup) {
+ this.m_canonical_spawnfunc = "item_jetpack";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_model = MDL_Jetpack_ITEM;
this.m_itemid = IT_JETPACK;
#endif
#endif
}
+SPAWNFUNC_ITEM(item_jetpack, ITEM_Jetpack)
+
#ifdef GAMEQC
MODEL(JetpackFuel_ITEM, Item_Model("g_fuel.md3"));
#endif
}
#endif
REGISTER_ITEM(JetpackFuel, Ammo) {
+ this.m_canonical_spawnfunc = "item_fuel";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_model = MDL_JetpackFuel_ITEM;
#endif
this.netname = "fuel";
#endif
}
+SPAWNFUNC_ITEM(item_fuel, ITEM_JetpackFuel)
+
#ifdef GAMEQC
MODEL(JetpackRegen_ITEM, Item_Model("g_fuelregen.md3"));
#endif
-REGISTER_ITEM(JetpackRegen, Powerup) {
+CLASS(JetpackRegen, Powerup)
+ENDCLASS(JetpackRegen)
+
+REGISTER_ITEM(JetpackRegen, JetpackRegen) {
+ this.m_canonical_spawnfunc = "item_fuel_regen";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_model = MDL_JetpackRegen_ITEM;
#endif
this.netname = "fuel_regen";
this.m_pickupevalfunc = ammo_pickupevalfunc;
#endif
}
+
+SPAWNFUNC_ITEM(item_fuel_regen, ITEM_JetpackRegen)
#include "pickup.qh"
+#include <common/items/inventory.qh>
#ifdef SVQC
bool ITEM_HANDLE(Pickup, entity this, entity item, entity player) {
return this.giveTo(this, item, player);
}
+
+METHOD(Pickup, giveTo, bool(Pickup this, entity item, entity player))
+{
+ TC(Pickup, this);
+ bool b = Item_GiveTo(item, player);
+ if (b) {
+ LOG_DEBUGF("entity %i picked up %s", player, this.m_name);
+ player.inventory.inv_items[this.m_id]++;
+ Inventory_update(player);
+ }
+ return b;
+}
+
#endif
PROPERTY(float, g_pickup_respawntimejitter_powerup)
#endif
-#include <common/items/inventory.qh>
#include <common/items/item.qh>
-#include <common/t_items.qh>
-
-#ifdef GAMEQC
-#include <common/models/all.qh>
-#include <common/sounds/all.qh>
-#include <common/sounds/all.inc>
-#endif
CLASS(Pickup, GameItem)
#ifdef GAMEQC
ATTRIB(Pickup, m_pickupanyway, float());
ATTRIB(Pickup, m_iteminit, void(entity item));
float Item_GiveTo(entity item, entity player);
- METHOD(Pickup, giveTo, bool(Pickup this, entity item, entity player))
- {
- TC(Pickup, this);
- bool b = Item_GiveTo(item, player);
- if (b) {
- LOG_DEBUGF("entity %i picked up %s", player, this.m_name);
- player.inventory.inv_items[this.m_id]++;
- Inventory_update(player);
- }
- return b;
- }
+ METHOD(Pickup, giveTo, bool(Pickup this, entity item, entity player));
bool ITEM_HANDLE(Pickup, Pickup this, entity item, entity player);
#endif
ENDCLASS(Pickup)
}
#endif
REGISTER_ITEM(Strength, Powerup) {
+ this.m_canonical_spawnfunc = "item_strength";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_model = MDL_Strength_ITEM;
this.m_sound = SND_Strength;
this.m_glow = true;
#endif
}
+SPAWNFUNC_ITEM(item_strength, ITEM_Strength)
+
#ifdef GAMEQC
MODEL(Shield_ITEM, Item_Model("g_invincible.md3"));
SOUND(Shield, Item_Sound("powerup_shield"));
}
#endif
REGISTER_ITEM(Shield, Powerup) {
+ this.m_canonical_spawnfunc = "item_shield";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_model = MDL_Shield_ITEM;
this.m_sound = SND_Shield;
this.m_glow = true;
this.m_iteminit = powerup_shield_init;
#endif
}
+
+SPAWNFUNC_ITEM(item_shield, ITEM_Shield)
+SPAWNFUNC_ITEM(item_invincible, ITEM_Shield)
return;
vector org = CENTER_OR_VIEWOFS(this);
- entity e = new(droppedweapon); // use weapon handling to remove it on touch
+ entity e = spawn();
+ Item_SetLoot(e, true);
e.spawnfunc_checked = true;
e.monster_loot = this.monster_loot;
e.noalign = true;
StartItem(e, e.monster_loot);
e.gravity = 1;
- set_movetype(e, MOVETYPE_TOSS);
- e.reset = SUB_Remove;
setorigin(e, org);
e.velocity = randomvec() * 175 + '0 0 325';
e.item_spawnshieldtime = time + 0.7;
#include <common/mutators/mutator/instagib/_mod.inc>
#include <common/mutators/mutator/invincibleproj/_mod.inc>
#include <common/mutators/mutator/itemstime/_mod.inc>
+#include <common/mutators/mutator/kick_teamkiller/_mod.inc>
#include <common/mutators/mutator/melee_only/_mod.inc>
#include <common/mutators/mutator/midair/_mod.inc>
#include <common/mutators/mutator/multijump/_mod.inc>
#include <common/mutators/mutator/physical_items/_mod.inc>
#include <common/mutators/mutator/pinata/_mod.inc>
#include <common/mutators/mutator/random_gravity/_mod.inc>
+#include <common/mutators/mutator/random_items/_mod.inc>
#include <common/mutators/mutator/rocketflying/_mod.inc>
#include <common/mutators/mutator/rocketminsta/_mod.inc>
#include <common/mutators/mutator/running_guns/_mod.inc>
#include <common/mutators/mutator/sandbox/_mod.inc>
#include <common/mutators/mutator/spawn_near_teammate/_mod.inc>
+#include <common/mutators/mutator/stale_move_negation/_mod.inc>
#include <common/mutators/mutator/superspec/_mod.inc>
#include <common/mutators/mutator/touchexplode/_mod.inc>
#include <common/mutators/mutator/vampire/_mod.inc>
#include <common/mutators/mutator/instagib/_mod.qh>
#include <common/mutators/mutator/invincibleproj/_mod.qh>
#include <common/mutators/mutator/itemstime/_mod.qh>
+#include <common/mutators/mutator/kick_teamkiller/_mod.qh>
#include <common/mutators/mutator/melee_only/_mod.qh>
#include <common/mutators/mutator/midair/_mod.qh>
#include <common/mutators/mutator/multijump/_mod.qh>
#include <common/mutators/mutator/physical_items/_mod.qh>
#include <common/mutators/mutator/pinata/_mod.qh>
#include <common/mutators/mutator/random_gravity/_mod.qh>
+#include <common/mutators/mutator/random_items/_mod.qh>
#include <common/mutators/mutator/rocketflying/_mod.qh>
#include <common/mutators/mutator/rocketminsta/_mod.qh>
#include <common/mutators/mutator/running_guns/_mod.qh>
#include <common/mutators/mutator/sandbox/_mod.qh>
#include <common/mutators/mutator/spawn_near_teammate/_mod.qh>
+#include <common/mutators/mutator/stale_move_negation/_mod.qh>
#include <common/mutators/mutator/superspec/_mod.qh>
#include <common/mutators/mutator/touchexplode/_mod.qh>
#include <common/mutators/mutator/vampire/_mod.qh>
switch(ent.classname)
{
case "item_strength":
- case "item_invincible":
+ case "item_shield":
{
entity e = spawn();
buff_SpawnReplacement(e, ent);
#include "sv_dodging.qh"
+// TODO the CSQC blocks in this sv_ file are currently not compiled but will be when dodging prediction gets enabled
+
#define PHYS_DODGING g_dodging
#define PHYS_DODGING_DELAY autocvar_sv_dodging_delay
#define PHYS_DODGING_DISTANCE_THRESHOLD autocvar_sv_dodging_wall_distance_threshold
-#define PHYS_DODGING_FROZEN_NODOUBLETAP autocvar_sv_dodging_frozen_doubletap
+#define PHYS_DODGING_FROZEN_DOUBLETAP autocvar_sv_dodging_frozen_doubletap
#define PHYS_DODGING_HEIGHT_THRESHOLD autocvar_sv_dodging_height_threshold
-#define PHYS_DODGING_HORIZ_SPEED autocvar_sv_dodging_horiz_speed
-#define PHYS_DODGING_HORIZ_SPEED_FROZEN autocvar_sv_dodging_horiz_speed_frozen
+#define PHYS_DODGING_HORIZ_SPEED_MIN autocvar_sv_dodging_horiz_speed_min
+#define PHYS_DODGING_HORIZ_SPEED_MAX autocvar_sv_dodging_horiz_speed_max
+#define PHYS_DODGING_HORIZ_FORCE_SLOWEST autocvar_sv_dodging_horiz_force_slowest
+#define PHYS_DODGING_HORIZ_FORCE_FASTEST autocvar_sv_dodging_horiz_force_fastest
+#define PHYS_DODGING_HORIZ_FORCE_FROZEN autocvar_sv_dodging_horiz_force_frozen
#define PHYS_DODGING_RAMP_TIME autocvar_sv_dodging_ramp_time
#define PHYS_DODGING_UP_SPEED autocvar_sv_dodging_up_speed
#define PHYS_DODGING_WALL autocvar_sv_dodging_wall_dodging
#define PHYS_DODGING_AIR autocvar_sv_dodging_air_dodging
#define PHYS_DODGING_MAXSPEED autocvar_sv_dodging_maxspeed
+#define PHYS_DODGING_AIR_MAXSPEED autocvar_sv_dodging_air_maxspeed
// we ran out of stats slots! TODO: re-enable this when prediction is available for dodging
#if 0
#define PHYS_DODGING STAT(DODGING, this)
#define PHYS_DODGING_DELAY STAT(DODGING_DELAY, this)
#define PHYS_DODGING_DISTANCE_THRESHOLD STAT(DODGING_DISTANCE_THRESHOLD, this)
-#define PHYS_DODGING_FROZEN_NODOUBLETAP STAT(DODGING_FROZEN_NO_DOUBLETAP, this)
+#define PHYS_DODGING_FROZEN_DOUBLETAP STAT(DODGING_FROZEN_DOUBLETAP, this)
#define PHYS_DODGING_HEIGHT_THRESHOLD STAT(DODGING_HEIGHT_THRESHOLD, this)
-#define PHYS_DODGING_HORIZ_SPEED STAT(DODGING_HORIZ_SPEED, this)
-#define PHYS_DODGING_HORIZ_SPEED_FROZEN STAT(DODGING_HORIZ_SPEED_FROZEN, this)
+#define PHYS_DODGING_HORIZ_SPEED_MIN STAT(DODGING_HORIZ_SPEED_MIN, this)
+#define PHYS_DODGING_HORIZ_SPEED_MAX STAT(DODGING_HORIZ_SPEED_MAX, this)
+#define PHYS_DODGING_HORIZ_FORCE_SLOWEST STAT(DODGING_HORIZ_FORCE_SLOWEST, this)
+#define PHYS_DODGING_HORIZ_FORCE_FASTEST STAT(DODGING_HORIZ_FORCE_FASTEST, this)
+#define PHYS_DODGING_HORIZ_FORCE_FROZEN STAT(DODGING_HORIZ_FORCE_FROZEN, this)
#define PHYS_DODGING_RAMP_TIME STAT(DODGING_RAMP_TIME, this)
#define PHYS_DODGING_UP_SPEED STAT(DODGING_UP_SPEED, this)
#define PHYS_DODGING_WALL STAT(DODGING_WALL, this)
#define PHYS_DODGING_AIR STAT(DODGING_AIR, this)
#define PHYS_DODGING_MAXSPEED STAT(DODGING_MAXSPEED, this)
+#define PHYS_DODGING_AIR_MAXSPEED STAT(DODGING_AIR_MAXSPEED, this)
#endif
#ifdef CSQC
bool autocvar_sv_dodging_sound;
-// set to 1 to indicate dodging has started.. reset by physics hook after dodge has been done..
-.float dodging_action;
-
-// the jump part of the dodge cannot be ramped
-.float dodging_single_action;
-
#include <common/animdecide.qh>
#include <common/physics/player.qh>
// the jump part of the dodge cannot be ramped
.float dodging_single_action;
-
// these are used to store the last key press time for each of the keys..
.float last_FORWARD_KEY_time;
.float last_BACKWARD_KEY_time;
// and to ramp up the dodge acceleration in the physics hook.
.float last_dodging_time;
-// This is the velocity gain to be added over the ramp time.
-// It will decrease from frame to frame during dodging_action = 1
-// until it's 0.
-.float dodging_velocity_gain;
+// the total speed that will be added over the ramp time
+.float dodging_force_total;
+// the part of total yet to be added
+.float dodging_force_remaining;
#ifdef CSQC
.int pressedkeys;
#endif
-// returns true if the player is close to a wall
-bool check_close_to_wall(entity this, float threshold)
-{
- if (PHYS_DODGING_WALL == 0) { return false; }
-
#define X(dir) \
tracebox(this.origin, this.mins, this.maxs, this.origin + threshold * dir, true, this); \
if (trace_fraction < 1 && !(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)) \
return true;
+// returns true if the player is close to a wall
+bool is_close_to_wall(entity this, float threshold)
+{
X(v_right);
X(-v_right);
X(v_forward);
X(-v_forward);
-#undef X
return false;
}
-bool check_close_to_ground(entity this, float threshold)
+bool is_close_to_ground(entity this, float threshold)
{
- return IS_ONGROUND(this) ? true : false;
+ if (IS_ONGROUND(this)) return true;
+ X(-v_up); // necessary for dodging down a slope using doubletap (using `+dodge` works anyway)
+
+ return false;
+}
+
+#undef X
+
+float determine_force(entity player) {
+ if (PHYS_FROZEN(player)) return PHYS_DODGING_HORIZ_FORCE_FROZEN;
+
+ float horiz_vel = vlen(vec2(player.velocity));
+ return map_bound_ranges(horiz_vel,
+ PHYS_DODGING_HORIZ_SPEED_MIN, PHYS_DODGING_HORIZ_SPEED_MAX,
+ PHYS_DODGING_HORIZ_FORCE_SLOWEST, PHYS_DODGING_HORIZ_FORCE_FASTEST);
}
bool PM_dodging_checkpressedkeys(entity this)
{
- if(!PHYS_DODGING)
- return false;
-
bool frozen_dodging = (PHYS_FROZEN(this) && PHYS_DODGING_FROZEN(this));
- bool frozen_no_doubletap = (frozen_dodging && !PHYS_DODGING_FROZEN_NODOUBLETAP);
+ bool frozen_no_doubletap = (frozen_dodging && !PHYS_DODGING_FROZEN_DOUBLETAP);
+
+ float tap_direction_x = 0;
+ float tap_direction_y = 0;
+ bool dodge_detected = false;
+ vector mymovement = PHYS_CS(this).movement;
- // first check if the last dodge is far enough back in time so we can dodge again
+ #define X(COND,BTN,RESULT) \
+ if (mymovement_##COND) { \
+ /* is this a state change? */ \
+ if(!(PHYS_DODGING_PRESSED_KEYS(this) & KEY_##BTN) || frozen_no_doubletap) { \
+ tap_direction_##RESULT; \
+ if ((time - this.last_##BTN##_KEY_time) < PHYS_DODGING_TIMEOUT(this) || frozen_no_doubletap) { \
+ dodge_detected = true; \
+ } else if(PHYS_INPUT_BUTTON_DODGE(this)) { \
+ dodge_detected = true; \
+ } \
+ this.last_##BTN##_KEY_time = time; \
+ } \
+ }
+ X(x < 0, BACKWARD, x--);
+ X(x > 0, FORWARD, x++);
+ X(y < 0, LEFT, y--);
+ X(y > 0, RIGHT, y++);
+ #undef X
+
+ if (!dodge_detected) return false;
+
+ // this check has to be after checking keys:
+ // the first key press of the double tap is allowed to be before dodging delay,
+ // only the second has to be after, otherwise +dodge gives an advantage because typical repress time is 0.1 s
+ // or higher which means players using +dodge would be able to do it more often
if ((time - this.last_dodging_time) < PHYS_DODGING_DELAY)
return false;
makevectors(this.angles);
- bool wall_dodge = false;
+ bool can_dodge = (is_close_to_ground(this, PHYS_DODGING_HEIGHT_THRESHOLD) && (PHYS_DODGING_MAXSPEED == 0 || vdist(this.velocity, <, PHYS_DODGING_MAXSPEED)));
+ bool can_wall_dodge = (PHYS_DODGING_WALL && is_close_to_wall(this, PHYS_DODGING_DISTANCE_THRESHOLD));
+ bool can_air_dodge = (PHYS_DODGING_AIR && (PHYS_DODGING_AIR_MAXSPEED == 0 || vdist(this.velocity, <, PHYS_DODGING_AIR_MAXSPEED)));
+ if (!can_dodge && !can_wall_dodge && !can_air_dodge) return false;
- if(!PHYS_DODGING_AIR)
- if(!check_close_to_ground(this, PHYS_DODGING_HEIGHT_THRESHOLD))
- {
- wall_dodge = check_close_to_wall(this, PHYS_DODGING_DISTANCE_THRESHOLD);
- if(!wall_dodge) // we're not on the ground, and wall dodging isn't allowed, end it!
- return true;
- }
+ this.last_dodging_time = time;
- if(!wall_dodge && PHYS_DODGING_MAXSPEED && vdist(this.velocity, >, PHYS_DODGING_MAXSPEED))
- return false;
+ this.dodging_action = 1;
+ this.dodging_single_action = 1;
- float tap_direction_x = 0;
- float tap_direction_y = 0;
- bool dodge_detected = false;
- vector mymovement = PHYS_CS(this).movement;
+ this.dodging_force_total = determine_force(this);
+ this.dodging_force_remaining = this.dodging_force_total;
- #define X(COND,BTN,RESULT) \
- if (mymovement_##COND) \
- /* is this a state change? */ \
- if(!(PHYS_DODGING_PRESSED_KEYS(this) & KEY_##BTN) || frozen_no_doubletap) { \
- tap_direction_##RESULT; \
- if ((time - this.last_##BTN##_KEY_time) < PHYS_DODGING_TIMEOUT(this) || frozen_no_doubletap) \
- dodge_detected = true; \
- if(PHYS_INPUT_BUTTON_DODGE(this)) \
- dodge_detected = true; \
- this.last_##BTN##_KEY_time = time; \
- }
- X(x < 0, BACKWARD, x--);
- X(x > 0, FORWARD, x++);
- X(y < 0, LEFT, y--);
- X(y > 0, RIGHT, y++);
- #undef X
-
- if (dodge_detected)
- {
- this.last_dodging_time = time;
-
- this.dodging_action = 1;
- this.dodging_single_action = 1;
+ this.dodging_direction.x = tap_direction_x;
+ this.dodging_direction.y = tap_direction_y;
- this.dodging_velocity_gain = PHYS_DODGING_HORIZ_SPEED;
+ // normalize the dodging_direction vector.. (unlike UT99) XD
+ float length = sqrt(this.dodging_direction.x ** 2 + this.dodging_direction.y ** 2);
- this.dodging_direction_x = tap_direction_x;
- this.dodging_direction_y = tap_direction_y;
+ this.dodging_direction.x = this.dodging_direction.x / length;
+ this.dodging_direction.y = this.dodging_direction.y / length;
- // normalize the dodging_direction vector.. (unlike UT99) XD
- float length = this.dodging_direction_x * this.dodging_direction_x
- + this.dodging_direction_y * this.dodging_direction_y;
- length = sqrt(length);
-
- this.dodging_direction_x = this.dodging_direction_x * 1.0 / length;
- this.dodging_direction_y = this.dodging_direction_y * 1.0 / length;
- return true;
- }
- return false;
+ return true;
}
void PM_dodging(entity this)
{
- if (!PHYS_DODGING)
- return;
+ // can't use return value from PM_dodging_checkpressedkeys because they're called from different hooks
+ if (!this.dodging_action) return;
// when swimming or dead, no dodging allowed..
if (this.waterlevel >= WATERLEVEL_SWIMMING || IS_DEAD(this))
{
this.dodging_action = 0;
- this.dodging_direction_x = 0;
- this.dodging_direction_y = 0;
+ this.dodging_direction.x = 0;
+ this.dodging_direction.y = 0;
return;
}
else
makevectors(this.angles);
+ // fraction of the force to apply each frame
// if we have e.g. 0.5 sec ramptime and a frametime of 0.25, then the ramp code
// will be called ramp_time/frametime times = 2 times. so, we need to
// add 0.5 * the total speed each frame until the dodge action is done..
float common_factor = PHYS_DODGING_FRAMETIME / PHYS_DODGING_RAMP_TIME;
+ // NOTE: depending on cl_netfps the client may (and probably will) send more input frames during each server frame
+ // but common_factor uses server frame rate so players with higher cl_netfps will ramp slightly faster
- // if ramp time is smaller than frametime we get problems ;D
- common_factor = min(common_factor, 1);
-
- float horiz_speed = PHYS_FROZEN(this) ? PHYS_DODGING_HORIZ_SPEED_FROZEN : PHYS_DODGING_HORIZ_SPEED;
- float new_velocity_gain = this.dodging_velocity_gain - (common_factor * horiz_speed);
- new_velocity_gain = max(0, new_velocity_gain);
-
- float velocity_difference = this.dodging_velocity_gain - new_velocity_gain;
-
- // ramp up dodging speed by adding some velocity each frame.. TODO: do it! :D
- if (this.dodging_action == 1)
- {
- //disable jump key during dodge accel phase
- if(PHYS_CS(this).movement.z > 0) { PHYS_CS(this).movement_z = 0; }
-
- this.velocity += ((this.dodging_direction_y * velocity_difference) * v_right)
- + ((this.dodging_direction_x * velocity_difference) * v_forward);
-
- this.dodging_velocity_gain = this.dodging_velocity_gain - velocity_difference;
- }
+ float velocity_increase = min(common_factor * this.dodging_force_total, this.dodging_force_remaining);
+ this.dodging_force_remaining -= velocity_increase;
+ this.velocity += this.dodging_direction.x * velocity_increase * v_forward
+ + this.dodging_direction.y * velocity_increase * v_right;
// the up part of the dodge is a single shot action
if (this.dodging_single_action == 1)
this.dodging_single_action = 0;
}
- // are we done with the dodging ramp yet?
- if((this.dodging_action == 1) && ((time - this.last_dodging_time) > PHYS_DODGING_RAMP_TIME))
+ if(this.dodging_force_remaining <= 0)
{
// reset state so next dodge can be done correctly
this.dodging_action = 0;
- this.dodging_direction_x = 0;
- this.dodging_direction_y = 0;
+ this.dodging_direction.x = 0;
+ this.dodging_direction.y = 0;
}
}
+#ifdef CSQC
void PM_dodging_GetPressedKeys(entity this)
{
-#ifdef CSQC
- if(!PHYS_DODGING) { return; }
-
PM_dodging_checkpressedkeys(this);
int keys = this.pressedkeys;
keys = BITSET(keys, KEY_ATCK, PHYS_INPUT_BUTTON_ATCK(this));
keys = BITSET(keys, KEY_ATCK2, PHYS_INPUT_BUTTON_ATCK2(this));
this.pressedkeys = keys;
-#endif
}
+#endif
MUTATOR_HOOKFUNCTION(dodging, PlayerPhysics)
{
- entity player = M_ARGV(0, entity);
+ entity player = M_ARGV(0, entity);
- // print("dodging_PlayerPhysics\n");
+#ifdef CSQC
PM_dodging_GetPressedKeys(player);
+#endif
PM_dodging(player);
}
REPLICATE(cvar_cl_dodging_timeout, float, "cl_dodging_timeout");
-MUTATOR_HOOKFUNCTION(dodging, PlayerPreThink)
-{
- entity player = M_ARGV(0, entity);
-
- STAT(DODGING_TIMEOUT, player) = CS(player).cvar_cl_dodging_timeout;
-}
-
MUTATOR_HOOKFUNCTION(dodging, GetPressedKeys)
{
entity player = M_ARGV(0, entity);
// generated file; do not modify
#include <common/mutators/mutator/instagib/items.qc>
+#ifdef SVQC
+ #include <common/mutators/mutator/instagib/sv_items.qc>
+#endif
#ifdef SVQC
#include <common/mutators/mutator/instagib/sv_instagib.qc>
#endif
}
#endif
REGISTER_ITEM(VaporizerCells, Ammo) {
+ this.m_canonical_spawnfunc = "item_vaporizer_cells";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_INSTAGIB | ITEM_FLAG_MUTATORBLOCKED;
this.m_model = MDL_VaporizerCells_ITEM;
this.m_sound = SND_VaporizerCells;
#endif
- this.netname = "minst_cells";
+ this.netname = "vaporizer_cells";
this.m_name = "Vaporizer Ammo";
this.m_icon = "ammo_supercells";
#ifdef SVQC
#endif
}
+SPAWNFUNC_ITEM(item_vaporizer_cells, ITEM_VaporizerCells)
+SPAWNFUNC_ITEM(item_minst_cells, ITEM_VaporizerCells)
+
#ifdef GAMEQC
MODEL(ExtraLife_ITEM, Item_Model("g_h100.md3"));
SOUND(ExtraLife, Item_Sound("megahealth"));
#endif
REGISTER_ITEM(ExtraLife, Powerup) {
+ this.m_canonical_spawnfunc = "item_extralife";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_INSTAGIB;
this.m_model = MDL_ExtraLife_ITEM;
this.m_sound = SND_ExtraLife;
#endif
- this.netname = "health_mega";
+ this.netname = "extralife";
this.m_name = "Extra life";
this.m_icon = "item_mega_health";
this.m_color = '1 0 0';
this.m_itemid = IT_NAILS;
}
+SPAWNFUNC_ITEM(item_extralife, ITEM_ExtraLife)
+
#ifdef GAMEQC
MODEL(Invisibility_ITEM, Item_Model("g_strength.md3"));
SOUND(Invisibility, Item_Sound("powerup"));
#endif
+#ifdef SVQC
+/// \brief Initializes the invisibility powerup.
+/// \param[in,out] item Item to initialize.
+/// \return No return.
+void powerup_invisibility_init(entity item);
+#endif
+
REGISTER_ITEM(Invisibility, Powerup) {
+ this.m_canonical_spawnfunc = "item_invisibility";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_INSTAGIB;
this.m_model = MDL_Invisibility_ITEM;
this.m_sound = SND_Invisibility;
+ this.m_glow = true;
+ this.m_respawnsound = SND_STRENGTH_RESPAWN;
#endif
- this.netname = "strength";
+ this.netname = "invisibility";
this.m_name = "Invisibility";
this.m_icon = "strength";
this.m_color = '0 0 1';
this.m_waypoint = _("Invisibility");
this.m_waypointblink = 2;
this.m_itemid = IT_STRENGTH;
+#ifdef SVQC
+ this.m_iteminit = powerup_invisibility_init;
+#endif
}
+SPAWNFUNC_ITEM(item_invisibility, ITEM_Invisibility)
+
#ifdef GAMEQC
MODEL(Speed_ITEM, Item_Model("g_invincible.md3"));
SOUND(Speed, Item_Sound("powerup_shield"));
#endif
+#ifdef SVQC
+/// \brief Initializes the speed powerup.
+/// \param[in,out] item Item to initialize.
+/// \return No return.
+void powerup_speed_init(entity item);
+#endif
+
REGISTER_ITEM(Speed, Powerup) {
+ this.m_canonical_spawnfunc = "item_speed";
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_INSTAGIB;
this.m_model = MDL_Speed_ITEM;
this.m_sound = SND_Speed;
+ this.m_glow = true;
+ this.m_respawnsound = SND_SHIELD_RESPAWN;
#endif
- this.netname = "invincible";
+ this.netname = "speed";
this.m_name = "Speed";
this.m_icon = "shield";
this.m_color = '1 0 1';
this.m_waypoint = _("Speed");
this.m_waypointblink = 2;
this.m_itemid = IT_INVINCIBLE;
+#ifdef SVQC
+ this.m_iteminit = powerup_speed_init;
+#endif
}
+
+SPAWNFUNC_ITEM(item_speed, ITEM_Speed)
#include <common/items/_mod.qh>
-REGISTER_MUTATOR(mutator_instagib, autocvar_g_instagib && !g_nexball);
-
-spawnfunc(item_minst_cells)
+REGISTER_MUTATOR(mutator_instagib, autocvar_g_instagib && !g_nexball)
{
- if (!g_instagib) { delete(this); return; }
- StartItem(this, ITEM_VaporizerCells);
+ MUTATOR_ONADD
+ {
+ ITEM_VaporizerCells.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
+ }
+ MUTATOR_ONROLLBACK_OR_REMOVE
+ {
+ ITEM_VaporizerCells.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
+ }
}
void instagib_invisibility(entity this)
void replace_with_insta_cells(entity item)
{
- entity e = spawn();
+ entity e = new(item_vaporizer_cells);
setorigin(e, item.origin);
e.noalign = item.noalign;
e.cnt = item.cnt;
e.team = item.team;
e.spawnfunc_checked = true;
- spawnfunc_item_minst_cells(e);
+ spawnfunc_item_vaporizer_cells(e);
}
MUTATOR_HOOKFUNCTION(mutator_instagib, FilterItem)
return true;
}
- if(item.weapon == WEP_VAPORIZER.m_id && item.classname == "droppedweapon")
+ if(item.weapon == WEP_VAPORIZER.m_id && Item_IsLoot(item))
{
SetResourceAmount(item, RESOURCE_CELLS, autocvar_g_instagib_ammo_drop);
return false;
return false;
float cells = GetResourceAmount(item, RESOURCE_CELLS);
- if(cells > autocvar_g_instagib_ammo_drop && item.classname != "item_minst_cells")
+ if(cells > autocvar_g_instagib_ammo_drop && item.classname != "item_vaporizer_cells")
SetResourceAmount(item, RESOURCE_CELLS, autocvar_g_instagib_ammo_drop);
if(cells && !item.weapon)
if (!autocvar_g_powerups) { return; }
entity ent = M_ARGV(0, entity);
// Can't use .itemdef here
- if (!(ent.classname == "item_strength" || ent.classname == "item_invincible" || ent.classname == "item_health_mega"))
+ if (!(ent.classname == "item_strength" || ent.classname == "item_shield" || ent.classname == "item_health_mega"))
return;
entity e = spawn();
float r = random();
if (r < 0.3)
+ {
+ e.classname = "item_invisibility";
setthink(e, instagib_invisibility);
+ }
else if (r < 0.6)
+ {
+ e.classname = "item_extralife";
setthink(e, instagib_extralife);
+ }
else
+ {
+ e.classname = "item_speed";
setthink(e, instagib_speed);
+ }
e.nextthink = time + 0.1;
e.spawnflags = ent.spawnflags;
#include "items.qh"
float autocvar_g_instagib_invis_alpha;
+
+void instagib_invisibility(entity this);
+void instagib_extralife(entity this);
+void instagib_speed(entity this);
--- /dev/null
+#include "items.qh"
+
+/// \brief Time of ivisibility powerup in seconds.
+float autocvar_g_instagib_invisibility_time;
+/// \brief Time of speed powerup in seconds.
+float autocvar_g_instagib_speed_time;
+
+void powerup_invisibility_init(entity item)
+{
+ if(!item.strength_finished)
+ {
+ item.strength_finished = autocvar_g_instagib_invisibility_time;
+ }
+}
+
+
+void powerup_speed_init(entity item)
+{
+ if(!item.invincible_finished)
+ {
+ item.invincible_finished = autocvar_g_instagib_speed_time;
+ }
+}
--- /dev/null
+// generated file; do not modify
+#ifdef SVQC
+ #include <common/mutators/mutator/kick_teamkiller/sv_kick_teamkiller.qc>
+#endif
--- /dev/null
+// generated file; do not modify
--- /dev/null
+
+float autocvar_g_kick_teamkiller_rate;
+float autocvar_g_kick_teamkiller_lower_limit;
+
+REGISTER_MUTATOR(kick_teamkiller, (autocvar_g_kick_teamkiller_rate > 0));
+
+MUTATOR_HOOKFUNCTION(kick_teamkiller, PlayerDies)
+{
+ if (!teamplay)
+ {
+ return;
+ }
+ if (warmup_stage)
+ {
+ return;
+ }
+ entity attacker = M_ARGV(1, entity);
+ if (!IS_REAL_CLIENT(attacker))
+ {
+ return;
+ }
+
+ int teamkills = PlayerScore_Get(attacker, SP_TEAMKILLS);
+ // use the players actual playtime
+ float playtime = time - CS(attacker).startplaytime;
+ // rate is in teamkills/minutes, playtime in seconds
+ if (teamkills >= autocvar_g_kick_teamkiller_lower_limit &&
+ teamkills >= autocvar_g_kick_teamkiller_rate*playtime/60.0)
+ {
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_KICK_TEAMKILL, attacker.netname);
+ dropclient(attacker);
+ }
+}
#include "sv_new_toys.qh"
+#include "../random_items/sv_random_items.qh"
+
/*
CORE laser vortex lg rl cry gl elec hagar fireb hook
MUTATOR_HOOKFUNCTION(nt, SetWeaponreplace)
{
+ if (autocvar_g_random_items)
+ {
+ // Do not replace weapons when random items are enabled.
+ return;
+ }
entity wep = M_ARGV(0, entity);
entity wepinfo = M_ARGV(1, entity);
string ret_string = M_ARGV(2, string);
M_ARGV(3, float) /* damage */ = (M_ARGV(0, entity)).max_health * 0.1;
}
-spawnfunc(weapon_hmg) { weapon_defaultspawnfunc(this, WEP_HMG); }
-
void W_HeavyMachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
if (!PHYS_INPUT_BUTTON_ATCK(actor))
#pragma once
+#include <common/weapons/all.qh>
+
CLASS(HeavyMachineGun, Weapon)
+/* spawnfunc */ ATTRIB(HeavyMachineGun, m_canonical_spawnfunc, string, "weapon_hmg");
/* ammotype */ ATTRIB(HeavyMachineGun, ammo_type, int, RESOURCE_BULLETS);
/* impulse */ ATTRIB(HeavyMachineGun, impulse, int, 3);
/* flags */ ATTRIB(HeavyMachineGun, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_SUPERWEAPON);
ENDCLASS(HeavyMachineGun)
REGISTER_WEAPON(HMG, hmg, NEW(HeavyMachineGun));
+
+SPAWNFUNC_WEAPON(weapon_hmg, WEP_HMG)
#include "rpc.qh"
#ifdef SVQC
-spawnfunc(weapon_rpc) { weapon_defaultspawnfunc(this, WEP_RPC); }
void W_RocketPropelledChainsaw_Explode(entity this, entity directhitentity)
{
#pragma once
+#include <common/weapons/all.qh>
+
CLASS(RocketPropelledChainsaw, Weapon)
+/* spawnfunc */ ATTRIB(RocketPropelledChainsaw, m_canonical_spawnfunc, string, "weapon_rpc");
/* ammotype */ ATTRIB(RocketPropelledChainsaw, ammo_type, int, RESOURCE_ROCKETS);
/* impulse */ ATTRIB(RocketPropelledChainsaw, impulse, int, 9);
/* flags */ ATTRIB(RocketPropelledChainsaw, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH | WEP_FLAG_SUPERWEAPON);
ENDCLASS(RocketPropelledChainsaw)
REGISTER_WEAPON(RPC, rpc, NEW(RocketPropelledChainsaw));
+
+SPAWNFUNC_WEAPON(weapon_rpc, WEP_RPC)
bool autocvar_g_overkill_itemwaypoints = true;
-bool autocvar_g_overkill_filter_healthmega;
-bool autocvar_g_overkill_filter_armormedium;
-bool autocvar_g_overkill_filter_armorbig;
-bool autocvar_g_overkill_filter_armormega;
-
-.float ok_item;
-
.Weapon ok_lastwep[MAX_WEAPONSLOTS];
-void ok_Initialize();
-
REGISTER_MUTATOR(ok, expr_evaluate(autocvar_g_overkill) && !cvar("g_instagib") && !g_nexball && cvar_string("g_mod_balance") == "Overkill")
{
MUTATOR_ONADD
{
- ok_Initialize();
+ precache_all_playermodels("models/ok_player/*.dpm");
+
+ if (autocvar_g_overkill_filter_healthmega)
+ {
+ ITEM_HealthMega.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
+ }
+ if (autocvar_g_overkill_filter_armormedium)
+ {
+ ITEM_ArmorMedium.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
+ }
+ if (autocvar_g_overkill_filter_armorbig)
+ {
+ ITEM_ArmorBig.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
+ }
+ if (autocvar_g_overkill_filter_armormega)
+ {
+ ITEM_ArmorMega.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
+ }
+
+ WEP_RPC.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+ WEP_HMG.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+
+ WEP_SHOTGUN.mdl = "ok_shotgun";
+ WEP_MACHINEGUN.mdl = "ok_mg";
+ WEP_VORTEX.mdl = "ok_sniper";
}
MUTATOR_ONREMOVE
{
+ ITEM_HealthMega.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
+ ITEM_ArmorMedium.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
+ ITEM_ArmorBig.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
+ ITEM_ArmorMega.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
+
WEP_RPC.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
WEP_HMG.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
}
}
void W_Blaster_Attack(entity, .entity, float, float, float, float, float, float, float, float, float, float);
-spawnfunc(weapon_hmg);
-spawnfunc(weapon_rpc);
MUTATOR_HOOKFUNCTION(ok, Damage_Calculate, CBC_ORDER_LAST)
{
void ok_DropItem(entity this, entity targ)
{
- entity e = new(droppedweapon); // hax
+ entity e = spawn();
e.ok_item = true;
- e.noalign = true;
- e.pickup_anyway = true;
- e.spawnfunc_checked = true;
- spawnfunc_item_armor_small(e);
- if (!wasfreed(e)) { // might have been blocked by a mutator
- set_movetype(e, MOVETYPE_TOSS);
- e.gravity = 1;
- e.reset = SUB_Remove;
- setorigin(e, this.origin + '0 0 32');
- e.velocity = '0 0 200' + normalize(targ.origin - this.origin) * 500;
- SUB_SetFade(e, time + 5, 1);
- }
+ Item_InitializeLoot(e, "item_armor_small", this.origin + '0 0 32',
+ '0 0 200' + normalize(targ.origin - this.origin) * 500, 5);
}
MUTATOR_HOOKFUNCTION(ok, PlayerDies)
wep.nextthink = time + 0.1;
return true;
}
- else if(ent.classname == "item_invincible")
+ else if(ent.classname == "item_shield")
{
entity wep = new(weapon_rpc);
setorigin(wep, ent.origin);
if(item.ok_item)
return false;
- switch(item.itemdef)
- {
- case ITEM_HealthMega: return autocvar_g_overkill_filter_healthmega;
- case ITEM_ArmorMedium: return autocvar_g_overkill_filter_armormedium;
- case ITEM_ArmorBig: return autocvar_g_overkill_filter_armorbig;
- case ITEM_ArmorMega: return autocvar_g_overkill_filter_armormega;
- }
-
return true;
}
M_ARGV(0, string) = "Overkill";
return true;
}
-
-void ok_Initialize()
-{
- precache_all_playermodels("models/ok_player/*.dpm");
-
- WEP_RPC.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
- WEP_HMG.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
-
- WEP_SHOTGUN.mdl = "ok_shotgun";
- WEP_MACHINEGUN.mdl = "ok_mg";
- WEP_VORTEX.mdl = "ok_sniper";
-}
#pragma once
+
+bool autocvar_g_overkill_filter_healthmega;
+bool autocvar_g_overkill_filter_armormedium;
+bool autocvar_g_overkill_filter_armorbig;
+bool autocvar_g_overkill_filter_armormega;
+
+.float ok_item;
--- /dev/null
+// generated file; do not modify
+#ifdef SVQC
+ #include <common/mutators/mutator/random_items/sv_random_items.qc>
+#endif
--- /dev/null
+// generated file; do not modify
+#ifdef SVQC
+ #include <common/mutators/mutator/random_items/sv_random_items.qh>
+#endif
--- /dev/null
+#include "sv_random_items.qh"
+
+/// \file
+/// \brief Source file that contains implementation of the random items mutator.
+/// \author Lyberta
+/// \copyright GNU GPLv2 or any later version.
+
+//============================ Constants ======================================
+
+enum
+{
+ RANDOM_ITEM_TYPE_HEALTH = 1,
+ RANDOM_ITEM_TYPE_ARMOR,
+ RANDOM_ITEM_TYPE_RESOURCE,
+ RANDOM_ITEM_TYPE_WEAPON,
+ RANDOM_ITEM_TYPE_POWERUP
+};
+
+//======================= Global variables ====================================
+
+// Replace cvars
+
+/// \brief Classnames to replace %s with.
+/// string autocvar_g_random_items_replace_%s;
+
+// Map probability cvars
+
+/// \brief Probability of random %s spawning in the map.
+/// float autocvar_g_random_items_%s_probability;
+
+/// \brief Probability of random %s spawning in the map during overkill.
+/// float autocvar_g_random_items_overkill_%s_probability;
+
+// Loot
+
+bool autocvar_g_random_loot; ///< Whether to enable random loot.
+
+float autocvar_g_random_loot_min; ///< Minimum amount of loot items.
+float autocvar_g_random_loot_max; ///< Maximum amount of loot items.
+float autocvar_g_random_loot_time; ///< Amount of time the loot will stay.
+float autocvar_g_random_loot_spread; ///< How far can loot be thrown.
+
+// Loot probability cvars
+
+/// \brief Probability of random %s spawning as loot.
+/// float autocvar_g_random_loot_%s_probability;
+
+/// \brief Probability of random %s spawning as loot during overkill.
+/// float autocvar_g_random_loot_overkill_%s_probability;
+
+/// \brief Holds whether random item is spawning. Used to prevent infinite
+/// recursion.
+bool random_items_is_spawning = false;
+
+//====================== Forward declarations =================================
+
+/// \brief Returns a random classname of the item with specific property.
+/// \param[in] prefix Prefix of the cvars that hold probabilities.
+/// \return Random classname of the item.
+string RandomItems_GetRandomItemClassNameWithProperty(string prefix,
+ .bool item_property);
+
+//=========================== Public API ======================================
+
+string RandomItems_GetRandomItemClassName(string prefix)
+{
+ if (autocvar_g_instagib)
+ {
+ return RandomItems_GetRandomInstagibItemClassName(prefix);
+ }
+ if (expr_evaluate(autocvar_g_overkill))
+ {
+ return RandomItems_GetRandomOverkillItemClassName(prefix);
+ }
+ return RandomItems_GetRandomVanillaItemClassName(prefix);
+}
+
+string RandomItems_GetRandomVanillaItemClassName(string prefix)
+{
+ RandomSelection_Init();
+ string cvar_name = sprintf("g_%s_health_probability", prefix);
+ if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+ {
+ LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
+ }
+ else
+ {
+ RandomSelection_AddFloat(RANDOM_ITEM_TYPE_HEALTH, cvar(cvar_name), 1);
+ }
+ cvar_name = sprintf("g_%s_armor_probability", prefix);
+ if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+ {
+ LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
+ }
+ else
+ {
+ RandomSelection_AddFloat(RANDOM_ITEM_TYPE_ARMOR, cvar(cvar_name), 1);
+ }
+ cvar_name = sprintf("g_%s_resource_probability", prefix);
+ if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+ {
+ LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
+ }
+ else
+ {
+ RandomSelection_AddFloat(RANDOM_ITEM_TYPE_RESOURCE, cvar(cvar_name), 1);
+ }
+ cvar_name = sprintf("g_%s_weapon_probability", prefix);
+ if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+ {
+ LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
+ }
+ else
+ {
+ RandomSelection_AddFloat(RANDOM_ITEM_TYPE_WEAPON, cvar(cvar_name), 1);
+ }
+ cvar_name = sprintf("g_%s_powerup_probability", prefix);
+ if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+ {
+ LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
+ }
+ else
+ {
+ RandomSelection_AddFloat(RANDOM_ITEM_TYPE_POWERUP, cvar(cvar_name), 1);
+ }
+ int item_type = RandomSelection_chosen_float;
+ switch (item_type)
+ {
+ case RANDOM_ITEM_TYPE_HEALTH:
+ {
+ return RandomItems_GetRandomItemClassNameWithProperty(prefix,
+ instanceOfHealth);
+ }
+ case RANDOM_ITEM_TYPE_ARMOR:
+ {
+ return RandomItems_GetRandomItemClassNameWithProperty(prefix,
+ instanceOfArmor);
+ }
+ case RANDOM_ITEM_TYPE_RESOURCE:
+ {
+ return RandomItems_GetRandomItemClassNameWithProperty(prefix,
+ instanceOfAmmo);
+ }
+ case RANDOM_ITEM_TYPE_WEAPON:
+ {
+ RandomSelection_Init();
+ FOREACH(Weapons, it != WEP_Null &&
+ !(it.spawnflags & WEP_FLAG_MUTATORBLOCKED),
+ {
+ cvar_name = sprintf("g_%s_%s_probability", prefix,
+ it.m_canonical_spawnfunc);
+ if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+ {
+ LOG_WARNF("Random items: cvar %s doesn't exist.",
+ cvar_name);
+ continue;
+ }
+ RandomSelection_AddString(it.m_canonical_spawnfunc,
+ cvar(cvar_name), 1);
+ });
+ return RandomSelection_chosen_string;
+ }
+ case RANDOM_ITEM_TYPE_POWERUP:
+ {
+ return RandomItems_GetRandomItemClassNameWithProperty(prefix,
+ instanceOfPowerup);
+ }
+ }
+ return "";
+}
+
+string RandomItems_GetRandomInstagibItemClassName(string prefix)
+{
+ RandomSelection_Init();
+ FOREACH(Items, it.spawnflags & ITEM_FLAG_INSTAGIB,
+ {
+ string cvar_name = sprintf("g_%s_%s_probability", prefix,
+ it.m_canonical_spawnfunc);
+ if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+ {
+ LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
+ continue;
+ }
+ RandomSelection_AddString(it.m_canonical_spawnfunc, cvar(cvar_name), 1);
+ });
+ return RandomSelection_chosen_string;
+}
+
+string RandomItems_GetRandomOverkillItemClassName(string prefix)
+{
+ RandomSelection_Init();
+ FOREACH(Items, (it.spawnflags & ITEM_FLAG_OVERKILL) &&
+ !(it.spawnflags & ITEM_FLAG_MUTATORBLOCKED),
+ {
+ string cvar_name = sprintf("g_%s_overkill_%s_probability", prefix,
+ it.m_canonical_spawnfunc);
+ if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+ {
+ LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
+ continue;
+ }
+ RandomSelection_AddString(it.m_canonical_spawnfunc, cvar(cvar_name), 1);
+ });
+ string cvar_name = sprintf("g_%s_overkill_weapon_hmg_probability", prefix);
+ if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+ {
+ LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
+ }
+ else
+ {
+ RandomSelection_AddString("weapon_hmg", cvar(cvar_name), 1);
+ }
+ cvar_name = sprintf("g_%s_overkill_weapon_rpc_probability", prefix);
+ if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+ {
+ LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
+ }
+ else
+ {
+ RandomSelection_AddString("weapon_rpc", cvar(cvar_name), 1);
+ }
+ return RandomSelection_chosen_string;
+}
+
+//========================= Free functions ====================================
+
+/// \brief Returns list of classnames to replace a map item with.
+/// \param[in] item Item to inspect.
+/// \return List of classnames to replace a map item with.
+string RandomItems_GetItemReplacementClassNames(entity item)
+{
+ string cvar_name = sprintf("g_random_items_replace_%s", item.classname);
+ if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+ {
+ LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
+ return "";
+ }
+ return cvar_string(cvar_name);
+}
+
+string RandomItems_GetRandomItemClassNameWithProperty(string prefix,
+ .bool item_property)
+{
+ RandomSelection_Init();
+ FOREACH(Items, it.item_property && (it.spawnflags & ITEM_FLAG_NORMAL),
+ {
+ string cvar_name = sprintf("g_%s_%s_probability", prefix,
+ it.m_canonical_spawnfunc);
+ if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+ {
+ LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
+ continue;
+ }
+ RandomSelection_AddString(it.m_canonical_spawnfunc, cvar(cvar_name), 1);
+ });
+ return RandomSelection_chosen_string;
+}
+
+/// \brief Replaces a map item.
+/// \param[in] item Item to replace.
+/// \return Spawned item on success, NULL otherwise.
+entity RandomItems_ReplaceMapItem(entity item)
+{
+ //PrintToChatAll(strcat("Replacing ", item.classname));
+ string new_classnames = RandomItems_GetItemReplacementClassNames(item);
+ if (new_classnames == "")
+ {
+ return NULL;
+ }
+ string new_classname;
+ if (new_classnames == "random")
+ {
+ new_classname = RandomItems_GetRandomItemClassName("random_items");
+ if (new_classname == "")
+ {
+ return NULL;
+ }
+ }
+ else
+ {
+ int num_new_classnames = tokenize_console(new_classnames);
+ if (num_new_classnames == 1)
+ {
+ new_classname = new_classnames;
+ }
+ else
+ {
+ int classname_index = floor(random() * num_new_classnames);
+ new_classname = argv(classname_index);
+ }
+ }
+ //PrintToChatAll(strcat("Replacing with ", new_classname));
+ if (new_classname == item.classname)
+ {
+ return NULL;
+ }
+ random_items_is_spawning = true;
+ entity new_item;
+ if (!expr_evaluate(autocvar_g_overkill))
+ {
+ new_item = Item_Create(strzone(new_classname), item.origin,
+ item.noalign);
+ random_items_is_spawning = false;
+ if (new_item == NULL)
+ {
+ return NULL;
+ }
+ }
+ else
+ {
+ new_item = spawn();
+ new_item.classname = strzone(new_classname);
+ new_item.spawnfunc_checked = true;
+ new_item.noalign = item.noalign;
+ new_item.ok_item = true;
+ Item_Initialize(new_item, new_classname);
+ random_items_is_spawning = false;
+ if (wasfreed(new_item))
+ {
+ return NULL;
+ }
+ setorigin(new_item, item.origin);
+ }
+ if (item.team)
+ {
+ new_item.team = item.team;
+ }
+ return new_item;
+}
+
+/// \brief Spawns a random loot item.
+/// \param[in] position Position of the item.
+/// \return No return.
+void RandomItems_SpawnLootItem(vector position)
+{
+ string class_name = RandomItems_GetRandomItemClassName("random_loot");
+ if (class_name == "")
+ {
+ return;
+ }
+ vector spread = '0 0 0';
+ spread.z = autocvar_g_random_loot_spread / 2;
+ spread += randomvec() * autocvar_g_random_loot_spread;
+ random_items_is_spawning = true;
+ if (!expr_evaluate(autocvar_g_overkill))
+ {
+ Item_CreateLoot(class_name, position, spread,
+ autocvar_g_random_loot_time);
+ }
+ else
+ {
+ entity item = spawn();
+ item.ok_item = true;
+ item.classname = class_name;
+ Item_InitializeLoot(item, class_name, position, spread,
+ autocvar_g_random_loot_time);
+ }
+ random_items_is_spawning = false;
+}
+
+//============================= Hooks ========================================
+
+REGISTER_MUTATOR(random_items, (autocvar_g_random_items ||
+ autocvar_g_random_loot));
+
+MUTATOR_HOOKFUNCTION(random_items, BuildMutatorsString)
+{
+ M_ARGV(0, string) = strcat(M_ARGV(0, string), ":random_items");
+}
+
+MUTATOR_HOOKFUNCTION(random_items, BuildMutatorsPrettyString)
+{
+ M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Random items");
+}
+
+/// \brief Hook that is called when an item is about to spawn.
+MUTATOR_HOOKFUNCTION(random_items, FilterItem, CBC_ORDER_LAST)
+{
+ //PrintToChatAll("FilterItem");
+ if (!autocvar_g_random_items)
+ {
+ return false;
+ }
+ if (random_items_is_spawning == true)
+ {
+ return false;
+ }
+ entity item = M_ARGV(0, entity);
+ if (Item_IsLoot(item))
+ {
+ return false;
+ }
+ if (RandomItems_ReplaceMapItem(item) == NULL)
+ {
+ return false;
+ }
+ return true;
+}
+
+/// \brief Hook that is called after the player has touched an item.
+MUTATOR_HOOKFUNCTION(random_items, ItemTouched, CBC_ORDER_LAST)
+{
+ //PrintToChatAll("ItemTouched");
+ if (!autocvar_g_random_items)
+ {
+ return;
+ }
+ entity item = M_ARGV(0, entity);
+ if (Item_IsLoot(item))
+ {
+ return;
+ }
+ entity new_item = RandomItems_ReplaceMapItem(item);
+ if (new_item == NULL)
+ {
+ return;
+ }
+ Item_ScheduleRespawn(new_item);
+ delete(item);
+}
+
+/// \brief Hook which is called when the player dies.
+MUTATOR_HOOKFUNCTION(random_items, PlayerDies)
+{
+ //PrintToChatAll("PlayerDies");
+ if (!autocvar_g_random_loot)
+ {
+ return;
+ }
+ entity victim = M_ARGV(2, entity);
+ vector loot_position = victim.origin + '0 0 32';
+ int num_loot_items = floor(autocvar_g_random_loot_min + random() *
+ autocvar_g_random_loot_max);
+ for (int item_index = 0; item_index < num_loot_items; ++item_index)
+ {
+ RandomItems_SpawnLootItem(loot_position);
+ }
+}
--- /dev/null
+#pragma once
+
+/// \file
+/// \brief Header file that describes the random items mutator.
+/// \author Lyberta
+/// \copyright GNU GPLv2 or any later version.
+
+bool autocvar_g_random_items; ///< Whether to enable random items.
+
+/// \brief Returns a random classname of the item.
+/// \param[in] prefix Prefix of the cvars that hold probabilities.
+/// \return Random classname of the item.
+/// \note This function will automatically detect gamemode and use cvars from
+/// that gamemode.
+string RandomItems_GetRandomItemClassName(string prefix);
+
+/// \brief Returns a random classname of the vanilla item.
+/// \param[in] prefix Prefix of the cvars that hold probabilities.
+/// \return Random classname of the vanilla item.
+/// \note This includes mutator items that don't change gameplay a lot such as
+/// jetpack and new toys.
+string RandomItems_GetRandomVanillaItemClassName(string prefix);
+
+/// \brief Returns a random classname of the instagib item.
+/// \param[in] prefix Prefix of the cvars that hold probabilities.
+/// \return Random classname of the instagib item.
+string RandomItems_GetRandomInstagibItemClassName(string prefix);
+
+/// \brief Returns a random classname of the overkill item.
+/// \param[in] prefix Prefix of the cvars that hold probabilities.
+/// \return Random classname of the overkill item.
+string RandomItems_GetRandomOverkillItemClassName(string prefix);
--- /dev/null
+// generated file; do not modify
+#ifdef SVQC
+ #include <common/mutators/mutator/stale_move_negation/sv_stale_move_negation.qc>
+#endif
--- /dev/null
+// generated file; do not modify
+#ifdef SVQC
+ #include <common/mutators/mutator/stale_move_negation/sv_stale_move_negation.qh>
+#endif
--- /dev/null
+#include "sv_stale_move_negation.qh"
+
+AUTOCVAR(g_smneg, bool, false, "Stale-move negation: penalize repeated use of the same weapon");
+AUTOCVAR(g_smneg_bonus, bool, true, "Stale-move negation: allow weapons to become stronger than their baseline");
+AUTOCVAR(g_smneg_bonus_asymptote, float, 4, "Stale-move negation: damage = infinity at this bonus level");
+AUTOCVAR(g_smneg_cooldown_factor, float, 1 / 4, "Stale-move negation: penalty cooldown factor");
+REGISTER_MUTATOR(mutator_smneg, autocvar_g_smneg);
+
+MUTATOR_HOOKFUNCTION(mutator_smneg, BuildMutatorsString) {
+ M_ARGV(0, string) = strcat(M_ARGV(0, string), ":StaleMoveNegation");
+}
+
+MUTATOR_HOOKFUNCTION(mutator_smneg, BuildMutatorsPrettyString) {
+ M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Stale-move negation");
+}
+
+.float x_smneg_weight[Weapons_MAX];
+
+float smneg_multiplier(float weight) {
+ float a = autocvar_g_smneg_bonus_asymptote;
+ float x = max(
+ (!autocvar_g_smneg_bonus ? 0 : (-a + .1)),
+ weight / start_health
+ );
+ float z = (M_PI / 5) * a;
+ float f = (x > 0)
+ ? (atan(z / x) / (M_PI / 2))
+ : (tan(-(x / z)) + 1);
+ return f;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_smneg, Damage_Calculate) {
+ float deathtype = M_ARGV(3, float);
+ Weapon w = DEATH_WEAPONOF(deathtype);
+ if (w == WEP_Null) return;
+
+ entity frag_attacker = M_ARGV(1, entity);
+ entity c = CS(frag_attacker);
+ float weight = c.x_smneg_weight[w.m_id];
+ float f = smneg_multiplier(weight);
+ float frag_damage = M_ARGV(4, float) = f * M_ARGV(4, float);
+ M_ARGV(6, vector) = f * M_ARGV(6, vector); // force
+
+ c.x_smneg_weight[w.m_id] = weight + frag_damage;
+ float restore = frag_damage * autocvar_g_smneg_cooldown_factor;
+ FOREACH(Weapons, it != WEP_Null && it != w, {
+ c.x_smneg_weight[it.m_id] -= restore;
+ });
+}
--- /dev/null
+#pragma once
MSG_INFO_NOTIF(QUIT_DISCONNECT, N_CHATCON, 1, 0, "s1", "", "", _("^BG%s^F3 disconnected"), "")
MSG_INFO_NOTIF(QUIT_KICK_IDLING, N_CHATCON, 1, 0, "s1", "", "", _("^BG%s^F3 was kicked for idling"), "")
MSG_INFO_NOTIF(QUIT_KICK_SPECTATING, N_CONSOLE, 0, 0, "", "", "", _("^F2You were kicked from the server because you are a spectator and spectators aren't allowed at the moment."), "")
+ MSG_INFO_NOTIF(QUIT_KICK_TEAMKILL, N_CHATCON, 1, 0, "s1", "", "", _("^BG%s^F3 was kicked for excessive teamkilling"), "")
MSG_INFO_NOTIF(QUIT_SPECTATE, N_CONSOLE, 1, 0, "s1", "", "", _("^BG%s^F3 is now spectating"), "")
MSG_INFO_NOTIF(RACE_ABANDONED, N_CONSOLE, 1, 0, "s1", "", "", _("^BG%s^BG has abandoned the race"), "")
_Movetype_CheckWater(this);
this.origin = this.origin + movedt * this.velocity;
this.angles = this.angles + movedt * this.avelocity;
- _Movetype_LinkEdict(this, false);
break;
case MOVETYPE_STEP:
_Movetype_Physics_Step(this, movedt);
case MOVETYPE_PHYSICS:
break;
}
+
+ //_Movetype_CheckVelocity(this);
+
+ _Movetype_LinkEdict(this, true);
+
+ //_Movetype_CheckVelocity(this);
}
void Movetype_Physics_NoMatchTicrate(entity this, float movedt, bool isclient) // to be run every move frame
STAT(MOVEVARS_AIRACCELERATE, this) = Physics_ClientOption(this, "airaccelerate", autocvar_sv_airaccelerate);
STAT(MOVEVARS_AIRSTOPACCELERATE, this) = Physics_ClientOption(this, "airstopaccelerate", autocvar_sv_airstopaccelerate);
STAT(MOVEVARS_JUMPVELOCITY, this) = Physics_ClientOption(this, "jumpvelocity", autocvar_sv_jumpvelocity);
+ STAT(MOVEVARS_JUMPVELOCITY_CROUCH, this) = Physics_ClientOption(this, "jumpvelocity_crouch", autocvar_sv_jumpvelocity_crouch);
STAT(MOVEVARS_TRACK_CANJUMP, this) = Physics_ClientOption(this, "track_canjump", autocvar_sv_track_canjump);
}
#endif
#endif
bool doublejump = false;
- float mjumpheight = PHYS_JUMPVELOCITY(this);
+ float mjumpheight = ((PHYS_JUMPVELOCITY_CROUCH(this) && IS_DUCKED(this)) ? PHYS_JUMPVELOCITY_CROUCH(this) : PHYS_JUMPVELOCITY(this));
bool track_jump = PHYS_CL_TRACK_CANJUMP(this);
if (MUTATOR_CALLHOOK(PlayerJump, this, mjumpheight, doublejump))
#define PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS(s) STAT(MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS)
#define PHYS_JUMPVELOCITY(s) STAT(MOVEVARS_JUMPVELOCITY, s)
+#define PHYS_JUMPVELOCITY_CROUCH(s) STAT(MOVEVARS_JUMPVELOCITY_CROUCH, s)
#define PHYS_MAXAIRSPEED(s) STAT(MOVEVARS_MAXAIRSPEED, s)
#define PHYS_MAXAIRSTRAFESPEED(s) STAT(MOVEVARS_MAXAIRSTRAFESPEED, s)
}
}
-// referred to by PS_GR_P_ADDVAL and PS_GR_T_ADDVAL
float PlayerStats_GameReport_Event(string prefix, string event_id, float value)
{
if((prefix == "") || PS_GR_OUT_DB < 0) { return 0; }
void PlayerStats_GameReport_Accuracy(entity p)
{
#define ACCMAC(suffix, field) \
- PS_GR_P_ADDVAL(p, sprintf("acc-%s-%s", it.netname, suffix), CS(p).accuracy.(field[i-1]));
+ PlayerStats_GameReport_Event_Player(p, \
+ sprintf("acc-%s-%s", it.netname, suffix), CS(p).accuracy.(field[i-1]));
FOREACH(Weapons, it != WEP_Null, {
ACCMAC("hit", accuracy_hit)
ACCMAC("fired", accuracy_fired)
// add global info!
if(p.alivetime)
{
- PS_GR_P_ADDVAL(p, PLAYERSTATS_ALIVETIME, time - p.alivetime);
+ PlayerStats_GameReport_Event_Player(p, PLAYERSTATS_ALIVETIME, time - p.alivetime);
p.alivetime = 0;
}
db_put(PS_GR_OUT_DB, sprintf("%s:_team", p.playerstats_id), ftos(p.team));
if(stof(db_get(PS_GR_OUT_DB, sprintf("%s:%s", p.playerstats_id, PLAYERSTATS_ALIVETIME))) > 0)
- PS_GR_P_ADDVAL(p, PLAYERSTATS_JOINS, 1);
+ PlayerStats_GameReport_Event_Player(p, PLAYERSTATS_JOINS, 1);
PlayerStats_GameReport_Accuracy(p);
anticheat_report_to_playerstats(p);
if(CS(p).latency_cnt)
{
float latency = (CS(p).latency_sum / CS(p).latency_cnt);
- if(latency) { PS_GR_P_ADDVAL(p, PLAYERSTATS_AVGLATENCY, latency); }
+ if(latency)
+ PlayerStats_GameReport_Event_Player(p, PLAYERSTATS_AVGLATENCY, latency);
}
}
FOREACH_CLIENT(true, {
// add personal score rank
- PS_GR_P_ADDVAL(it, PLAYERSTATS_RANK, it.score_dummyfield);
+ PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_RANK, it.score_dummyfield);
// scoreboard data
if(it.scoreboard_pos)
{
// scoreboard is valid!
- PS_GR_P_ADDVAL(it, PLAYERSTATS_SCOREBOARD_VALID, 1);
+ PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_SCOREBOARD_VALID, 1);
// add scoreboard position
- PS_GR_P_ADDVAL(it, PLAYERSTATS_SCOREBOARD_POS, it.scoreboard_pos);
+ PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_SCOREBOARD_POS, it.scoreboard_pos);
// add scoreboard data
PlayerScore_PlayerStats(it);
// if the match ended normally, add winning info
if(finished)
{
- PS_GR_P_ADDVAL(it, PLAYERSTATS_WINS, it.winning);
- PS_GR_P_ADDVAL(it, PLAYERSTATS_MATCHES, 1);
+ PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_WINS, it.winning);
+ PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_MATCHES, 1);
}
}
void PlayerStats_GameReport_AddEvent(string event_id);
// call on each event to track, or at player disconnect OR match end for "global stuff"
-#define PS_GR_P_ADDVAL(ent,eventid,val) PlayerStats_GameReport_Event(ent.playerstats_id, eventid, val)
-#define PS_GR_T_ADDVAL(team,eventid,val) PlayerStats_GameReport_Event(sprintf("team#%d", team), eventid, val)
+#define PlayerStats_GameReport_Event_Player(ent, eventid, val) PlayerStats_GameReport_Event(ent.playerstats_id, eventid, val)
+#define PlayerStats_GameReport_Event_Team(team, eventid, val) PlayerStats_GameReport_Event(sprintf("team#%d", team), eventid, val)
float PlayerStats_GameReport_Event(string prefix, string event_id, float value);
void PlayerStats_GameReport_Accuracy(entity p);
REGISTER_SP(KILLS);
REGISTER_SP(DEATHS);
REGISTER_SP(SUICIDES);
+REGISTER_SP(TEAMKILLS);
REGISTER_SP(FRAGS);
REGISTER_SP(ELO);
bool autocvar_sv_dodging_frozen;
bool autocvar_sv_dodging_frozen_doubletap;
float autocvar_sv_dodging_height_threshold;
-float autocvar_sv_dodging_horiz_speed;
-float autocvar_sv_dodging_horiz_speed_frozen;
+float autocvar_sv_dodging_horiz_speed_min;
+float autocvar_sv_dodging_horiz_speed_max;
+float autocvar_sv_dodging_horiz_force_slowest;
+float autocvar_sv_dodging_horiz_force_fastest;
+float autocvar_sv_dodging_horiz_force_frozen;
float autocvar_sv_dodging_ramp_time;
float autocvar_sv_dodging_up_speed;
bool autocvar_sv_dodging_wall_dodging;
bool autocvar_sv_dodging_air_dodging;
-float autocvar_sv_dodging_maxspeed = 450;
+float autocvar_sv_dodging_maxspeed;
+float autocvar_sv_dodging_air_maxspeed;
#endif
#if 0
REGISTER_STAT(DODGING, int, g_dodging)
REGISTER_STAT(DODGING_DELAY, float, autocvar_sv_dodging_delay)
REGISTER_STAT(DODGING_DISTANCE_THRESHOLD, float, autocvar_sv_dodging_wall_distance_threshold)
-REGISTER_STAT(DODGING_FROZEN_NO_DOUBLETAP, int, autocvar_sv_dodging_frozen_doubletap)
+REGISTER_STAT(DODGING_FROZEN_DOUBLETAP, int, autocvar_sv_dodging_frozen_doubletap)
REGISTER_STAT(DODGING_HEIGHT_THRESHOLD, float, autocvar_sv_dodging_height_threshold)
-REGISTER_STAT(DODGING_HORIZ_SPEED, float, autocvar_sv_dodging_horiz_speed)
-REGISTER_STAT(DODGING_HORIZ_SPEED_FROZEN, float, autocvar_sv_dodging_horiz_speed_frozen)
+REGISTER_STAT(DODGING_HORIZ_SPEED_MIN, float, autocvar_sv_dodging_horiz_speed_min)
+REGISTER_STAT(DODGING_HORIZ_SPEED_MAX, float, autocvar_sv_dodging_horiz_speed_max)
+REGISTER_STAT(DODGING_HORIZ_FORCE_SLOWEST, float, autocvar_sv_dodging_horiz_force_slowest)
+REGISTER_STAT(DODGING_HORIZ_FORCE_FASTEST, float, autocvar_sv_dodging_horiz_force_fastest)
+REGISTER_STAT(DODGING_HORIZ_FORCE_FROZEN, float, autocvar_sv_dodging_horiz_force_frozen)
REGISTER_STAT(DODGING_RAMP_TIME, float, autocvar_sv_dodging_ramp_time)
REGISTER_STAT(DODGING_UP_SPEED, float, autocvar_sv_dodging_up_speed)
REGISTER_STAT(DODGING_WALL, bool, autocvar_sv_dodging_wall_dodging)
REGISTER_STAT(DODGING_AIR, bool, autocvar_sv_dodging_air_dodging)
REGISTER_STAT(DODGING_MAXSPEED, float, autocvar_sv_dodging_maxspeed)
+REGISTER_STAT(DODGING_AIR_MAXSPEED, float, autocvar_sv_dodging_air_maxspeed)
#endif
/** cvar loopback */
REGISTER_STAT(DODGING_FROZEN, int, autocvar_sv_dodging_frozen)
#ifdef SVQC
#include "physics/movetypes/movetypes.qh"
+float warmup_limit;
#endif
REGISTER_STAT(MOVEVARS_AIRACCEL_QW_STRETCHFACTOR, float)
// FIXME: Was 0 on server, 1 on client. Still want that?
REGISTER_STAT(MOVEVARS_ENTGRAVITY, float, (this.gravity) ? this.gravity : 1)
REGISTER_STAT(MOVEVARS_JUMPVELOCITY, float)
+REGISTER_STAT(MOVEVARS_JUMPVELOCITY_CROUCH, float)
REGISTER_STAT(MOVEVARS_MAXAIRSPEED, float)
REGISTER_STAT(MOVEVARS_STEPHEIGHT, float, autocvar_sv_stepheight)
REGISTER_STAT(MOVEVARS_AIRACCEL_QW, float)
void Item_Touch(entity this, entity toucher)
{
-
// remove the item if it's currnetly in a NODROP brush or hits a NOIMPACT surface (such as sky)
- if (this.classname == "droppedweapon")
+ if (Item_IsLoot(this))
{
if (ITEM_TOUCH_NEEDKILL())
{
toucher = M_ARGV(1, entity);
- if (this.classname == "droppedweapon")
+ if (Item_IsExpiring(this))
{
this.strength_finished = max(0, this.strength_finished - time);
this.invincible_finished = max(0, this.invincible_finished - time);
this.superweapons_finished = max(0, this.superweapons_finished - time);
}
- entity it = this.itemdef;
- bool gave = ITEM_HANDLE(Pickup, it, this, toucher);
+ bool gave = ITEM_HANDLE(Pickup, this.itemdef, this, toucher);
if (!gave)
{
- if (this.classname == "droppedweapon")
+ if (Item_IsExpiring(this))
{
// undo what we did above
this.strength_finished += time;
Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
_sound (toucher, (this.itemdef.instanceOfPowerup ? CH_TRIGGER_SINGLE : CH_TRIGGER), (this.item_pickupsound ? this.item_pickupsound : Sound_fixpath(this.item_pickupsound_ent)), VOL_BASE, ATTEN_NORM);
- if (this.classname == "droppedweapon")
+ MUTATOR_CALLHOOK(ItemTouched, this, toucher);
+ if (wasfreed(this))
+ {
+ return;
+ }
+
+ if (Item_IsLoot(this))
+ {
delete(this);
- else if (this.spawnshieldtime)
+ return;
+ }
+ if (!this.spawnshieldtime)
{
- entity e;
- if(this.team)
+ return;
+ }
+ entity e;
+ if (this.team)
+ {
+ RandomSelection_Init();
+ IL_EACH(g_items, it.team == this.team,
{
- RandomSelection_Init();
- IL_EACH(g_items, it.team == this.team,
+ if (it.itemdef) // is a registered item
{
- if(it.itemdef) // is a registered item
- {
- Item_Show(it, -1);
- it.scheduledrespawntime = 0;
- RandomSelection_AddEnt(it, it.cnt, 0);
- }
- });
- e = RandomSelection_chosen_ent;
- Item_Show(e, 1); // reset its state so it is visible (extra sendflags doesn't matter, this happens anyway)
- }
- else
- e = this;
- Item_ScheduleRespawn(e);
+ Item_Show(it, -1);
+ it.scheduledrespawntime = 0;
+ RandomSelection_AddEnt(it, it.cnt, 0);
+ }
+ });
+ e = RandomSelection_chosen_ent;
+ Item_Show(e, 1); // reset its state so it is visible (extra sendflags doesn't matter, this happens anyway)
}
+ else
+ e = this;
+ Item_ScheduleRespawn(e);
}
void Item_Reset(entity this)
Item_Show(this, !this.state);
setorigin(this, this.origin);
- if (this.classname != "droppedweapon")
+ if (Item_IsLoot(this))
{
- setthink(this, Item_Think);
- this.nextthink = time;
-
- if (this.waypointsprite_attached)
- WaypointSprite_Kill(this.waypointsprite_attached);
-
- if (this.itemdef.instanceOfPowerup || (this.weapons & WEPSET_SUPERWEAPONS)) // do not spawn powerups initially!
- Item_ScheduleInitialRespawn(this);
+ return;
+ }
+ setthink(this, Item_Think);
+ this.nextthink = time;
+ if (this.waypointsprite_attached)
+ {
+ WaypointSprite_Kill(this.waypointsprite_attached);
+ }
+ if (this.itemdef.instanceOfPowerup || (this.weapons & WEPSET_SUPERWEAPONS)) // do not spawn powerups initially!
+ {
+ Item_ScheduleInitialRespawn(this);
}
}
return;
}
- // is it a dropped weapon?
- if (this.classname == "droppedweapon")
+ if (Item_IsLoot(this))
{
this.reset = SUB_Remove;
- // it's a dropped weapon
set_movetype(this, MOVETYPE_TOSS);
// Savage: remove thrown items after a certain period of time ("garbage collection")
this.takedamage = DAMAGE_YES;
this.event_damage = Item_Damage;
- if(this.strength_finished || this.invincible_finished || this.superweapons_finished)
+ if (Item_IsExpiring(this))
{
// if item is worthless after a timer, have it expire then
this.nextthink = max(this.strength_finished, this.invincible_finished, this.superweapons_finished);
if(def.instanceOfWeaponPickup)
{
- if (this.classname != "droppedweapon") // if dropped, colormap is already set up nicely
+ if (!Item_IsLoot(this)) // if dropped, colormap is already set up nicely
this.colormap = 1024; // color shirt=0 pants=0 grey
else
this.gravity = 1;
void StartItem(entity this, GameItem def)
{
+ def = def.m_spawnfunc_hookreplace(def, this);
+ if (def.spawnflags & ITEM_FLAG_MUTATORBLOCKED)
+ {
+ delete(this);
+ return;
+ }
+ this.classname = def.m_canonical_spawnfunc;
_StartItem(
this,
this.itemdef = def,
}
}
-spawnfunc(item_rockets)
-{
- StartItem(this, ITEM_Rockets);
-}
-
-spawnfunc(item_bullets)
-{
- if(!weaponswapping && autocvar_sv_q3acompat_machineshotgunswap &&
- (this.classname != "droppedweapon"))
- {
- weaponswapping = true;
- spawnfunc_item_shells(this);
- weaponswapping = false;
- return;
- }
-
- StartItem(this, ITEM_Bullets);
-}
-
-spawnfunc(item_cells)
-{
- StartItem(this, ITEM_Cells);
-}
-
-spawnfunc(item_plasma)
-{
- StartItem(this, ITEM_Plasma);
-}
-
-spawnfunc(item_shells)
-{
- if(!weaponswapping && autocvar_sv_q3acompat_machineshotgunswap &&
- (this.classname != "droppedweapon"))
- {
- weaponswapping = true;
- spawnfunc_item_bullets(this);
- weaponswapping = false;
- return;
- }
-
- StartItem(this, ITEM_Shells);
-}
-
-spawnfunc(item_armor_small)
-{
- StartItem(this, ITEM_ArmorSmall);
-}
-
-spawnfunc(item_armor_medium)
-{
- StartItem(this, ITEM_ArmorMedium);
-}
-
-spawnfunc(item_armor_big)
-{
- StartItem(this, ITEM_ArmorBig);
-}
-
-spawnfunc(item_armor_mega)
-{
- StartItem(this, ITEM_ArmorMega);
-}
-
-spawnfunc(item_health_small)
-{
- StartItem(this, ITEM_HealthSmall);
-}
-
-spawnfunc(item_health_medium)
-{
- StartItem(this, ITEM_HealthMedium);
-}
-
-spawnfunc(item_health_big)
-{
- StartItem(this, ITEM_HealthBig);
-}
-
-spawnfunc(item_health_mega)
-{
- StartItem(this, ITEM_HealthMega);
-}
-
-// 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_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)
-{
- StartItem(this, ITEM_Strength);
-}
-
-spawnfunc(item_invincible)
-{
- StartItem(this, ITEM_Shield);
-}
-
-// compatibility:
-spawnfunc(item_quad) { this.classname = "item_strength";spawnfunc_item_strength(this);}
-
void target_items_use(entity this, entity actor, entity trigger)
{
- if(actor.classname == "droppedweapon")
+ if(Item_IsLoot(actor))
{
EXACTTRIGGER_TOUCH(this, trigger);
delete(actor);
EXACTTRIGGER_TOUCH(this, trigger);
}
- IL_EACH(g_items, it.enemy == actor && it.classname == "droppedweapon",
+ IL_EACH(g_items, it.enemy == actor && Item_IsLoot(it),
{
delete(it);
});
}
}
-spawnfunc(item_fuel)
-{
- StartItem(this, ITEM_JetpackFuel);
-}
-
-spawnfunc(item_fuel_regen)
-{
- if(start_items & ITEM_JetpackRegen.m_itemid)
- {
- spawnfunc_item_fuel(this);
- return;
- }
- StartItem(this, ITEM_JetpackRegen);
-}
-
-spawnfunc(item_jetpack)
-{
- if(start_items & ITEM_Jetpack.m_itemid)
- {
- spawnfunc_item_fuel(this);
- return;
- }
- StartItem(this, ITEM_Jetpack);
-}
-
float GiveWeapon(entity e, float wpn, float op, float val)
{
WepSet v0, v1;
#pragma once
-#ifdef SVQC
-#include <server/defs.qh>
-#endif
-
const int AMMO_COUNT = 4; // amount of ammo types to show in the inventory panel
// item networking
#endif
#ifdef SVQC
-spawnfunc(item_strength);
-spawnfunc(item_invincible);
-spawnfunc(item_armor_small);
-spawnfunc(item_shells);
-spawnfunc(item_bullets);
-spawnfunc(item_rockets);
float autocvar_sv_simple_items;
bool ItemSend(entity this, entity to, int sf);
-
bool have_pickup_item(entity this);
const float ITEM_RESPAWN_TICKS = 10;
if(this.spawnflags & DOOR_NOSPLASH)
if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
return;
- this.health = this.health - damage;
- if (this.health <= 0)
+ if (this.spawnflags & BUTTON_DONTACCUMULATEDMG)
{
- this.enemy = attacker;
- button_fire(this);
+ if (this.health <= damage)
+ {
+ this.enemy = attacker;
+ button_fire(this);
+ }
+ }
+ else
+ {
+ this.health = this.health - damage;
+ if (this.health <= 0)
+ {
+ this.enemy = attacker;
+ button_fire(this);
+ }
}
}
#pragma once
+
+const int BUTTON_DONTACCUMULATEDMG = 128;
spawnfunc_info_teleport_destination(this);
}
-spawnfunc(target_teleporter)
-{
- spawnfunc_info_teleport_destination(this);
-}
-
#elif defined(CSQC)
void teleport_dest_remove(entity this)
void teleport_findtarget(entity this)
{
+ bool istrigger = (this.solid == SOLID_TRIGGER);
+
int n = 0;
- entity e;
- for(e = NULL; (e = find(e, targetname, this.target)); )
+ for(entity e = NULL; (e = find(e, targetname, this.target)); )
{
++n;
#ifdef SVQC
else if(n == 1)
{
// exactly one dest - bots love that
- this.enemy = find(e, targetname, this.target);
+ this.enemy = find(NULL, targetname, this.target);
}
else
{
}
// now enable touch
- settouch(this, Teleport_Touch);
+ if(istrigger)
+ settouch(this, Teleport_Touch);
#ifdef SVQC
- trigger_teleport_link(this);
+ if(istrigger)
+ trigger_teleport_link(this);
#endif
}
if (!IS_DEAD(toucher))
if (toucher.triggerhealtime < time)
{
- EXACTTRIGGER_TOUCH(this, toucher);
+ bool is_trigger = !boolean(!this.nottargeted && this.targetname != "");
+ if(is_trigger)
+ EXACTTRIGGER_TOUCH(this, toucher);
toucher.triggerhealtime = time + 1;
if (toucher.health < this.max_health)
}
}
+void trigger_heal_use(entity this, entity actor, entity trigger)
+{
+ trigger_heal_touch(this, actor);
+}
+
spawnfunc(trigger_heal)
{
this.active = ACTIVE_ACTIVE;
this.noise = "misc/mediumhealth.wav";
precache_sound(this.noise);
}
+
+spawnfunc(target_heal)
+{
+ this.active = ACTIVE_ACTIVE;
+ this.use = trigger_heal_use;
+ if (!this.health)
+ this.health = 10;
+ if (!this.max_health)
+ this.max_health = 200; //Max health topoff for field
+ if(this.noise == "")
+ this.noise = "misc/mediumhealth.wav";
+ precache_sound(this.noise);
+}
#endif
torg = tgt.origin + (tgt.mins + tgt.maxs) * 0.5;
- grav = PHYS_GRAVITY(other);
- if(PHYS_ENTGRAVITY(other))
- grav *= PHYS_ENTGRAVITY(other);
+ grav = PHYS_GRAVITY(tgt);
+ if(PHYS_ENTGRAVITY(tgt))
+ grav *= PHYS_ENTGRAVITY(tgt);
zdist = torg.z - org.z;
sdist = vlen(torg - org - zdist * '0 0 1');
this.use = SUB_UseTargets;
this.reset = spawnfunc_trigger_relay; // this spawnfunc resets fully
}
+
+spawnfunc(target_relay) { spawnfunc_trigger_relay(this); }
#endif
}
#endif
-void Teleport_Touch(entity this, entity toucher)
+bool Teleport_Active(entity this, entity player)
{
if (this.active != ACTIVE_ACTIVE)
- return;
+ return false;
#ifdef SVQC
- if (!toucher.teleportable)
- return;
+ if (!player.teleportable)
+ return false;
- if(toucher.vehicle)
- if(!toucher.vehicle.teleportable)
- return;
+ if(player.vehicle)
+ if(!player.vehicle.teleportable)
+ return false;
- if(IS_TURRET(toucher))
- return;
+ if(IS_TURRET(player))
+ return false;
#elif defined(CSQC)
- if(!IS_PLAYER(toucher))
- return;
+ if(!IS_PLAYER(player))
+ return false;
#endif
- if(IS_DEAD(toucher))
- return;
+ if(IS_DEAD(player))
+ return false;
if(this.team)
- if(((this.spawnflags & 4) == 0) == (DIFF_TEAM(this, toucher)))
- return;
+ if(((this.spawnflags & 4) == 0) == (DIFF_TEAM(this, player)))
+ return false;
- EXACTTRIGGER_TOUCH(this, toucher);
+ return true;
+}
+
+void Teleport_Touch(entity this, entity toucher)
+{
+ entity player = toucher;
+
+ if(!Teleport_Active(this, player))
+ return;
+
+ EXACTTRIGGER_TOUCH(this, player);
#ifdef SVQC
- if(IS_PLAYER(toucher))
- RemoveGrapplingHooks(toucher);
+ if(IS_PLAYER(player))
+ RemoveGrapplingHooks(player);
#endif
entity e;
- e = Simple_TeleportPlayer(this, toucher);
+ e = Simple_TeleportPlayer(this, player);
#ifdef SVQC
string s = this.target; this.target = string_null;
- SUB_UseTargets(this, toucher, toucher); // TODO: should we be using toucher for trigger too?
+ SUB_UseTargets(this, player, player); // TODO: should we be using toucher for trigger too?
if (!this.target) this.target = s;
- SUB_UseTargets(e, toucher, toucher);
+ SUB_UseTargets(e, player, player);
#endif
}
+#ifdef SVQC
+void target_teleport_use(entity this, entity actor, entity trigger)
+{
+ entity player = actor;
+
+ if(!Teleport_Active(this, player))
+ return;
+
+ if(IS_PLAYER(player))
+ RemoveGrapplingHooks(player);
+
+ entity e = Simple_TeleportPlayer(this, player);
+
+ string s = this.target; this.target = string_null;
+ SUB_UseTargets(this, player, player); // TODO: should we be using toucher for trigger too?
+ if (!this.target) this.target = s;
+
+ SUB_UseTargets(e, player, player);
+}
+#endif
+
#ifdef SVQC
float trigger_teleport_send(entity this, entity to, float sf)
{
IL_PUSH(g_teleporters, this);
}
+
+spawnfunc(target_teleporter)
+{
+ if(this.target == "")
+ {
+ // actually a destination!
+ spawnfunc_info_teleport_destination(this);
+ return;
+ }
+
+ this.active = ACTIVE_ACTIVE;
+
+ this.use = target_teleport_use;
+
+ if(this.noise != "")
+ FOREACH_WORD(this.noise, true, precache_sound(it));
+
+ InitializeEntity(this, teleport_findtarget, INITPRIO_FINDTARGET);
+}
#elif defined(CSQC)
NET_HANDLE(ENT_CLIENT_TRIGGER_TELEPORT, bool isnew)
{
/** idle frame */
const int WS_READY = 4;
-#ifdef SVQC
-.int ammo_shells;
-.int ammo_nails;
-.int ammo_rockets;
-.int ammo_cells;
-.int ammo_plasma = _STAT(PLASMA);
-.int ammo_fuel = _STAT(FUEL);
-.int ammo_none;
-#else
-.int ammo_shells;
-.int ammo_nails;
-.int ammo_rockets;
-.int ammo_cells;
-.int ammo_plasma;
-.int ammo_fuel;
-.int ammo_none;
-#endif
-
/** fields which are explicitly/manually set are marked with "M", fields set automatically are marked with "A" */
CLASS(Weapon, Object)
ATTRIB(Weapon, m_id, int, 0);
+ /** the canonical spawnfunc name */
+ ATTRIB(Weapon, m_canonical_spawnfunc, string);
+ /** control what happens when this weapon is spawned */
+ METHOD(Weapon, m_spawnfunc_hookreplace, Weapon(Weapon this, entity e)) { return this; }
/** A: WEPSET_id : WEPSET_... */
ATTRIB(Weapon, weapons, WepSet, '0 0 0');
/** M: ammotype : main ammo type */
}
ENDCLASS(Weapon)
+#ifdef SVQC
+
+void weapon_defaultspawnfunc(entity this, Weapon e);
+#define SPAWNFUNC_WEAPON(name, weapon) \
+ spawnfunc(name) { weapon_defaultspawnfunc(this, weapon); }
+
+#else
+
+#define SPAWNFUNC_WEAPON(name, weapon)
+
+#endif
+
#include <common/items/_mod.qh>
CLASS(WeaponPickup, Pickup)
ATTRIB(WeaponPickup, m_weapon, Weapon);
#include "arc.qh"
#ifdef SVQC
-spawnfunc(weapon_arc) { weapon_defaultspawnfunc(this, WEP_ARC); }
bool W_Arc_Beam_Send(entity this, entity to, int sf)
{
#pragma once
CLASS(Arc, Weapon)
+/* spawnfunc */ ATTRIB(Arc, m_canonical_spawnfunc, string, "weapon_arc");
/* ammotype */ ATTRIB(Arc, ammo_type, int, RESOURCE_CELLS);
/* impulse */ ATTRIB(Arc, impulse, int, 3);
/* flags */ ATTRIB(Arc, spawnflags, int, WEP_TYPE_HITSCAN);
ENDCLASS(Arc)
REGISTER_WEAPON(ARC, arc, NEW(Arc));
+SPAWNFUNC_WEAPON(weapon_arc, WEP_ARC)
#ifdef GAMEQC
const float ARC_MAX_SEGMENTS = 20;
#include "blaster.qh"
#ifdef SVQC
-spawnfunc(weapon_blaster) { weapon_defaultspawnfunc(this, WEP_BLASTER); }
-spawnfunc(weapon_laser) { spawnfunc_weapon_blaster(this); }
void W_Blaster_Touch(entity this, entity toucher)
{
#pragma once
CLASS(Blaster, Weapon)
+/* spawnfunc */ ATTRIB(Blaster, m_canonical_spawnfunc, string, "weapon_blaster");
/* ammotype */ //ATTRIB(Blaster, ammo_type, int, RESOURCE_NONE);
/* impulse */ ATTRIB(Blaster, impulse, int, 1);
/* flags */ ATTRIB(Blaster, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH);
ENDCLASS(Blaster)
REGISTER_WEAPON(BLASTER, blaster, NEW(Blaster));
+SPAWNFUNC_WEAPON(weapon_blaster, WEP_BLASTER)
+SPAWNFUNC_WEAPON(weapon_laser, WEP_BLASTER)
+
#ifdef SVQC
.float blaster_damage;
.float blaster_edgedamage;
.float blaster_radius;
.float blaster_force;
.float blaster_lifetime;
+
#endif
#include "crylink.qh"
#ifdef SVQC
-spawnfunc(weapon_crylink) { weapon_defaultspawnfunc(this, WEP_CRYLINK); }
void W_Crylink_CheckLinks(entity e)
{
#pragma once
CLASS(Crylink, Weapon)
+/* spawnfunc */ ATTRIB(Crylink, m_canonical_spawnfunc, string, "weapon_crylink");
/* ammotype */ ATTRIB(Crylink, ammo_type, int, RESOURCE_CELLS);
/* impulse */ ATTRIB(Crylink, impulse, int, 6);
/* flags */ ATTRIB(Crylink, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH | WEP_FLAG_CANCLIMB | WEP_FLAG_NODUAL);
ENDCLASS(Crylink)
REGISTER_WEAPON(CRYLINK, crylink, NEW(Crylink));
+SPAWNFUNC_WEAPON(weapon_crylink, WEP_CRYLINK)
+
#ifdef SVQC
.float gravity;
.float crylink_waitrelease;
#include "devastator.qh"
#ifdef SVQC
-spawnfunc(weapon_devastator) { weapon_defaultspawnfunc(this, WEP_DEVASTATOR); }
-spawnfunc(weapon_rocketlauncher) { spawnfunc_weapon_devastator(this); }
.entity lastrocket;
#pragma once
CLASS(Devastator, Weapon)
+/* spawnfunc */ ATTRIB(Devastator, m_canonical_spawnfunc, string, "weapon_devastator");
/* ammotype */ ATTRIB(Devastator, ammo_type, int, RESOURCE_ROCKETS);
/* impulse */ ATTRIB(Devastator, impulse, int, 9);
/* flags */ ATTRIB(Devastator, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH | WEP_FLAG_NODUAL);
ENDCLASS(Devastator)
REGISTER_WEAPON(DEVASTATOR, devastator, NEW(Devastator));
+SPAWNFUNC_WEAPON(weapon_devastator, WEP_DEVASTATOR)
+SPAWNFUNC_WEAPON(weapon_rocketlauncher, WEP_DEVASTATOR)
+
#ifdef SVQC
.float rl_release;
.float rl_detonate_later;
#include "electro.qh"
#ifdef SVQC
-spawnfunc(weapon_electro) { weapon_defaultspawnfunc(this, WEP_ELECTRO); }
void W_Electro_TriggerCombo(vector org, float rad, entity own)
{
#pragma once
CLASS(Electro, Weapon)
+/* spawnfunc */ ATTRIB(Electro, m_canonical_spawnfunc, string, "weapon_electro");
/* ammotype */ ATTRIB(Electro, ammo_type, int, RESOURCE_CELLS);
/* impulse */ ATTRIB(Electro, impulse, int, 5);
/* flags */ ATTRIB(Electro, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH);
ENDCLASS(Electro)
REGISTER_WEAPON(ELECTRO, electro, NEW(Electro));
+SPAWNFUNC_WEAPON(weapon_electro, WEP_ELECTRO)
#ifdef SVQC
.float electro_count;
#include "fireball.qh"
#ifdef SVQC
-spawnfunc(weapon_fireball) { weapon_defaultspawnfunc(this, WEP_FIREBALL); }
void W_Fireball_Explode(entity this, entity directhitentity)
{
#pragma once
CLASS(Fireball, Weapon)
+/* spawnfunc */ ATTRIB(Fireball, m_canonical_spawnfunc, string, "weapon_fireball");
/* ammotype */ //ATTRIB(Fireball, ammo_type, int, RESOURCE_NONE);
/* impulse */ ATTRIB(Fireball, impulse, int, 9);
/* flags */ ATTRIB(Fireball, spawnflags, int, WEP_FLAG_SUPERWEAPON | WEP_TYPE_SPLASH | WEP_FLAG_NODUAL);
ENDCLASS(Fireball)
REGISTER_WEAPON(FIREBALL, fireball, NEW(Fireball));
+SPAWNFUNC_WEAPON(weapon_fireball, WEP_FIREBALL)
+
#ifdef SVQC
.float bot_primary_fireballmooth; // whatever a mooth is
.vector fireball_impactvec;
#include "hagar.qh"
#ifdef SVQC
-spawnfunc(weapon_hagar) { weapon_defaultspawnfunc(this, WEP_HAGAR); }
// NO bounce protection, as bounces are limited!
#pragma once
CLASS(Hagar, Weapon)
+/* spawnfunc */ ATTRIB(Hagar, m_canonical_spawnfunc, string, "weapon_hagar");
/* ammotype */ ATTRIB(Hagar, ammo_type, int, RESOURCE_ROCKETS);
/* impulse */ ATTRIB(Hagar, impulse, int, 8);
/* flags */ ATTRIB(Hagar, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH);
ENDCLASS(Hagar)
REGISTER_WEAPON(HAGAR, hagar, NEW(Hagar));
+
+SPAWNFUNC_WEAPON(weapon_hagar, WEP_HAGAR)
#include "hlac.qh"
#ifdef SVQC
-spawnfunc(weapon_hlac) { weapon_defaultspawnfunc(this, WEP_HLAC); }
void W_HLAC_Touch(entity this, entity toucher)
{
#pragma once
CLASS(HLAC, Weapon)
+/* spawnfunc */ ATTRIB(HLAC, m_canonical_spawnfunc, string, "weapon_hlac");
/* ammotype */ ATTRIB(HLAC, ammo_type, int, RESOURCE_CELLS);
/* impulse */ ATTRIB(HLAC, impulse, int, 6);
/* flags */ ATTRIB(HLAC, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH);
ENDCLASS(HLAC)
REGISTER_WEAPON(HLAC, hlac, NEW(HLAC));
+
+SPAWNFUNC_WEAPON(weapon_hlac, WEP_HLAC)
#ifdef SVQC
-spawnfunc(weapon_hook) { weapon_defaultspawnfunc(this, WEP_HOOK); }
-
void W_Hook_ExplodeThink(entity this)
{
float dt, dmg_remaining_next, f;
#pragma once
CLASS(Hook, Weapon)
+/* spawnfunc */ ATTRIB(Hook, m_canonical_spawnfunc, string, "weapon_hook");
/* ammotype */ ATTRIB(Hook, ammo_type, int, RESOURCE_FUEL);
/* impulse */ ATTRIB(Hook, impulse, int, 0);
/* flags */ ATTRIB(Hook, spawnflags, int, WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH);
ENDCLASS(Hook)
REGISTER_WEAPON(HOOK, hook, NEW(Hook));
+SPAWNFUNC_WEAPON(weapon_hook, WEP_HOOK)
+
CLASS(OffhandHook, OffhandWeapon)
#ifdef SVQC
METHOD(OffhandHook, offhand_think, void(OffhandHook this, entity actor, bool key_pressed))
#ifdef SVQC
-spawnfunc(weapon_machinegun)
+METHOD(MachineGun, m_spawnfunc_hookreplace, Weapon(MachineGun this, entity e))
{
- if(autocvar_sv_q3acompat_machineshotgunswap)
- if(this.classname != "droppedweapon")
+ if (autocvar_sv_q3acompat_machineshotgunswap && !Item_IsLoot(e))
{
- weapon_defaultspawnfunc(this, WEP_SHOCKWAVE);
- return;
+ return WEP_SHOCKWAVE;
}
- weapon_defaultspawnfunc(this, WEP_MACHINEGUN);
+ return this;
}
-spawnfunc(weapon_uzi) { spawnfunc_weapon_machinegun(this); }
void W_MachineGun_MuzzleFlash_Think(entity this)
{
#pragma once
CLASS(MachineGun, Weapon)
+/* spawnfunc */ ATTRIB(MachineGun, m_canonical_spawnfunc, string, "weapon_machinegun");
/* ammotype */ ATTRIB(MachineGun, ammo_type, int, RESOURCE_BULLETS);
/* impulse */ ATTRIB(MachineGun, impulse, int, 3);
/* flags */ ATTRIB(MachineGun, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_PENETRATEWALLS);
ENDCLASS(MachineGun)
REGISTER_WEAPON(MACHINEGUN, machinegun, NEW(MachineGun));
+
+SPAWNFUNC_WEAPON(weapon_machinegun, WEP_MACHINEGUN)
+SPAWNFUNC_WEAPON(weapon_uzi, WEP_MACHINEGUN)
#include "minelayer.qh"
#ifdef SVQC
-spawnfunc(weapon_minelayer) { weapon_defaultspawnfunc(this, WEP_MINE_LAYER); }
void W_MineLayer_Stick(entity this, entity to)
{
#pragma once
CLASS(MineLayer, Weapon)
+/* spawnfunc */ ATTRIB(MineLayer, m_canonical_spawnfunc, string, "weapon_minelayer");
/* ammotype */ ATTRIB(MineLayer, ammo_type, int, RESOURCE_ROCKETS);
/* impulse */ ATTRIB(MineLayer, impulse, int, 4);
/* flags */ ATTRIB(MineLayer, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH);
ENDCLASS(MineLayer)
REGISTER_WEAPON(MINE_LAYER, minelayer, NEW(MineLayer));
+SPAWNFUNC_WEAPON(weapon_minelayer, WEP_MINE_LAYER)
+
#ifdef SVQC
void W_MineLayer_Think(entity this);
.float minelayer_detonate, mine_explodeanyway;
#ifdef SVQC
-spawnfunc(weapon_mortar) { weapon_defaultspawnfunc(this, WEP_MORTAR); }
-spawnfunc(weapon_grenadelauncher) { spawnfunc_weapon_mortar(this); }
-
void W_Mortar_Grenade_Explode(entity this, entity directhitentity)
{
if(directhitentity.takedamage == DAMAGE_AIM)
#pragma once
CLASS(Mortar, Weapon)
+/* spawnfunc */ ATTRIB(Mortar, m_canonical_spawnfunc, string, "weapon_mortar");
/* ammotype */ ATTRIB(Mortar, ammo_type, int, RESOURCE_ROCKETS);
/* impulse */ ATTRIB(Mortar, impulse, int, 4);
/* flags */ ATTRIB(Mortar, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH);
ENDCLASS(Mortar)
REGISTER_WEAPON(MORTAR, mortar, NEW(Mortar));
+SPAWNFUNC_WEAPON(weapon_mortar, WEP_MORTAR)
+SPAWNFUNC_WEAPON(weapon_grenadelauncher, WEP_MORTAR)
#ifdef SVQC
.float gl_detonate_later;
#ifdef SVQC
#include <common/triggers/trigger/jumppads.qh>
-spawnfunc(weapon_porto) { weapon_defaultspawnfunc(this, WEP_PORTO); }
-
REGISTER_MUTATOR(porto_ticker, true);
MUTATOR_HOOKFUNCTION(porto_ticker, SV_StartFrame) {
FOREACH_CLIENT(IS_PLAYER(it), it.porto_forbidden = max(0, it.porto_forbidden - 1));
#pragma once
CLASS(PortoLaunch, Weapon)
+/* spawnfunc */ ATTRIB(PortoLaunch, m_canonical_spawnfunc, string, "weapon_porto");
/* ammotype */ ATTRIB(PortoLaunch, ammo_type, int, RESOURCE_NONE);
/* impulse */ ATTRIB(PortoLaunch, impulse, int, 0);
/* flags */ ATTRIB(PortoLaunch, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_SUPERWEAPON | WEP_FLAG_NODUAL);
ENDCLASS(PortoLaunch)
REGISTER_WEAPON(PORTO, porto, NEW(PortoLaunch));
+SPAWNFUNC_WEAPON(weapon_porto, WEP_PORTO)
+
#ifdef SVQC
.entity porto_current;
.vector porto_v_angle; // holds "held" view angles
#include "rifle.qh"
#ifdef SVQC
-spawnfunc(weapon_rifle) { weapon_defaultspawnfunc(this, WEP_RIFLE); }
-spawnfunc(weapon_campingrifle) { spawnfunc_weapon_rifle(this); }
-spawnfunc(weapon_sniperrifle) { spawnfunc_weapon_rifle(this); }
void W_Rifle_FireBullet(Weapon thiswep, .entity weaponentity, float pSpread, float pDamage, float pForce, float pSolidPenetration, float pAmmo, int deathtype, float pTracer, float pShots, Sound pSound, entity actor)
{
#pragma once
CLASS(Rifle, Weapon)
+/* spawnfunc */ ATTRIB(Rifle, m_canonical_spawnfunc, string, "weapon_rifle");
/* ammotype */ ATTRIB(Rifle, ammo_type, int, RESOURCE_BULLETS);
/* impulse */ ATTRIB(Rifle, impulse, int, 7);
/* flags */ ATTRIB(Rifle, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_PENETRATEWALLS);
ENDCLASS(Rifle)
REGISTER_WEAPON(RIFLE, rifle, NEW(Rifle));
+SPAWNFUNC_WEAPON(weapon_rifle, WEP_RIFLE)
+SPAWNFUNC_WEAPON(weapon_campingrifle, WEP_RIFLE)
+SPAWNFUNC_WEAPON(weapon_sniperrifle, WEP_RIFLE)
#ifdef SVQC
.float rifle_accumulator;
#include "seeker.qh"
#ifdef SVQC
-spawnfunc(weapon_seeker) { weapon_defaultspawnfunc(this, WEP_SEEKER); }
// ============================
// Begin: Missile functions, these are general functions to be manipulated by other code
#pragma once
CLASS(Seeker, Weapon)
+/* spawnfunc */ ATTRIB(Seeker, m_canonical_spawnfunc, string, "weapon_seeker");
/* ammotype */ ATTRIB(Seeker, ammo_type, int, RESOURCE_ROCKETS);
/* impulse */ ATTRIB(Seeker, impulse, int, 8);
/* flags */ ATTRIB(Seeker, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH);
ENDCLASS(Seeker)
REGISTER_WEAPON(SEEKER, seeker, NEW(Seeker));
+SPAWNFUNC_WEAPON(weapon_seeker, WEP_SEEKER)
+
#ifdef SVQC
.entity tag_target, wps_tag_tracker;
.float tag_time;
REGISTER_NET_TEMP(TE_CSQC_SHOCKWAVEPARTICLE)
#ifdef SVQC
-spawnfunc(weapon_shockwave)
+METHOD(Shockwave, m_spawnfunc_hookreplace, Weapon(Shockwave this, entity e))
{
//if(autocvar_sv_q3acompat_machineshockwaveswap) // WEAPONTODO
- if(autocvar_sv_q3acompat_machineshotgunswap)
- if(this.classname != "droppedweapon")
+ if (autocvar_sv_q3acompat_machineshotgunswap && !Item_IsLoot(e))
{
- weapon_defaultspawnfunc(this, WEP_MACHINEGUN);
- return;
+ return WEP_MACHINEGUN;
}
- weapon_defaultspawnfunc(this, WEP_SHOCKWAVE);
+ return this;
}
const float MAX_SHOCKWAVE_HITS = 10;
if(autocvar_g_antilag == 0 || noantilag)
lag = 0; // only do hitscan, but no antilag
if(lag)
- {
- FOREACH_CLIENT(IS_PLAYER(it) && it != actor, antilag_takeback(it, CS(it), time - lag));
- IL_EACH(g_monsters, it != actor,
- {
- antilag_takeback(it, it, time - lag);
- });
- }
+ antilag_takeback_all(actor, lag);
while(head)
{
}
if(lag)
- {
- FOREACH_CLIENT(IS_PLAYER(it) && it != actor, antilag_restore(it, CS(it)));
- IL_EACH(g_monsters, it != actor,
- {
- antilag_restore(it, it);
- });
- }
+ antilag_restore_all(actor);
}
METHOD(Shockwave, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
#pragma once
CLASS(Shockwave, Weapon)
+/* spawnfunc */ ATTRIB(Shockwave, m_canonical_spawnfunc, string, "weapon_shockwave");
/* ammotype */ //ATTRIB(Shockwave, ammo_type, int, RESOURCE_NONE);
/* impulse */ ATTRIB(Shockwave, impulse, int, 2);
/* flags */ ATTRIB(Shockwave, spawnflags, int, WEP_TYPE_HITSCAN | WEP_FLAG_CANCLIMB | WEP_TYPE_MELEE_SEC);
ENDCLASS(Shockwave)
REGISTER_WEAPON(SHOCKWAVE, shockwave, NEW(Shockwave));
+SPAWNFUNC_WEAPON(weapon_shockwave, WEP_SHOCKWAVE)
#ifdef CSQC
void Net_ReadShockwaveParticle();
#include "shotgun.qh"
#ifdef SVQC
-spawnfunc(weapon_shotgun) { weapon_defaultspawnfunc(this, WEP_SHOTGUN); }
void W_Shotgun_Attack(Weapon thiswep, entity actor, .entity weaponentity, float isprimary)
{
#pragma once
CLASS(Shotgun, Weapon)
+/* spawnfunc */ ATTRIB(Shotgun, m_canonical_spawnfunc, string, "weapon_shotgun");
/* ammotype */ ATTRIB(Shotgun, ammo_type, int, RESOURCE_SHELLS);
/* impulse */ ATTRIB(Shotgun, impulse, int, 2);
/* flags */ ATTRIB(Shotgun, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_TYPE_MELEE_SEC);
ENDCLASS(Shotgun)
REGISTER_WEAPON(SHOTGUN, shotgun, NEW(Shotgun));
+
+SPAWNFUNC_WEAPON(weapon_shotgun, WEP_SHOTGUN)
.float tuba_lastnotes_cnt; // over
.vector tuba_lastnotes[MAX_TUBANOTES];
-spawnfunc(weapon_tuba) { weapon_defaultspawnfunc(this, WEP_TUBA); }
-
bool W_Tuba_HasPlayed(entity pl, .entity weaponentity, string melody, int instrument, bool ignorepitch, float mintempo, float maxtempo)
{
float i, j, mmin, mmax, nolength;
#pragma once
CLASS(Tuba, Weapon)
+/* spawnfunc */ ATTRIB(Tuba, m_canonical_spawnfunc, string, "weapon_tuba");
/* impulse */ ATTRIB(Tuba, impulse, int, 1);
/* flags */ ATTRIB(Tuba, spawnflags, int, WEP_FLAG_HIDDEN | WEP_TYPE_SPLASH | WEP_FLAG_NODUAL);
/* rating */ ATTRIB(Tuba, bot_pickupbasevalue, float, 2000);
ENDCLASS(Tuba)
REGISTER_WEAPON(TUBA, tuba, NEW(Tuba));
+SPAWNFUNC_WEAPON(weapon_tuba, WEP_TUBA)
+
#ifdef CSQC
entityclass(Tuba);
class(Tuba) .int note;
#endif
#ifdef SVQC
-spawnfunc(weapon_vaporizer) { weapon_defaultspawnfunc(this, WEP_VAPORIZER); }
-spawnfunc(weapon_minstanex) { spawnfunc_weapon_vaporizer(this); }
void W_RocketMinsta_Explosion(entity actor, vector loc)
{
#pragma once
CLASS(Vaporizer, Weapon)
+/* spawnfunc */ ATTRIB(Vaporizer, m_canonical_spawnfunc, string, "weapon_vaporizer");
/* ammotype */ ATTRIB(Vaporizer, ammo_type, int, RESOURCE_CELLS);
/* impulse */ ATTRIB(Vaporizer, impulse, int, 7);
/* flags */ ATTRIB(Vaporizer, spawnflags, int, WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_FLAG_SUPERWEAPON | WEP_TYPE_HITSCAN | WEP_FLAG_NODUAL);
ENDCLASS(Vaporizer)
REGISTER_WEAPON(VAPORIZER, vaporizer, NEW(Vaporizer));
+SPAWNFUNC_WEAPON(weapon_vaporizer, WEP_VAPORIZER)
+SPAWNFUNC_WEAPON(weapon_minstanex, WEP_VAPORIZER)
#ifdef SVQC
.float vaporizer_lasthit;
#endif
#ifdef SVQC
-spawnfunc(weapon_vortex) { weapon_defaultspawnfunc(this, WEP_VORTEX); }
-spawnfunc(weapon_nex) { spawnfunc_weapon_vortex(this); }
REGISTER_MUTATOR(vortex_charge, true);
#pragma once
CLASS(Vortex, Weapon)
+/* spawnfunc */ ATTRIB(Vortex, m_canonical_spawnfunc, string, "weapon_vortex");
/* ammotype */ ATTRIB(Vortex, ammo_type, int, RESOURCE_CELLS);
/* impulse */ ATTRIB(Vortex, impulse, int, 7);
/* flags */ ATTRIB(Vortex, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_NODUAL);
ENDCLASS(Vortex)
REGISTER_WEAPON(VORTEX, vortex, NEW(Vortex));
+SPAWNFUNC_WEAPON(weapon_vortex, WEP_VORTEX)
+SPAWNFUNC_WEAPON(weapon_nex, WEP_VORTEX)
#ifdef SVQC
-
.float vortex_lasthit;
#endif
vector m1 = e.maxs;
e.mins = '0 0 0';
e.maxs = '0 0 0';
- WarpZoneLib_MoveOutOfSolid_Expand(e, eX * m0.x); e.mins.x = m0.x;
- WarpZoneLib_MoveOutOfSolid_Expand(e, eX * m1.x); e.maxs.x = m1.x;
- WarpZoneLib_MoveOutOfSolid_Expand(e, eY * m0.y); e.mins.y = m0.y;
- WarpZoneLib_MoveOutOfSolid_Expand(e, eY * m1.y); e.maxs.y = m1.y;
- WarpZoneLib_MoveOutOfSolid_Expand(e, eZ * m0.z); e.mins.z = m0.z;
- WarpZoneLib_MoveOutOfSolid_Expand(e, eZ * m1.z); e.maxs.z = m1.z;
+ WarpZoneLib_MoveOutOfSolid_Expand(e, eX * m0.x); e.mins_x = m0.x;
+ WarpZoneLib_MoveOutOfSolid_Expand(e, eX * m1.x); e.maxs_x = m1.x;
+ WarpZoneLib_MoveOutOfSolid_Expand(e, eY * m0.y); e.mins_y = m0.y;
+ WarpZoneLib_MoveOutOfSolid_Expand(e, eY * m1.y); e.maxs_y = m1.y;
+ WarpZoneLib_MoveOutOfSolid_Expand(e, eZ * m0.z); e.mins_z = m0.z;
+ WarpZoneLib_MoveOutOfSolid_Expand(e, eZ * m1.z); e.maxs_z = m1.z;
setorigin(e, e.origin);
tracebox(e.origin, e.mins, e.maxs, e.origin, MOVE_WORLDONLY, e);
break;
}
me.encryptLabel.setText(me.encryptLabel, me.currentServerEncrypt);
+ setZonedTooltip(me.encryptLabel, _("Use the `crypto_aeslevel` cvar to change your preferences"), string_null);
s = crypto_getidfp(me.currentServerCName);
if (!s) { s = _("N/A"); }
#include <server/impulse.qc>
#include <server/ipban.qc>
#include <server/item_key.qc>
+#include <server/items.qc>
#include <server/mapvoting.qc>
#include <server/matrix.qc>
#include <server/miscfunctions.qc>
#include <server/impulse.qh>
#include <server/ipban.qh>
#include <server/item_key.qh>
+#include <server/items.qh>
#include <server/mapvoting.qh>
#include <server/matrix.qh>
#include <server/miscfunctions.qh>
}
void anticheat_report_to_playerstats(entity this) {
- PS_GR_P_ADDVAL(this, strcat(PLAYERSTATS_ANTICHEAT, "_time"), servertime - CS(this).anticheat_jointime);
+ PlayerStats_GameReport_Event_Player(this,
+ strcat(PLAYERSTATS_ANTICHEAT, "_time"), servertime - CS(this).anticheat_jointime);
#define ANTICHEAT_REPORT_ONE(name, f, tmin, mi, ma) \
- PS_GR_P_ADDVAL(this, strcat(PLAYERSTATS_ANTICHEAT, name), f)
+ PlayerStats_GameReport_Event_Player(this, strcat(PLAYERSTATS_ANTICHEAT, name), f)
ANTICHEATS(ANTICHEAT_REPORT_ONE);
#undef ANTICHEAT_REPORT_ONE
}
}
store.antilag_index = ANTILAG_MAX_ORIGINS - 1; // next one is 0
}
+
+// TODO: use a single intrusive list across all antilagged entities
+void antilag_takeback_all(entity ignore, float lag)
+{
+ FOREACH_CLIENT(IS_PLAYER(it) && it != ignore, antilag_takeback(it, CS(it), time - lag));
+ IL_EACH(g_monsters, it != ignore,
+ {
+ antilag_takeback(it, it, time - lag);
+ });
+ IL_EACH(g_projectiles, it != ignore && it.classname == "nade",
+ {
+ antilag_takeback(it, it, time - lag);
+ });
+}
+
+void antilag_restore_all(entity ignore)
+{
+ FOREACH_CLIENT(IS_PLAYER(it) && it != ignore, antilag_restore(it, CS(it)));
+ IL_EACH(g_monsters, it != ignore,
+ {
+ antilag_restore(it, it);
+ });
+ IL_EACH(g_projectiles, it != ignore && it.classname == "nade",
+ {
+ antilag_restore(it, it);
+ });
+}
void antilag_restore(entity e, entity store);
void antilag_clear(entity e, entity store);
+void antilag_takeback_all(entity ignore, float lag);
+void antilag_restore_all(entity ignore);
+
.float antilag_debug;
#define ANTILAG_LATENCY(e) min(0.4, CS(e).ping * 0.001)
float autocvar_sv_jumpspeedcap_max_disable_on_ramps;
string autocvar_sv_jumpspeedcap_min;
float autocvar_sv_jumpvelocity;
+float autocvar_sv_jumpvelocity_crouch;
bool autocvar_sv_logscores_bots;
bool autocvar_sv_logscores_console;
bool autocvar_sv_logscores_file;
#include <server/defs.qh>
#include <server/miscfunctions.qh>
+#include <server/items.qh>
#include "havocbot.qh"
#include "../cvars.qh"
continue;
// Check if the item can be picked up safely
- if(it.classname == "droppedweapon")
+ if(Item_IsLoot(it))
{
if(!IS_ONGROUND(it))
continue;
if (this.alivetime)
{
if (!warmup_stage)
- PS_GR_P_ADDVAL(this, PLAYERSTATS_ALIVETIME, time - this.alivetime);
+ PlayerStats_GameReport_Event_Player(this, PLAYERSTATS_ALIVETIME, time - this.alivetime);
this.alivetime = 0;
}
PHYS_INPUT_BUTTON_ATCK(this) = PHYS_INPUT_BUTTON_JUMP(this) = PHYS_INPUT_BUTTON_ATCK2(this) = false;
+ // player was spectator
if (CS(this).killcount == FRAGS_SPECTATOR) {
PlayerScore_Clear(this);
CS(this).killcount = 0;
+ CS(this).startplaytime = time;
}
for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
.float clientkill_nexttime;
void ClientKill_Now_TeamChange(entity this)
{
- if(CS(this).killindicator_teamchange == -1)
+ if(this.killindicator_teamchange == -1)
{
JoinBestTeam( this, false, true );
}
- else if(CS(this).killindicator_teamchange == -2)
+ else if(this.killindicator_teamchange == -2)
{
if(blockSpectators)
Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
PutObserverInServer(this);
}
else
- SV_ChangeTeam(this, CS(this).killindicator_teamchange - 1);
- CS(this).killindicator_teamchange = 0;
+ SV_ChangeTeam(this, this.killindicator_teamchange - 1);
+ this.killindicator_teamchange = 0;
}
void ClientKill_Now(entity this)
if(this.vehicle)
{
vehicles_exit(this.vehicle, VHEF_RELEASE);
- if(!CS(this).killindicator_teamchange)
+ if(!this.killindicator_teamchange)
{
this.vehicle_health = -1;
Damage(this, this, this, 1 , DEATH_KILL.m_id, this.origin, '0 0 0');
this.killindicator = NULL;
- if(CS(this).killindicator_teamchange)
+ if(this.killindicator_teamchange)
ClientKill_Now_TeamChange(this);
if (!IS_SPEC(this) && !IS_OBSERVER(this) && MUTATOR_CALLHOOK(ClientKill_Now, this) == false)
return;
killtime = M_ARGV(1, float);
- CS(this).killindicator_teamchange = targetteam;
+ this.killindicator_teamchange = targetteam;
if(!this.killindicator)
{
ATTRIB(Client, parm_idlesince, int, this.parm_idlesince);
ATTRIB(Client, muted, bool, this.muted);
- ATTRIB(Client, killindicator_teamchange, int, this.killindicator_teamchange);
ATTRIB(Client, idlekick_lasttimeleft, float, this.idlekick_lasttimeleft);
ATTRIB(Client, pm_frametime, float, this.pm_frametime);
ATTRIB(Client, pressedkeys, int, this.pressedkeys);
ATTRIB(Client, motd_actived_time, float, this.motd_actived_time);
ATTRIB(Client, jointime, float, this.jointime);
ATTRIB(Client, spectatortime, float, this.spectatortime);
+ ATTRIB(Client, startplaytime, float, this.startplaytime);
ATTRIB(Client, version_nagtime, float, this.version_nagtime);
ATTRIB(Client, netname_previous, string, this.netname_previous);
ATTRIB(Client, allowed_timeouts, int, this.allowed_timeouts);
FOREACH_CLIENT(IS_PLAYER(it), {
it.alivetime = 0;
CS(it).killcount = 0;
- PS_GR_P_ADDVAL(it, PLAYERSTATS_ALIVETIME, -PS_GR_P_ADDVAL(it, PLAYERSTATS_ALIVETIME, 0));
+ float val = PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_ALIVETIME, 0);
+ PlayerStats_GameReport_Event_Player(it, PLAYERSTATS_ALIVETIME, -val);
});
restart_mapalreadyrestarted = false; // reset this var, needed when cvar sv_ready_restart_repeatable is in use
#include <server/miscfunctions.qh>
#include <common/weapons/_all.qh>
-spawnfunc(weapon_electro);
-spawnfunc(weapon_hagar);
-spawnfunc(weapon_machinegun);
-spawnfunc(item_bullets);
-spawnfunc(item_armor_mega);
-spawnfunc(item_health_mega);
-spawnfunc(item_health_medium);
-
//***********************
//QUAKE 1 ENTITIES - So people can play quake1 maps with the xonotic weapons
//***********************
-spawnfunc(weapon_nailgun) {spawnfunc_weapon_electro(this);}
-spawnfunc(weapon_supernailgun) {spawnfunc_weapon_hagar(this);}
-spawnfunc(weapon_supershotgun) {spawnfunc_weapon_machinegun(this);}
+SPAWNFUNC_WEAPON(weapon_nailgun, WEP_ELECTRO)
+SPAWNFUNC_WEAPON(weapon_supernailgun, WEP_HAGAR)
+SPAWNFUNC_WEAPON(weapon_supershotgun, WEP_MACHINEGUN)
-spawnfunc(item_spikes) {spawnfunc_item_bullets(this);}
+SPAWNFUNC_ITEM(item_spikes, ITEM_Bullets)
//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_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_health
-
-
-
+SPAWNFUNC_ITEM(item_armor2, ITEM_ArmorMega)
+SPAWNFUNC_ITEM(item_armorInv, ITEM_ArmorMega) // TODO: make sure we actually want this
+spawnfunc(item_health) {if (this.spawnflags & 2) StartItem(this, ITEM_HealthMega);else StartItem(this, ITEM_HealthMedium);}
#include "quake2.qh"
-spawnfunc(item_armor_medium);
-
-spawnfunc(item_invincible);
-
+#include <common/items/_mod.qh>
//***********************
//QUAKE 2 ENTITIES - So people can play quake2 maps with the xonotic weapons
//***********************
-spawnfunc(item_armor_jacket) {spawnfunc_item_armor_medium(this);}
+SPAWNFUNC_ITEM(item_armor_jacket, ITEM_ArmorMedium)
-spawnfunc(item_invulnerability) {spawnfunc_item_invincible(this);}
+SPAWNFUNC_ITEM(item_invulnerability, ITEM_Shield)
// rest of the quake 2 entities are handled by q1 and q3 compat
#include <server/defs.qh>
#include <server/miscfunctions.qh>
+#include <server/items.qh>
#include <common/weapons/_all.qh>
-spawnfunc(weapon_crylink);
-spawnfunc(weapon_electro);
-spawnfunc(weapon_hagar);
-spawnfunc(weapon_hook);
-spawnfunc(weapon_machinegun);
-spawnfunc(weapon_vortex);
-spawnfunc(weapon_minelayer);
-
spawnfunc(target_items);
-spawnfunc(item_bullets);
-spawnfunc(item_cells);
-spawnfunc(item_rockets);
-spawnfunc(item_shells);
-
-spawnfunc(item_strength);
-
-spawnfunc(item_armor_big);
-spawnfunc(item_armor_mega);
-spawnfunc(item_armor_small);
-
-spawnfunc(item_health_medium);
-spawnfunc(item_health_mega);
-
//***********************
//QUAKE 3 ENTITIES - So people can play quake3 maps with the xonotic weapons
//***********************
// NOTE: for best experience, you need to swap MGs with SGs in the map or it won't have a MG
// SG -> SG
-spawnfunc(ammo_shells) { spawnfunc_item_shells(this); }
+SPAWNFUNC_ITEM(ammo_shells, ITEM_Shells)
// MG -> MG
-spawnfunc(ammo_bullets) { spawnfunc_item_bullets(this); }
+SPAWNFUNC_ITEM(ammo_bullets, ITEM_Bullets)
// GL -> Mortar
-spawnfunc(ammo_grenades) { spawnfunc_item_rockets(this); }
+SPAWNFUNC_ITEM(ammo_grenades, ITEM_Rockets)
// Mines -> Rockets
-spawnfunc(weapon_prox_launcher) { spawnfunc_weapon_minelayer(this); }
-spawnfunc(ammo_mines) { spawnfunc_item_rockets(this); }
+SPAWNFUNC_WEAPON(weapon_prox_launcher, WEP_MINE_LAYER)
+SPAWNFUNC_ITEM(ammo_mines, ITEM_Rockets)
// LG -> Lightning
-spawnfunc(weapon_lightning) { spawnfunc_weapon_electro(this); }
-spawnfunc(ammo_lightning) { spawnfunc_item_cells(this); }
+SPAWNFUNC_WEAPON(weapon_lightning, WEP_ELECTRO)
+SPAWNFUNC_ITEM(ammo_lightning, ITEM_Cells)
// Plasma -> Hagar
-spawnfunc(weapon_plasmagun) { spawnfunc_weapon_hagar(this); }
-spawnfunc(ammo_cells) { spawnfunc_item_rockets(this); }
+SPAWNFUNC_WEAPON(weapon_plasmagun, WEP_HAGAR)
+SPAWNFUNC_ITEM(ammo_cells, ITEM_Rockets)
// Rail -> Vortex
-spawnfunc(weapon_railgun) { spawnfunc_weapon_vortex(this); }
-spawnfunc(ammo_slugs) { spawnfunc_item_cells(this); }
+SPAWNFUNC_WEAPON(weapon_railgun, WEP_VORTEX)
+SPAWNFUNC_ITEM(ammo_slugs, ITEM_Cells)
// BFG -> Crylink
-spawnfunc(weapon_bfg) { spawnfunc_weapon_crylink(this); }
-spawnfunc(ammo_bfg) { spawnfunc_item_cells(this); }
+SPAWNFUNC_WEAPON(weapon_bfg, WEP_CRYLINK)
+SPAWNFUNC_ITEM(ammo_bfg, ITEM_Cells)
// grappling hook -> hook
-spawnfunc(weapon_grapplinghook) { spawnfunc_weapon_hook(this); }
+SPAWNFUNC_WEAPON(weapon_grapplinghook, WEP_HOOK)
// RL -> RL
-spawnfunc(ammo_rockets) { spawnfunc_item_rockets(this); }
+SPAWNFUNC_ITEM(ammo_rockets, ITEM_Rockets)
// Armor
-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); }
+SPAWNFUNC_ITEM(item_armor_body, ITEM_ArmorMega)
+SPAWNFUNC_ITEM(item_armor_combat, ITEM_ArmorBig)
+SPAWNFUNC_ITEM(item_armor_shard, ITEM_ArmorSmall)
+SPAWNFUNC_ITEM(item_enviro, ITEM_Shield)
// medkit -> armor (we have no holdables)
-spawnfunc(holdable_medkit) { spawnfunc_item_armor_mega(this); }
+SPAWNFUNC_ITEM(holdable_medkit, ITEM_ArmorMega)
// doubler -> strength
-spawnfunc(item_doubler) { spawnfunc_item_strength(this); }
+SPAWNFUNC_ITEM(item_doubler, ITEM_Strength)
.float wait;
.float delay;
{
IL_EACH(g_items, it.targetname == this.target,
{
- if (it.classname == "weapon_rocketlauncher" || it.classname == "weapon_devastator") {
+ if (it.classname == "weapon_devastator") {
this.ammo_rockets += it.count * WEP_CVAR(devastator, ammo);
this.netname = cons(this.netname, "devastator");
}
- else if (it.classname == "weapon_lightning") {
+ else if (it.classname == "weapon_vortex") {
+ this.ammo_cells += it.count * WEP_CVAR_PRI(vortex, ammo); // WEAPONTODO
+ this.netname = cons(this.netname, "vortex");
+ }
+ else if (it.classname == "weapon_electro") {
this.ammo_cells += it.count * WEP_CVAR_PRI(electro, ammo); // WEAPONTODO
this.netname = cons(this.netname, "electro");
}
- else if (it.classname == "weapon_plasmagun") {
+ else if (it.classname == "weapon_hagar") {
this.ammo_rockets += it.count * WEP_CVAR_PRI(hagar, ammo); // WEAPONTODO
this.netname = cons(this.netname, "hagar");
}
- else if (it.classname == "weapon_bfg") {
+ else if (it.classname == "weapon_crylink") {
this.ammo_cells += it.count * WEP_CVAR_PRI(crylink, ammo);
this.netname = cons(this.netname, "crylink");
}
- else if (it.classname == "weapon_grenadelauncher" || it.classname == "weapon_mortar") {
+ else if (it.classname == "weapon_mortar") {
this.ammo_rockets += it.count * WEP_CVAR_PRI(mortar, ammo); // WEAPONTODO
this.netname = cons(this.netname, "mortar");
}
- else if (it.classname == "item_armor_body")
+ else if (it.classname == "item_armor_mega")
this.armorvalue = 100;
else if (it.classname == "item_health_mega")
this.health = 200;
#include <server/defs.qh>
#include <server/miscfunctions.qh>
+#include <server/items.qh>
#include <common/weapons/_all.qh>
-// #include <server/mutators/gamemode.qh>
-
-spawnfunc(weapon_arc);
-spawnfunc(weapon_crylink);
-spawnfunc(weapon_electro);
-spawnfunc(weapon_mortar);
-spawnfunc(weapon_hagar);
-spawnfunc(weapon_machinegun);
-spawnfunc(weapon_devastator);
-spawnfunc(weapon_shotgun);
-spawnfunc(weapon_vortex);
-
-spawnfunc(item_armor_big);
-spawnfunc(item_armor_mega);
-spawnfunc(item_armor_small);
-
-spawnfunc(item_bullets);
-spawnfunc(item_cells);
-spawnfunc(item_quad);
-spawnfunc(item_rockets);
-spawnfunc(item_shells);
-
-spawnfunc(item_jetpack);
spawnfunc(item_haste);
-spawnfunc(item_health_medium);
-spawnfunc(item_health_mega);
spawnfunc(item_invis);
//***********************
-//WORD OF PADMAN ENTITIES - So people can play wop maps with the xonotic weapons
+//WORLD OF PADMAN ENTITIES - So people can play wop maps with the xonotic weapons
//***********************
//spawnfunc(item_revival) /* handled by buffs mutator */
//spawnfunc(item_jumper) /* handled by buffs mutator */
-spawnfunc(weapon_punchy) { spawnfunc_weapon_arc(this); }
-spawnfunc(weapon_nipper) { spawnfunc_weapon_machinegun(this); }
-spawnfunc(weapon_pumper) { spawnfunc_weapon_shotgun(this); }
-spawnfunc(weapon_boaster) { spawnfunc_weapon_electro(this); }
-spawnfunc(weapon_splasher) { spawnfunc_weapon_vortex(this); }
-spawnfunc(weapon_bubbleg) { spawnfunc_weapon_hagar(this); }
-spawnfunc(weapon_balloony) { spawnfunc_weapon_mortar(this); }
-spawnfunc(weapon_betty) { spawnfunc_weapon_devastator(this); }
-spawnfunc(weapon_imperius) { spawnfunc_weapon_crylink(this); }
-
-spawnfunc(ammo_pumper) { spawnfunc_item_shells(this); }
-spawnfunc(ammo_nipper) { spawnfunc_item_bullets(this); }
-spawnfunc(ammo_balloony) { spawnfunc_item_rockets(this); }
-spawnfunc(ammo_bubbleg) { spawnfunc_item_rockets(this); }
-spawnfunc(ammo_boaster) { spawnfunc_item_cells(this); }
-spawnfunc(ammo_betty) { spawnfunc_item_rockets(this); }
-spawnfunc(ammo_imperius) { spawnfunc_item_cells(this); }
-
-spawnfunc(item_padpower) { spawnfunc_item_quad(this); }
-spawnfunc(item_climber) { spawnfunc_item_invincible(this); }
+SPAWNFUNC_WEAPON(weapon_punchy, WEP_ARC)
+SPAWNFUNC_WEAPON(weapon_nipper, WEP_MACHINEGUN)
+SPAWNFUNC_WEAPON(weapon_pumper, WEP_SHOTGUN)
+SPAWNFUNC_WEAPON(weapon_boaster, WEP_ELECTRO)
+SPAWNFUNC_WEAPON(weapon_splasher, WEP_VORTEX)
+SPAWNFUNC_WEAPON(weapon_bubbleg, WEP_HAGAR)
+SPAWNFUNC_WEAPON(weapon_balloony, WEP_MORTAR)
+SPAWNFUNC_WEAPON(weapon_betty, WEP_DEVASTATOR)
+SPAWNFUNC_WEAPON(weapon_imperius, WEP_CRYLINK)
+
+SPAWNFUNC_ITEM(ammo_pumper, ITEM_Shells)
+SPAWNFUNC_ITEM(ammo_nipper, ITEM_Bullets)
+SPAWNFUNC_ITEM(ammo_balloony, ITEM_Rockets)
+SPAWNFUNC_ITEM(ammo_bubbleg, ITEM_Rockets)
+SPAWNFUNC_ITEM(ammo_boaster, ITEM_Cells)
+SPAWNFUNC_ITEM(ammo_betty, ITEM_Rockets)
+SPAWNFUNC_ITEM(ammo_imperius, ITEM_Cells)
+
+SPAWNFUNC_ITEM(item_padpower, ITEM_Strength)
+SPAWNFUNC_ITEM(item_climber, ITEM_Shield)
spawnfunc(item_speedy) { spawnfunc_item_haste(this); }
spawnfunc(item_visionless) { spawnfunc_item_invis(this); }
-spawnfunc(item_armor_padshield) { spawnfunc_item_armor_mega(this); }
+SPAWNFUNC_ITEM(item_armor_padshield, ITEM_ArmorMega)
-spawnfunc(holdable_floater) { spawnfunc_item_jetpack(this); }
+SPAWNFUNC_ITEM(holdable_floater, ITEM_Jetpack)
#pragma once
-float warmup_limit;
#include <common/weapons/_all.qh>
#include <common/stats.qh>
float game_completion_ratio; // 0 at start, 1 near end
.float winning;
-.float jointime; // time of joining
+.float jointime; // time of connecting
+.float startplaytime; // time of switching from spectator to player
.float alivetime; // time of being alive
.float motd_actived_time; // used for both motd and campaign_message
.float stat_respawn_time = _STAT(RESPAWN_TIME); // shows respawn time, and is negative when awaiting respawn
+.int killindicator_teamchange;
+
void PlayerUseKey(entity this);
USING(spawn_evalfunc_t, vector(entity this, entity player, entity spot, vector current));
else
{
// teamkill
- GameRules_scoring_add(attacker, KILLS, -1); // or maybe add a teamkills field?
+ GameRules_scoring_add(attacker, TEAMKILLS, 1);
}
}
else
{
// regular frag
GameRules_scoring_add(attacker, KILLS, 1);
- if(targ.playerid)
- PS_GR_P_ADDVAL(attacker, sprintf("kills-%d", targ.playerid), 1);
+ if(!warmup_stage && targ.playerid)
+ PlayerStats_GameReport_Event_Player(attacker, sprintf("kills-%d", targ.playerid), 1);
}
GameRules_scoring_add(targ, DEATHS, 1);
string s1, string s2, string s3,
float f1, float f2, float f3)
{
- if(DEATH_ISSPECIAL(deathtype))
+ if(!DEATH_ISSPECIAL(deathtype))
{
- entity deathent = Deathtypes_from(deathtype - DT_FIRST);
- if (!deathent) { backtrace("Obituary_SpecialDeath: Could not find deathtype entity!\n"); return; }
+ backtrace("Obituary_SpecialDeath called without a special deathtype?\n");
+ return;
+ }
- if(g_cts && deathtype == DEATH_KILL.m_id)
- return; // TODO: somehow put this in CTS gamemode file!
+ entity deathent = Deathtypes_from(deathtype - DT_FIRST);
+ if (!deathent)
+ {
+ backtrace("Obituary_SpecialDeath: Could not find deathtype entity!\n");
+ return;
+ }
- if(murder)
- {
- if(deathent.death_msgmurder)
- {
- Send_Notification_WOCOVA(
- NOTIF_ONE,
- notif_target,
- MSG_MULTI,
- deathent.death_msgmurder,
- s1, s2, s3, "",
- f1, f2, f3, 0
- );
- Send_Notification_WOCOVA(
- NOTIF_ALL_EXCEPT,
- notif_target,
- MSG_INFO,
- deathent.death_msgmurder.nent_msginfo,
- s1, s2, s3, "",
- f1, f2, f3, 0
- );
- }
- }
- else
- {
- if(deathent.death_msgself)
- {
- Send_Notification_WOCOVA(
- NOTIF_ONE,
- notif_target,
- MSG_MULTI,
- deathent.death_msgself,
- s1, s2, s3, "",
- f1, f2, f3, 0
- );
- Send_Notification_WOCOVA(
- NOTIF_ALL_EXCEPT,
- notif_target,
- MSG_INFO,
- deathent.death_msgself.nent_msginfo,
- s1, s2, s3, "",
- f1, f2, f3, 0
- );
- }
- }
+ if(g_cts && deathtype == DEATH_KILL.m_id)
+ return; // TODO: somehow put this in CTS gamemode file!
+
+ Notification death_message = (murder) ? deathent.death_msgmurder : deathent.death_msgself;
+ if(death_message)
+ {
+ Send_Notification_WOCOVA(
+ NOTIF_ONE,
+ notif_target,
+ MSG_MULTI,
+ death_message,
+ s1, s2, s3, "",
+ f1, f2, f3, 0
+ );
+ Send_Notification_WOCOVA(
+ NOTIF_ALL_EXCEPT,
+ notif_target,
+ MSG_INFO,
+ death_message.nent_msginfo,
+ s1, s2, s3, "",
+ f1, f2, f3, 0
+ );
}
- else { backtrace("Obituary_SpecialDeath called without a special deathtype?\n"); return; }
}
float Obituary_WeaponDeath(
float f1, float f2)
{
Weapon death_weapon = DEATH_WEAPONOF(deathtype);
- if (death_weapon != WEP_Null)
- {
- w_deathtype = deathtype;
- Notification death_message = ((murder) ? death_weapon.wr_killmessage(death_weapon) : death_weapon.wr_suicidemessage(death_weapon));
- w_deathtype = false;
+ if (death_weapon == WEP_Null)
+ return false;
- if (death_message)
- {
- Send_Notification_WOCOVA(
- NOTIF_ONE,
- notif_target,
- MSG_MULTI,
- death_message,
- s1, s2, s3, "",
- f1, f2, 0, 0
- );
- // send the info part to everyone
- Send_Notification_WOCOVA(
- NOTIF_ALL_EXCEPT,
- notif_target,
- MSG_INFO,
- death_message.nent_msginfo,
- s1, s2, s3, "",
- f1, f2, 0, 0
- );
- }
- else
- {
- LOG_TRACEF(
- "Obituary_WeaponDeath(): ^1Deathtype ^7(%d)^1 has no notification for weapon %d!\n",
- deathtype,
- death_weapon
- );
- }
+ w_deathtype = deathtype;
+ Notification death_message = ((murder) ? death_weapon.wr_killmessage(death_weapon) : death_weapon.wr_suicidemessage(death_weapon));
+ w_deathtype = false;
- return true;
+ if (death_message)
+ {
+ Send_Notification_WOCOVA(
+ NOTIF_ONE,
+ notif_target,
+ MSG_MULTI,
+ death_message,
+ s1, s2, s3, "",
+ f1, f2, 0, 0
+ );
+ // send the info part to everyone
+ Send_Notification_WOCOVA(
+ NOTIF_ALL_EXCEPT,
+ notif_target,
+ MSG_INFO,
+ death_message.nent_msginfo,
+ s1, s2, s3, "",
+ f1, f2, 0, 0
+ );
}
- return false;
+ else
+ {
+ LOG_TRACEF(
+ "Obituary_WeaponDeath(): ^1Deathtype ^7(%d)^1 has no notification for weapon %d!\n",
+ deathtype,
+ death_weapon
+ );
+ }
+
+ return true;
}
bool frag_centermessage_override(entity attacker, entity targ, int deathtype, int kill_count_to_attacker, int kill_count_to_target)
attacker.killsound += 1;
+ // TODO: improve SPREE_ITEM and KILL_SPREE_LIST
+ // these 2 macros are spread over multiple files
#define SPREE_ITEM(counta,countb,center,normal,gentle) \
case counta: \
{ \
Send_Notification(NOTIF_ONE, attacker, MSG_ANNCE, ANNCE_KILLSTREAK_##countb); \
- PS_GR_P_ADDVAL(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##counta, 1); \
+ if (!warmup_stage)\
+ {\
+ PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##counta, 1); \
+ }\
break; \
}
switch(CS(attacker).killcount)
}
#undef SPREE_ITEM
- if(!checkrules_firstblood)
+ if(!warmup_stage && !checkrules_firstblood)
{
checkrules_firstblood = true;
notif_firstblood = true; // modify the current messages so that they too show firstblood information
- PS_GR_P_ADDVAL(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1);
- PS_GR_P_ADDVAL(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1);
+ PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1);
+ PlayerStats_GameReport_Event_Player(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1);
// tell spree_inf and spree_cen that this is a first-blood and first-victim event
kill_count_to_attacker = -1;
if(GameRules_scoring_add(targ, SCORE, 0) == -5)
{
Send_Notification(NOTIF_ONE, targ, MSG_ANNCE, ANNCE_ACHIEVEMENT_BOTLIKE);
- PS_GR_P_ADDVAL(attacker, PLAYERSTATS_ACHIEVEMENT_BOTLIKE, 1);
+ if (!warmup_stage)
+ {
+ PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_BOTLIKE, 1);
+ }
}
}
source.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
if (lag)
- {
- // take players back into the past
- FOREACH_CLIENT(IS_PLAYER(it) && it != forent, antilag_takeback(it, CS(it), time - lag));
- IL_EACH(g_monsters, it != forent,
- {
- antilag_takeback(it, it, time - lag);
- });
- }
+ antilag_takeback_all(forent, lag);
// do the trace
if(wz)
// restore players to current positions
if (lag)
- {
- FOREACH_CLIENT(IS_PLAYER(it) && it != forent, antilag_restore(it, CS(it)));
- IL_EACH(g_monsters, it != forent,
- {
- antilag_restore(it, it);
- });
- }
+ antilag_restore_all(forent);
// restore shooter solid type
if(source)
{
antilag_record(it, it, altime);
});
+ IL_EACH(g_projectiles, it.classname == "nade",
+ {
+ antilag_record(it, it, altime);
+ });
systems_update();
IL_ENDFRAME();
}
--- /dev/null
+#include "items.qh"
+
+/// \file
+/// \brief Source file that contains implementation of the functions related to
+/// game items.
+/// \copyright GNU GPLv2 or any later version.
+
+#include "g_subs.qh"
+#include <common/weapons/all.qh>
+
+.bool m_isloot; ///< Holds whether item is loot.
+/// \brief Holds whether strength, shield or superweapon timers expire while
+/// this item is on the ground.
+.bool m_isexpiring;
+
+entity Item_Create(string class_name, vector position, bool no_align)
+{
+ entity item = spawn();
+ item.classname = class_name;
+ item.spawnfunc_checked = true;
+ setorigin(item, position);
+ item.noalign = no_align;
+ Item_Initialize(item, class_name);
+ if (wasfreed(item))
+ {
+ return NULL;
+ }
+ return item;
+}
+
+void Item_Initialize(entity item, string class_name)
+{
+ FOREACH(Weapons, it.m_canonical_spawnfunc == class_name,
+ {
+ weapon_defaultspawnfunc(item, it);
+ return;
+ });
+ FOREACH(Items, it.m_canonical_spawnfunc == class_name,
+ {
+ StartItem(item, it);
+ return;
+ });
+ LOG_FATALF("Item_Initialize: Invalid classname: %s", class_name);
+}
+
+entity Item_CreateLoot(string class_name, vector position, vector vel,
+ float time_to_live)
+{
+ entity item = spawn();
+ if (!Item_InitializeLoot(item, class_name, position, vel, time_to_live))
+ {
+ return NULL;
+ }
+ return item;
+}
+
+bool Item_InitializeLoot(entity item, string class_name, vector position,
+ vector vel, float time_to_live)
+{
+ item.classname = class_name;
+ Item_SetLoot(item, true);
+ item.noalign = true;
+ setorigin(item, position);
+ item.pickup_anyway = true;
+ item.spawnfunc_checked = true;
+ Item_Initialize(item, class_name);
+ if (wasfreed(item))
+ {
+ return false;
+ }
+ item.gravity = 1;
+ item.velocity = vel;
+ SUB_SetFade(item, time + time_to_live, 1);
+ return true;
+}
+
+bool Item_IsLoot(entity item)
+{
+ return item.m_isloot;
+}
+
+void Item_SetLoot(entity item, bool loot)
+{
+ item.m_isloot = loot;
+}
+
+bool Item_IsExpiring(entity item)
+{
+ return item.m_isexpiring;
+}
+
+void Item_SetExpiring(entity item, bool expiring)
+{
+ item.m_isexpiring = expiring;
+}
+
+// Compatibility spawn functions
+
+// FIXME: in Quake this is green armor, in Xonotic maps it is an armor shard
+SPAWNFUNC_ITEM(item_armor1, ITEM_ArmorSmall)
+
+SPAWNFUNC_ITEM(item_armor25, ITEM_ArmorMega)
+
+SPAWNFUNC_ITEM(item_armor_large, ITEM_ArmorMega)
+
+SPAWNFUNC_ITEM(item_health1, ITEM_HealthSmall)
+
+SPAWNFUNC_ITEM(item_health25, ITEM_HealthMedium)
+
+SPAWNFUNC_ITEM(item_health_large, ITEM_HealthBig)
+
+SPAWNFUNC_ITEM(item_health100, ITEM_HealthMega)
+
+SPAWNFUNC_ITEM(item_quad, ITEM_Strength)
--- /dev/null
+#pragma once
+
+/// \file
+/// \brief Header file that describes the functions related to game items.
+/// \copyright GNU GPLv2 or any later version.
+
+/// \brief Creates a new item.
+/// \param[in] class_name Class name of the item.
+/// \param[in] position Position of the item.
+/// \param[in] no_align True if item should be placed directly at specified
+/// position, false to let it drop to the ground.
+/// \return Item on success, NULL otherwise.
+entity Item_Create(string class_name, vector position, bool no_align);
+
+/// \brief Initializes the item according to classname.
+/// \param[in,out] item Item to initialize.
+/// \param[in] class_name Class name to use.
+/// \return No return.
+/// \nore This function is useful if you want to set some item properties before
+/// initialization.
+void Item_Initialize(entity item, string class_name);
+
+/// \brief Creates a loot item.
+/// \param[in] class_name Class name of the item.
+/// \param[in] position Position of the item.
+/// \param[in] velocity of the item.
+/// \param[in] time_to_live Amount of time after which the item will disappear.
+/// \return Item on success, NULL otherwise.
+entity Item_CreateLoot(string class_name, vector position, vector vel,
+ float time_to_live);
+
+/// \brief Initializes the loot item.
+/// \param[in] class_name Class name of the item.
+/// \param[in] position Position of the item.
+/// \param[in] velocity of the item.
+/// \param[in] time_to_live Amount of time after which the item will disappear.
+/// \return True on success, false otherwise.
+/// \nore This function is useful if you want to set some item properties before
+/// initialization.
+bool Item_InitializeLoot(entity item, string class_name, vector position,
+ vector vel, float time_to_live);
+
+/// \brief Returns whether the item is loot.
+/// \param[in] item Item to check.
+/// \return True if the item is loot, false otherwise.
+bool Item_IsLoot(entity item);
+
+/// \brief Sets the item loot status.
+/// \param[in,out] item Item to adjust.
+/// \param[in] loot Whether item is loot.
+/// \return No return.
+void Item_SetLoot(entity item, bool loot);
+
+/// \brief Returns whether the item is expiring (i.e. its strength, shield and
+/// superweapon timers expire while it is on the ground).
+/// \param[in] item Item to check.
+/// \return True if the item is expiring, false otherwise.
+bool Item_IsExpiring(entity item);
+
+/// \brief Sets the item expiring status (i.e. whether its strength, shield
+/// and superweapon timers expire while it is on the ground).
+/// \param[in,out] item Item to adjust.
+/// \param[in] expiring Whether item is expiring.
+/// \return No return.
+void Item_SetExpiring(entity item, bool expiring);
#include "mutators/_mod.qh"
#include "../common/t_items.qh"
#include "resources.qh"
+#include "items.qh"
#include "weapons/accuracy.qh"
#include "weapons/csqcprojectile.qh"
#include "weapons/selection.qh"
"g_random_start_shells"));
SetResourceAmount(random_start_ammo, RESOURCE_BULLETS, cvar(
"g_random_start_bullets"));
- SetResourceAmount(random_start_ammo, RESOURCE_ROCKETS,
+ SetResourceAmount(random_start_ammo, RESOURCE_ROCKETS,
cvar("g_random_start_rockets"));
SetResourceAmount(random_start_ammo, RESOURCE_CELLS, cvar(
"g_random_start_cells"));
return false;
if(e.iscreature)
return true;
+ if (Item_IsLoot(e))
+ {
+ return true;
+ }
switch(e.classname)
{
case "body":
- case "droppedweapon":
return true;
case "bullet": // antilagged bullets can't hit this either
return false;
MUT_ITEMTOUCH_PICKUP // return this flag to have the item "picked up" and taken even after mutator handled it
};
+/** called after the item has been touched. */
+#define EV_ItemTouched(i, o) \
+ /** item */ i(entity, MUTATOR_ARGV_0_entity) \
+ /** toucher */ i(entity, MUTATOR_ARGV_1_entity) \
+ /**/
+MUTATOR_HOOKABLE(ItemTouched, EV_ItemTouched);
+
/** Called when the amount of entity resources changes. Can be used to override
resource limit. */
#define EV_GetResourceLimit(i, o) \
ca_LastPlayerForTeam_Notify(frag_target);
if (!allowed_to_spawn)
- frag_target.respawn_flags = RESPAWN_SILENT;
+ {
+ frag_target.respawn_flags = RESPAWN_SILENT;
+ // prevent unwanted sudden rejoin as spectator and move of spectator camera
+ frag_target.respawn_time = time + 2;
+ }
if (!warmup_stage)
eliminatedPlayers.SendFlags |= 1;
if(IS_BOT_CLIENT(frag_target))
if (!IS_DEAD(player))
ca_LastPlayerForTeam_Notify(player);
- if (CS(player).killindicator_teamchange == -2) // player wants to spectate
+ if (player.killindicator_teamchange == -2) // player wants to spectate
player.caplayer = 0;
if (player.caplayer)
player.frags = FRAGS_LMS_LOSER;
#include "gamemode_cts.qh"
-#include <server/race.qh>
#include <server/race.qh>
+#include <server/items.qh>
float autocvar_g_cts_finish_kill_delay;
bool autocvar_g_cts_selfdamage;
{
entity item = M_ARGV(0, entity);
- if(item.classname == "droppedweapon")
+ if (Item_IsLoot(item))
+ {
return true;
+ }
}
MUTATOR_HOOKFUNCTION(cts, Damage_Calculate)
#include "gamemode_lms.qh"
-#include <common/mutators/mutator/instagib/items.qc>
+#include <common/mutators/mutator/instagib/items.qh>
#include <server/campaign.qh>
#include <server/command/_mod.qh>
if(this.alivetime)
{
- PS_GR_P_ADDVAL(this, PLAYERSTATS_ALIVETIME, time - this.alivetime);
+ PlayerStats_GameReport_Event_Player(this, PLAYERSTATS_ALIVETIME, time - this.alivetime);
this.alivetime = 0;
}
{
delete(this.killindicator);
this.killindicator = NULL;
- if(CS(this).killindicator_teamchange)
+ if(this.killindicator_teamchange)
defer_ClientKill_Now_TeamChange = true;
if(this.classname == "body")
if(w != WEP_Null && accuracy_isgooddamage(attacker, this))
CS(attacker).accuracy.(accuracy_frags[w.m_id-1]) += 1;
+ this.respawn_time = 0;
MUTATOR_CALLHOOK(PlayerDies, inflictor, attacker, this, deathtype, damage);
damage = M_ARGV(4, float);
excess = max(0, damage - take - save);
if(this.health >= 1 || !(IS_PLAYER(this) || this.classname == "body"))
return;
+ if (!this.respawn_time) // can be set in the mutator hook PlayerDies
+ calculate_player_respawn_time(this);
+
// when we get here, player actually dies
Unfreeze(this); // remove any icy remains
STAT(MOVEVARS_SPECIALCOMMAND, this) = false; // sweet release
- // when to allow respawn
- calculate_player_respawn_time(this);
-
this.death_time = time;
if (random() < 0.5)
animdecide_setstate(this, this.anim_state | ANIMSTATE_DEAD1, true);
PlayerStats_GameReport_AddTeam(t);
}
-float TeamScore_AddToTeam(float t, float scorefield, float score)
+float TeamScore_AddToTeam(int t, float scorefield, float score)
{
entity s;
if(scores_label(scorefield) != "")
s.SendFlags |= (2 ** (scorefield.m_id % 16));
if(!warmup_stage)
- PS_GR_P_ADDVAL(s.owner, strcat(PLAYERSTATS_TOTAL, scores_label(scorefield)), score);
+ PlayerStats_GameReport_Event_Player(s.owner, strcat(PLAYERSTATS_TOTAL, scores_label(scorefield)), score);
s.(scores(scorefield)) += score;
MUTATOR_CALLHOOK(AddedPlayerScore, scorefield, score, player);
return s.(scores(scorefield));
{
entity s = CS(p).scorekeeper;
FOREACH(Scores, true, {
- if(s.(scores(it)) != 0)
- if(scores_label(it) != "")
- PS_GR_P_ADDVAL(s.owner, strcat(PLAYERSTATS_SCOREBOARD, scores_label(it)), s.(scores(it)));
- });
+ if(s.(scores(it)) != 0 && scores_label(it) != "")
+ PlayerStats_GameReport_Event_Player(s.owner,
+ strcat(PLAYERSTATS_SCOREBOARD, scores_label(it)), s.(scores(it)));
+ });
}
void PlayerScore_TeamStats()
if(!sk)
continue;
for(i = 0; i < MAX_TEAMSCORE; ++i)
- if(sk.(teamscores(i)) != 0)
- if(teamscores_label(i) != "")
- // the +1 is important here!
- PS_GR_T_ADDVAL(t+1, strcat(PLAYERSTATS_SCOREBOARD, teamscores_label(i)), sk.(teamscores(i)));
+ if(sk.(teamscores(i)) != 0 && teamscores_label(i) != "")
+ // the +1 is important here!
+ PlayerStats_GameReport_Event_Team(t+1,
+ strcat(PLAYERSTATS_SCOREBOARD, teamscores_label(i)), sk.(teamscores(i)));
}
}
* NEVER call this if team has not been set yet!
* Returns the new score.
*/
-float TeamScore_AddToTeam(float t, float scorefield, float score);
+float TeamScore_AddToTeam(int t, float scorefield, float score);
/**
* Returns a value indicating the team score (and higher is better).
ScoreInfo_SetLabel_PlayerScore(SP_DEATHS, "deaths", SFL_LOWER_IS_BETTER);
if (!INDEPENDENT_PLAYERS)
+ {
ScoreInfo_SetLabel_PlayerScore(SP_SUICIDES, "suicides", SFL_LOWER_IS_BETTER);
+ ScoreInfo_SetLabel_PlayerScore(SP_TEAMKILLS, "teamkills", SFL_LOWER_IS_BETTER);
+ }
if(score_enabled)
ScoreInfo_SetLabel_PlayerScore(SP_SCORE, "score", sprio);
source_team = Team_TeamToNumber(source_color + 1);
destination_team = Team_TeamToNumber(destination_color + 1);
+ if (destination_team == -1)
+ {
+ return;
+ }
+
CheckAllowedTeams(this);
if (destination_team == 1 && c1 < 0) destination_team = 4;
#include "weaponsystem.qh"
#include <common/t_items.qh>
+#include <server/items.qh>
#include <common/constants.qh>
#include <common/net_linked.qh>
#include <common/util.qh>
if (!autocvar_g_showweaponspawns) return;
IL_EACH(g_items, it.weapon == this.m_id && (!it.team || (it.ItemStatus & ITS_AVAILABLE)),
{
- if (it.classname == "droppedweapon" && autocvar_g_showweaponspawns < 2)
+ if (Item_IsLoot(it) && (autocvar_g_showweaponspawns < 2))
+ {
continue;
+ }
entity wp = WaypointSprite_Spawn(
WP_Weapon,
-2, 0,
#include "../resources.qh"
#include "../mutators/_mod.qh"
#include <common/t_items.qh>
+#include <server/items.qh>
#include <common/weapons/_all.qh>
+.bool m_isreplaced; ///< Holds whether the weapon has been replaced.
+
string W_Apply_Weaponreplace(string in)
{
string out = "";
void weapon_defaultspawnfunc(entity this, Weapon e)
{
Weapon wpn = e;
- if (this.classname != "droppedweapon" && this.classname != "replacedweapon")
+ e = wpn = wpn.m_spawnfunc_hookreplace(wpn, this);
+ this.classname = wpn.m_canonical_spawnfunc;
+ if (!Item_IsLoot(this) && !this.m_isreplaced)
{
if (e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
{
{
entity replacement = spawn();
copyentity(this, replacement);
- replacement.classname = "replacedweapon";
+ replacement.m_isreplaced = true;
weapon_defaultspawnfunc(replacement, it);
break;
}
#include "weaponsystem.qh"
#include "../resources.qh"
+#include "../items.qh"
#include "../mutators/_mod.qh"
#include <common/t_items.qh>
#include "../g_damage.qh"
Weapon info = Weapons_from(wpn);
int ammotype = info.ammo_type;
- entity wep = new(droppedweapon);
-
+ entity wep = spawn();
+ Item_SetLoot(wep, true);
setorigin(wep, org);
wep.velocity = velo;
wep.owner = wep.enemy = own;
if(WepSet_FromWeapon(Weapons_from(wpn)) & WEPSET_SUPERWEAPONS)
{
+ Item_SetExpiring(wep, true);
if(own.items & IT_UNLIMITED_SUPERWEAPONS)
{
wep.superweapons_finished = time + autocvar_g_balance_superweapons_time;
if(autocvar_g_antilag == 0 || noantilag)
lag = 0; // only do hitscan, but no antilag
if(lag)
- {
- FOREACH_CLIENT(IS_PLAYER(it) && it != this, antilag_takeback(it, CS(it), time - lag));
- IL_EACH(g_monsters, it != this,
- {
- antilag_takeback(it, it, time - lag);
- });
- }
+ antilag_takeback_all(this, lag);
// change shooter to SOLID_BBOX so the shot can hit corpses
int oldsolid = this.dphitcontentsmask;
}
if(lag)
- {
- FOREACH_CLIENT(IS_PLAYER(it) && it != this, antilag_restore(it, CS(it)));
- IL_EACH(g_monsters, it != this,
- {
- antilag_restore(it, it);
- });
- }
+ antilag_restore_all(this);
// restore shooter solid type
if(this)
#include <server/miscfunctions.qh>
float internalteam;
-float weaponswapping;
entity weapon_dropevent_item;
..entity weaponentity_fld;
--- /dev/null
+// Random items mutator config
+
+// Map items
+
+set g_random_items_replace_item_health_small "random" "Classnames to replace small health with."
+set g_random_items_replace_item_health_medium "random" "Classnames to replace medium health with."
+set g_random_items_replace_item_health_big "random" "Classnames to replace big health with."
+set g_random_items_replace_item_health_mega "random" "Classnames to replace mega health with."
+set g_random_items_replace_item_armor_small "random" "Classnames to replace small armor with."
+set g_random_items_replace_item_armor_medium "random" "Classnames to replace medium armor with."
+set g_random_items_replace_item_armor_big "random" "Classnames to replace big armor with."
+set g_random_items_replace_item_armor_mega "random" "Classnames to replace mega armor with."
+set g_random_items_replace_item_shells "random" "Classnames to replace shells with."
+set g_random_items_replace_item_bullets "random" "Classnames to replace bullets with."
+set g_random_items_replace_item_rockets "random" "Classnames to replace rockets with."
+set g_random_items_replace_item_cells "random" "Classnames to replace cells with."
+set g_random_items_replace_item_plasma "random" "Classnames to replace plasma with."
+set g_random_items_replace_item_fuel "random" "Classnames to replace fuel with."
+set g_random_items_replace_weapon_blaster "random" "Classnames to replace blaster with."
+set g_random_items_replace_weapon_shotgun "random" "Classnames to replace shotgun with."
+set g_random_items_replace_weapon_machinegun "random" "Classnames to replace machinegun with."
+set g_random_items_replace_weapon_mortar "random" "Classnames to replace mortar with."
+set g_random_items_replace_weapon_electro "random" "Classnames to replace electro with."
+set g_random_items_replace_weapon_crylink "random" "Classnames to replace crylink with."
+set g_random_items_replace_weapon_vortex "random" "Classnames to replace vortex with."
+set g_random_items_replace_weapon_hagar "random" "Classnames to replace hagar with."
+set g_random_items_replace_weapon_devastator "random" "Classnames to replace devastator with."
+set g_random_items_replace_weapon_shockwave "random" "Classnames to replace shockwave with."
+set g_random_items_replace_weapon_arc "random" "Classnames to replace arc with."
+set g_random_items_replace_weapon_hook "random" "Classnames to replace hook with."
+set g_random_items_replace_weapon_tuba "random" "Classnames to replace tuba with."
+set g_random_items_replace_weapon_porto "random" "Classnames to replace port-o-launch with."
+set g_random_items_replace_weapon_fireball "random" "Classnames to replace fireball with."
+set g_random_items_replace_weapon_minelayer "random" "Classnames to replace mine layer with."
+set g_random_items_replace_weapon_hlac "random" "Classnames to replace HLAC with."
+set g_random_items_replace_weapon_rifle "random" "Classnames to replace rifle with."
+set g_random_items_replace_weapon_seeker "random" "Classnames to replace TAG seeker with."
+set g_random_items_replace_weapon_vaporizer "random" "Classnames to replace vaporizer with."
+set g_random_items_replace_weapon_hmg "random" "Classnames to replace HMG with."
+set g_random_items_replace_weapon_rpc "random" "Classnames to replace RPC with."
+set g_random_items_replace_item_strength "random" "Classnames to replace strength with."
+set g_random_items_replace_item_shield "random" "Classnames to replace shield with."
+set g_random_items_replace_item_fuel_regen "random" "Classnames to replace fuel regeneration with."
+set g_random_items_replace_item_jetpack "random" "Classnames to replace jetpack with."
+set g_random_items_replace_item_vaporizer_cells "random" "Classnames to replace vaporizer cells with."
+set g_random_items_replace_item_invisibility "random" "Classnames to replace invisibility with."
+set g_random_items_replace_item_extralife "random" "Classnames to replace extra life with."
+set g_random_items_replace_item_speed "random" "Classnames to replace speed with."
+set g_random_items_health_probability 1 "Probability of random health items spawning in the map."
+set g_random_items_armor_probability 1 "Probability of random armor items spawning in the map."
+set g_random_items_resource_probability 1 "Probability of random resource items spawning in the map."
+set g_random_items_weapon_probability 1 "Probability of random weapons spawning in the map."
+set g_random_items_powerup_probability 0.15 "Probability of random powerups spawning in the map."
+set g_random_items_item_health_small_probability 10 "Probability of random small health spawning in the map."
+set g_random_items_item_health_medium_probability 4 "Probability of random medium health spawning in the map."
+set g_random_items_item_health_big_probability 2 "Probability of random big health spawning in the map."
+set g_random_items_item_health_mega_probability 1 "Probability of random mega health spawning in the map."
+set g_random_items_item_armor_small_probability 10 "Probability of random small armor spawning in the map."
+set g_random_items_item_armor_medium_probability 4 "Probability of random medium armor spawning in the map."
+set g_random_items_item_armor_big_probability 2 "Probability of random big armor spawning in the map."
+set g_random_items_item_armor_mega_probability 1 "Probability of random mega armor spawning in the map."
+set g_random_items_item_shells_probability 1 "Probability of random shells spawning in the map."
+set g_random_items_item_bullets_probability 1 "Probability of random bullets spawning in the map."
+set g_random_items_item_rockets_probability 1 "Probability of random rockets spawning in the map."
+set g_random_items_item_cells_probability 1 "Probability of random cells spawning in the map."
+set g_random_items_item_plasma_probability 0 "Probability of random plasma spawning in the map."
+set g_random_items_item_fuel_probability 0 "Probability of random fuel spawning in the map."
+set g_random_items_weapon_blaster_probability 0 "Probability of random blaster spawning in the map."
+set g_random_items_weapon_shotgun_probability 0 "Probability of random shotgun spawning in the map."
+set g_random_items_weapon_machinegun_probability 1 "Probability of random machinegun spawning in the map."
+set g_random_items_weapon_mortar_probability 1 "Probability of random mortar spawning in the map."
+set g_random_items_weapon_electro_probability 1 "Probability of random electro spawning in the map."
+set g_random_items_weapon_crylink_probability 1 "Probability of random crylink spawning in the map."
+set g_random_items_weapon_vortex_probability 1 "Probability of random vortex spawning in the map."
+set g_random_items_weapon_hagar_probability 1 "Probability of random hagar spawning in the map."
+set g_random_items_weapon_devastator_probability 1 "Probability of random devastator spawning in the map."
+set g_random_items_weapon_shockwave_probability 0 "Probability of random shockwave spawning in the map."
+set g_random_items_weapon_arc_probability 0 "Probability of random arc spawning in the map."
+set g_random_items_weapon_hook_probability 0 "Probability of random hook spawning in the map."
+set g_random_items_weapon_tuba_probability 0 "Probability of random tuba spawning in the map."
+set g_random_items_weapon_porto_probability 0 "Probability of random port-o-launch spawning in the map."
+set g_random_items_weapon_fireball_probability 0 "Probability of random fireball spawning in the map."
+set g_random_items_weapon_minelayer_probability 0 "Probability of random mine layer spawning in the map."
+set g_random_items_weapon_hlac_probability 0 "Probability of random HLAC spawning in the map."
+set g_random_items_weapon_rifle_probability 0 "Probability of random rifle spawning in the map."
+set g_random_items_weapon_seeker_probability 0 "Probability of random TAG seeker spawning in the map."
+set g_random_items_weapon_vaporizer_probability 0 "Probability of random vaporizer spawning in the map."
+set g_random_items_item_strength_probability 1 "Probability of random strength spawning in the map."
+set g_random_items_item_shield_probability 1 "Probability of random shield spawning in the map."
+set g_random_items_item_fuel_regen_probability 0 "Probability of random fuel regeneration spawning in the map."
+set g_random_items_item_jetpack_probability 0 "Probability of random jetpack spawning in the map."
+set g_random_items_item_vaporizer_cells_probability 20 "Probability of random vaporizer cells spawning in the map."
+set g_random_items_item_invisibility_probability 1 "Probability of random invisibility spawning in the map."
+set g_random_items_item_extralife_probability 1 "Probability of random extra life spawning in the map."
+set g_random_items_item_speed_probability 1 "Probability of random speed spawning in the map."
+set g_random_items_overkill_item_health_mega_probability 1 "Probability of random mega health spawning in the map during overkill."
+set g_random_items_overkill_item_armor_small_probability 10 "Probability of random small armor spawning in the map during overkill."
+set g_random_items_overkill_item_armor_medium_probability 4 "Probability of random medium armor spawning in the map during overkill."
+set g_random_items_overkill_item_armor_big_probability 2 "Probability of random big armor spawning in the map during overkill."
+set g_random_items_overkill_item_armor_mega_probability 1 "Probability of random mega armor spawning in the map during overkill."
+set g_random_items_overkill_weapon_hmg_probability 0.5 "Probability of random HMG spawning in the map during overkill."
+set g_random_items_overkill_weapon_rpc_probability 0.5 "Probability of random RPC spawning in the map during overkill."
+
+// Loot
+
+set g_random_loot_min 0 "Minimum amount of loot items."
+set g_random_loot_max 4 "Maximum amount of loot items."
+set g_random_loot_time 10 "Amount of time the loot will stay in seconds."
+set g_random_loot_spread 200 "How far can loot be thrown."
+set g_random_loot_health_probability 1 "Probability of random health items spawning as loot."
+set g_random_loot_armor_probability 1 "Probability of random armor items spawning as loot."
+set g_random_loot_resource_probability 1 "Probability of random ammo items spawning as loot."
+set g_random_loot_weapon_probability 1 "Probability of random weapons spawning as loot."
+set g_random_loot_powerup_probability 0.2 "Probability of random powerups spawning as loot."
+set g_random_loot_item_health_small_probability 4 "Probability of random small health spawning as loot."
+set g_random_loot_item_health_medium_probability 3 "Probability of random medium health spawning as loot."
+set g_random_loot_item_health_big_probability 2 "Probability of random big health spawning as loot."
+set g_random_loot_item_health_mega_probability 1 "Probability of random mega health spawning as loot."
+set g_random_loot_item_armor_small_probability 4 "Probability of random small armor spawning as loot."
+set g_random_loot_item_armor_medium_probability 3 "Probability of random medium armor spawning as loot."
+set g_random_loot_item_armor_big_probability 2 "Probability of random big armor spawning as loot."
+set g_random_loot_item_armor_mega_probability 1 "Probability of random mega armor spawning as loot."
+set g_random_loot_item_shells_probability 1 "Probability of random shells spawning as loot."
+set g_random_loot_item_bullets_probability 1 "Probability of random bullets spawning as loot."
+set g_random_loot_item_rockets_probability 1 "Probability of random rockets spawning as loot."
+set g_random_loot_item_cells_probability 1 "Probability of random cells spawning as loot."
+set g_random_loot_item_plasma_probability 0 "Probability of random plasma spawning as loot."
+set g_random_loot_item_fuel_probability 0 "Probability of random fuel spawning as loot."
+set g_random_loot_weapon_blaster_probability 0 "Probability of random blaster spawning as loot."
+set g_random_loot_weapon_shotgun_probability 0 "Probability of random shotgun spawning as loot."
+set g_random_loot_weapon_machinegun_probability 1 "Probability of random machinegun spawning as loot."
+set g_random_loot_weapon_mortar_probability 1 "Probability of random mortar spawning as loot."
+set g_random_loot_weapon_electro_probability 1 "Probability of random electro spawning as loot."
+set g_random_loot_weapon_crylink_probability 1 "Probability of random crylink spawning as loot."
+set g_random_loot_weapon_vortex_probability 1 "Probability of random vortex spawning as loot."
+set g_random_loot_weapon_hagar_probability 1 "Probability of random hagar spawning as loot."
+set g_random_loot_weapon_devastator_probability 1 "Probability of random devastator spawning as loot."
+set g_random_loot_weapon_shockwave_probability 0 "Probability of random shockwave spawning as loot."
+set g_random_loot_weapon_arc_probability 0 "Probability of random arc spawning as loot."
+set g_random_loot_weapon_hook_probability 0 "Probability of random hook spawning as loot."
+set g_random_loot_weapon_tuba_probability 0 "Probability of random tuba spawning as loot."
+set g_random_loot_weapon_porto_probability 0 "Probability of random port-o-launch spawning as loot."
+set g_random_loot_weapon_fireball_probability 0 "Probability of random fireball spawning as loot."
+set g_random_loot_weapon_minelayer_probability 0 "Probability of random mine layer spawning as loot."
+set g_random_loot_weapon_hlac_probability 0 "Probability of random HLAC spawning as loot."
+set g_random_loot_weapon_rifle_probability 0 "Probability of random rifle spawning as loot."
+set g_random_loot_weapon_seeker_probability 0 "Probability of random TAG seeker spawning as loot."
+set g_random_loot_weapon_vaporizer_probability 0 "Probability of random vaporizer spawning as loot."
+set g_random_loot_item_strength_probability 1 "Probability of random strength spawning as loot."
+set g_random_loot_item_shield_probability 1 "Probability of random shield spawning as loot."
+set g_random_loot_item_fuel_regen_probability 0 "Probability of random fuel regeneration spawning as loot."
+set g_random_loot_item_jetpack_probability 0 "Probability of random jetpack spawning as loot."
+set g_random_loot_item_vaporizer_cells_probability 20 "Probability of random vaporizer cells spawning as loot."
+set g_random_loot_item_invisibility_probability 1 "Probability of random invisibility spawning as loot."
+set g_random_loot_item_extralife_probability 1 "Probability of random extra life spawning as loot."
+set g_random_loot_item_speed_probability 1 "Probability of random speed spawning as loot."
+set g_random_loot_overkill_item_health_mega_probability 1 "Probability of random mega health spawning as loot during overkill."
+set g_random_loot_overkill_item_armor_small_probability 10 "Probability of random small armor spawning as loot during overkill."
+set g_random_loot_overkill_item_armor_medium_probability 4 "Probability of random medium armor spawning as loot during overkill."
+set g_random_loot_overkill_item_armor_big_probability 2 "Probability of random big armor spawning as loot during overkill."
+set g_random_loot_overkill_item_armor_mega_probability 1 "Probability of random mega armor spawning as loot during overkill."
+set g_random_loot_overkill_weapon_hmg_probability 1 "Probability of random HMG spawning as loot during overkill."
+set g_random_loot_overkill_weapon_rpc_probability 1 "Probability of random RPC spawning as loot during overkill."