]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into Lyberta/TeamplayFixes_
authorLyberta <lyberta@lyberta.net>
Fri, 17 Mar 2017 20:11:53 +0000 (23:11 +0300)
committerLyberta <lyberta@lyberta.net>
Fri, 17 Mar 2017 20:11:53 +0000 (23:11 +0300)
36 files changed:
bal-wep-overkill.cfg
balance-overkill.cfg
defaultOverkill.cfg
defaultXonotic.cfg
mutators.cfg
physicsOverkill.cfg
physicsXDF.cfg
qcsrc/client/view.qc
qcsrc/client/wall.qc
qcsrc/common/ent_cs.qc
qcsrc/common/mutators/mutator/buffs/sv_buffs.qc
qcsrc/common/mutators/mutator/dodging/sv_dodging.qc
qcsrc/common/mutators/mutator/overkill/sv_overkill.qc
qcsrc/common/sounds/all.inc
qcsrc/common/stats.qh
qcsrc/common/t_items.qc
qcsrc/common/t_items.qh
qcsrc/common/triggers/subs.qc
qcsrc/ecs/systems/sv_physics.qc
qcsrc/menu/xonotic/dialog_settings_effects.qc
qcsrc/menu/xonotic/slider_particles.qc
qcsrc/menu/xonotic/util.qc
qcsrc/server/autocvars.qh
qcsrc/server/bot/api.qh
qcsrc/server/bot/default/havocbot/havocbot.qc
qcsrc/server/bot/default/navigation.qc
qcsrc/server/bot/default/waypoints.qc
qcsrc/server/client.qc
qcsrc/server/defs.qh
qcsrc/server/g_damage.qc
qcsrc/server/g_models.qc
qcsrc/server/g_world.qc
qcsrc/server/impulse.qc
qcsrc/server/mutators/events.qh
qcsrc/server/race.qc
sound/misc/kill.ogg [new file with mode: 0644]

index 8c6432264c1fcdc8cf57488d3dc5a44fe786ab67..f423417f83b854c752b8640871580c9142886b78 100644 (file)
@@ -81,7 +81,7 @@ set g_balance_machinegun_first_spread 0.03
 set g_balance_machinegun_mode 1
 set g_balance_machinegun_reload_ammo 30
 set g_balance_machinegun_reload_time 1.5
-set g_balance_machinegun_solidpenetration 13.1
+set g_balance_machinegun_solidpenetration 63
 set g_balance_machinegun_spread_add 0.012
 set g_balance_machinegun_spread_max 0.05
 set g_balance_machinegun_spread_min 0
index da17e0afeb099d8cdd3664890f6cca351d208e43..381eb51d7ba3d19948ad83cd5d3acfbb838fd828 100644 (file)
@@ -64,7 +64,7 @@ set g_pickup_fuel_weapon 50
 set g_pickup_fuel_jetpack 100
 set g_pickup_fuel_max 100
 set g_pickup_armorsmall 5
-set g_pickup_armorsmall_max 20
+set g_pickup_armorsmall_max 100
 set g_pickup_armorsmall_anyway 1
 set g_pickup_armormedium 25
 set g_pickup_armormedium_max 100
index 29fb2bf12782f02de96f0911d6865e9e4c1f3d1e..ae5df4a1ab98818c9dd0d2e127fe002cfc211c5a 100644 (file)
@@ -1,6 +1,6 @@
-// ================
-//  Overkill Mode
-// ================
+// ==============
+//  Overkill Mod
+// ==============
 
 exec defaultXonotic.cfg
 exec balance-overkill.cfg
@@ -8,8 +8,20 @@ exec physicsOverkill.cfg
 
 // general gameplay
 set g_overkill 1
+set g_respawn_ghosts 0
+
 set g_nades 1
+set g_nades_nade_small 1
+set g_nades_spread 0
+set g_nades_nade_refire 10
+set g_nades_nade_newton_style 2
+
 set g_dodging 1
 set sv_dodging_wall_dodging 1
+
 set g_spawn_near_teammate 1
 set g_spawn_near_teammate_ignore_spawnpoint 1
+set g_spawnshieldtime 0.5
+set g_respawn_delay_forced 2
+
+set g_lms_start_armor 100
index 0c916558e4f12db13729a3b75233c4f30b2b122c..5b3105c8c1d58c9c0cc70251c64f9cad9601d2d2 100644 (file)
@@ -402,6 +402,8 @@ set bot_ai_aimskill_order_filter_5th 0.5 "Movement prediction filter. Used rarel
 // waypoint editor enable
 set g_waypointeditor 0
 set g_waypointeditor_auto 0 "Automatically create waypoints for bots while playing; BEWARE, this currently creates too many of them"
+set g_waypointeditor_symmetrical 0 "Enable symmetrical editing of waypoints, useful in symmetrical CTF maps. NOTE: it assumes that the map is perfectly symmetrical"
+set g_waypointeditor_symmetrical_center "0 0" "Center (x y) for symmetrical editing of waypoints"
 set bot_ignore_bots 0  "When set, bots don't shoot at other bots"
 set bot_join_empty 0   "When set, bots also play if no player has joined the server"
 set bot_vs_human 0     "Bots and humans play in different teams when set. positive values to make an all-bot blue team, set to negative values to make an all-bot red team, the absolute value is the ratio bots vs humans (1 for equal count). Changes will be correctly applied only from the next game"
index f61930852d0f9d75f6b66c241deb801a41032e9b..d078494899004d591cb01ffad0c5c68acb14fa4d 100644 (file)
@@ -51,6 +51,7 @@ set g_instagib_friendlypush 1 "allow pushing teammates with the vaporizer primar
 set g_overkill 0 "enable overkill"
 
 set g_overkill_powerups_replace 1
+set g_overkill_itemwaypoints 1
 set g_overkill_filter_healthmega 0
 set g_overkill_filter_armormedium 0
 set g_overkill_filter_armorbig 0
@@ -190,7 +191,7 @@ set g_nades_nade_damage 225
 set g_nades_nade_edgedamage 90
 set g_nades_nade_radius 300
 set g_nades_nade_force 650
-set g_nades_nade_newton_style 0
+set g_nades_nade_newton_style 0 "0 is absolute, 1 is relative (takes into account player speed), 2 is something in between"
 set g_nades_nade_type 1 "Type of the off-hand grenade. 1:normal 2:napalm 3:ice 4:translocate 5:spawn 6:heal 7:pokenade 8:entrap"
 
 seta cl_nade_timer 1 "show a visual timer for nades, 1 = only circle, 2 = circle with text"
index ec74d8588a2f484beb84375d31822efcc13d09aa..c40b755bf81868d2548fb1de4c9c321f3c698411 100644 (file)
@@ -38,7 +38,7 @@ sv_aircontrol 125
 sv_aircontrol_penalty 180
 sv_aircontrol_power 2
 sv_aircontrol_backwards 0
-sv_airspeedlimit_nonqw 800
+sv_airspeedlimit_nonqw 900
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index 5a3aaa393bd117eaf455bfe99342e4979adc1b98..db55fd8491448367d7aa51a064394fb9bc836f69 100644 (file)
@@ -36,7 +36,7 @@ sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
 sv_warsowbunny_backtosideratio 0.8
 sv_friction_on_land 0
-sv_friction_slick 0.5
+sv_friction_slick 0
 sv_doublejump 1
 sv_jumpspeedcap_min 0
 sv_jumpspeedcap_max 0.5
index 104405b3973616eb2ce156a97fe06a90ac34e536..65df30fd89ff5ec10f4eb3804cac9e7d3776c384 100644 (file)
@@ -875,6 +875,14 @@ void HitSound()
                sound(NULL, CH_INFO, SND_TYPEHIT, VOL_BASE, ATTN_NONE);
                typehit_time_prev = typehit_time;
        }
+
+       static float kill_time_prev = 0;
+       float kill_time = STAT(KILL_TIME);
+       if (COMPARE_INCREASING(kill_time, kill_time_prev) > autocvar_cl_hitsound_antispam_time)
+       {
+               sound(NULL, CH_INFO, SND_KILL, VOL_BASE, ATTN_NONE);
+               kill_time_prev = kill_time;
+       }
 }
 
 vector crosshair_getcolor(entity this, float health_stat)
index 64916ad8c17d05251f940ed0ae9e02e340ffb8bf..7a31265db9d6a549f5c72ef86c8dff2dde75da78 100644 (file)
@@ -136,6 +136,7 @@ NET_HANDLE(ENT_CLIENT_WALL, bool isnew)
                        this.colormap = ReadShort();
                else
                        this.colormap = 0;
+               this.skin = ReadByte();
        }
 
        if(f & 2)
index f308530d50d7d475e020257e67503bc5606dc858..12abc21b18a255a29821912a00f8968ac1588ff9 100644 (file)
@@ -1,5 +1,38 @@
 #include "ent_cs.qh"
 
+REGISTRY(EntCSProps, BITS(16) - 1)
+#define EntCSProps_from(i) _EntCSProps_from(i, NULL)
+REGISTER_REGISTRY(EntCSProps)
+REGISTRY_SORT(EntCSProps)
+REGISTRY_CHECK(EntCSProps)
+STATIC_INIT(RegisterEntCSProps_renumber) { FOREACH(EntCSProps, true, it.m_id = i); }
+
+.bool m_public;
+.bool(entity ent, entity player) m_check;
+.void(entity ent, entity player) m_set;
+.void(int chan, entity ent) m_send;
+.void(entity ent) m_receive;
+
+#ifdef SVQC
+#define ENTCS_PROP(id, ispublic, checkprop, setprop, svsend, clreceive) \
+       bool id##_check(entity ent, entity player) { return (ent.(checkprop) != player.(checkprop)); } \
+       void id##_set(entity ent, entity player) { setprop(ent.(checkprop), player.(checkprop)); } \
+       void id##_send(int chan, entity ent) { LAMBDA(svsend); } \
+       REGISTER(EntCSProps, ENTCS_PROP, id, m_id, new_pure(entcs_prop)) { \
+               this.m_public = ispublic; \
+               this.m_check = id##_check; \
+               this.m_set = id##_set; \
+               this.m_send = id##_send; \
+       }
+#elif defined(CSQC)
+#define ENTCS_PROP(id, ispublic, checkprop, setprop, svsend, clreceive) \
+       void id##_receive(entity ent) { LAMBDA(clreceive); } \
+       REGISTER(EntCSProps, ENTCS_PROP, id, m_id, new_pure(entcs_prop)) { \
+               this.m_public = ispublic; \
+               this.m_receive = id##_receive; \
+       }
+#endif
+
 #define ENTCS_SET_NORMAL(var, x) MACRO_BEGIN \
        var = x; \
 MACRO_END
@@ -10,62 +43,53 @@ MACRO_END
        var = strzone(x); \
 MACRO_END
 
-// #define PROP(public, fld, set, sv, cl)
-#define ENTCS_NETPROPS(ent, PROP) PROP(false, sv_entnum, ENTCS_SET_NORMAL, {}, {}) /* sentinel */ \
-       PROP(false, origin, ENTCS_SET_NORMAL, \
-       { WriteCoord(chan, ent.origin.x);  WriteCoord(chan, ent.origin.y); \
-         WriteCoord(chan, ent.origin.z); }, \
-       { ent.has_sv_origin = true; vector v; v.x = ReadCoord(); v.y = ReadCoord(); v.z = ReadCoord(); setorigin(ent, v); }) \
-    \
-       PROP(false, angles_y, ENTCS_SET_NORMAL, \
-       { WriteByte(chan, ent.angles.y / 360 * 256); }, \
-       { vector v = '0 0 0'; v.y = ReadByte() / 256 * 360; ent.angles = v; }) \
-    \
-       PROP(false, health, ENTCS_SET_NORMAL, \
-       { WriteByte(chan, bound(0, ent.health / 10, 255));  /* FIXME: use a better scale? */ }, \
-       { ent.healthvalue = ReadByte() * 10; }) \
-    \
-       PROP(false, armorvalue, ENTCS_SET_NORMAL, \
-       { WriteByte(chan, bound(0, ent.armorvalue / 10, 255));  /* FIXME: use a better scale? */ }, \
-       { ent.armorvalue = ReadByte() * 10; }) \
-    \
-       PROP(true, netname, ENTCS_SET_MUTABLE_STRING, \
-       { WriteString(chan, ent.netname); }, \
-       { if (ent.netname) strunzone(ent.netname); ent.netname = strzone(ReadString()); }) \
-    \
-       PROP(true, model, ENTCS_SET_NORMAL, \
-       { WriteString(chan, ent.model); }, \
-       { if (ent.model) strunzone(ent.model); ent.model = strzone(ReadString()); }) \
-    \
-       PROP(true, skin, ENTCS_SET_NORMAL, \
-       { WriteByte(chan, ent.skin); }, \
-       { ent.skin = ReadByte(); }) \
-    \
-    PROP(true, clientcolors, ENTCS_SET_NORMAL, \
-       { WriteByte(chan, ent.clientcolors); }, \
-       { ent.colormap = ReadByte(); }) \
-    \
-    PROP(true, frags, ENTCS_SET_NORMAL, \
-       { WriteShort(chan, ent.frags); }, \
-       { ent.frags = ReadShort(); }) \
-    \
-       /**/
+ENTCS_PROP(ENTNUM, false, sv_entnum, ENTCS_SET_NORMAL, {}, {}) /* sentinel */
+
+ENTCS_PROP(ORIGIN, false, origin, ENTCS_SET_NORMAL,
+       { WriteVector(chan, ent.origin); },
+       { ent.has_sv_origin = true; vector v = ReadVector(); setorigin(ent, v); })
+
+ENTCS_PROP(ANGLES, false, angles_y, ENTCS_SET_NORMAL,
+       { WriteByte(chan, ent.angles.y / 360 * 256); },
+       { vector v = '0 0 0'; v.y = ReadByte() / 256 * 360; ent.angles = v; })
+
+ENTCS_PROP(HEALTH, false, health, ENTCS_SET_NORMAL,
+       { WriteByte(chan, bound(0, ent.health / 10, 255));  /* FIXME: use a better scale? */ },
+       { ent.healthvalue = ReadByte() * 10; })
+
+ENTCS_PROP(ARMOR, false, armorvalue, ENTCS_SET_NORMAL,
+       { WriteByte(chan, bound(0, ent.armorvalue / 10, 255));  /* FIXME: use a better scale? */ },
+       { ent.armorvalue = ReadByte() * 10; })
+
+ENTCS_PROP(NAME, true, netname, ENTCS_SET_MUTABLE_STRING,
+       { WriteString(chan, ent.netname); },
+       { if (ent.netname) strunzone(ent.netname); ent.netname = strzone(ReadString()); })
+
+ENTCS_PROP(MODEL, true, model, ENTCS_SET_NORMAL,
+       { WriteString(chan, ent.model); },
+       { if (ent.model) strunzone(ent.model); ent.model = strzone(ReadString()); })
+
+ENTCS_PROP(SKIN, true, skin, ENTCS_SET_NORMAL,
+       { WriteByte(chan, ent.skin); },
+       { ent.skin = ReadByte(); })
+
+ENTCS_PROP(CLIENTCOLORS, true, clientcolors, ENTCS_SET_NORMAL,
+       { WriteByte(chan, ent.clientcolors); },
+       { ent.colormap = ReadByte(); })
+
+ENTCS_PROP(FRAGS, true, frags, ENTCS_SET_NORMAL,
+       { WriteShort(chan, ent.frags); },
+       { ent.frags = ReadShort(); })
 
 #ifdef SVQC
 
        int ENTCS_PUBLICMASK = 0;
        STATIC_INIT(ENTCS_PUBLICMASK)
        {
-               int i = 0;
-               #define X(public, fld, set, sv, cl) { \
-                       if (public) { \
-                               ENTCS_PUBLICMASK |= BIT(i); \
-                       } \
-                       i += 1; \
-               }
-               ENTCS_NETPROPS(this, X);
-               #undef X
-               if (i >= BITS(16 - 1)) LOG_FATAL("Exceeded ENTCS_NETPROPS limit");
+               FOREACH(EntCSProps, it.m_public,
+               {
+                       ENTCS_PUBLICMASK |= BIT(it.m_id);
+               });
        }
 
        bool _entcs_send(entity this, entity to, int sf, int chan)
@@ -90,15 +114,10 @@ MACRO_END
                        WriteHeader(chan, CLIENT_ENTCS);
                WriteByte(chan, etof(player) - 1);
                WriteShort(chan, sf);
-               int i = 0;
-               #define X(public, fld, set, sv, cl) { \
-                       if (sf & BIT(i)) { \
-                               sv; \
-                       } \
-                       i += 1; \
-               }
-               ENTCS_NETPROPS(this, X);
-               #undef X
+               FOREACH(EntCSProps, sf & BIT(it.m_id),
+               {
+                       it.m_send(chan, this);
+               });
                return true;
        }
 
@@ -111,16 +130,11 @@ MACRO_END
        {
                this.nextthink = time + 0.033333333333;  // TODO: increase this to like 0.15 once the client can do smoothing
                entity o = this.owner;
-               int i = 0;
-               #define X(public, fld, set, sv, cl) { \
-                       if (o.fld != this.fld) { \
-                               set(this.fld, o.fld); \
-                               this.SendFlags |= BIT(i); \
-                       } \
-                       i += 1; \
-               }
-               ENTCS_NETPROPS(this, X);
-               #undef X
+               FOREACH(EntCSProps, it.m_check(this, o),
+               {
+                       it.m_set(this, o);
+                       this.SendFlags |= BIT(it.m_id);
+               });
            setorigin(this, this.origin);  // relink
        }
 
@@ -208,15 +222,10 @@ MACRO_END
                int sf = ReadShort();
                e.has_sv_origin = false;
                e.m_entcs_private = boolean(sf & BIT(0));
-               int i = 0;
-               #define X(public, fld, set, sv, cl) { \
-                       if (sf & BIT(i)) { \
-                               cl; \
-                       } \
-                       i += 1; \
-               }
-               ENTCS_NETPROPS(e, X);
-               #undef X
+               FOREACH(EntCSProps, sf & BIT(it.m_id),
+               {
+                       it.m_receive(e);
+               });
                e.iflags |= IFLAG_ORIGIN;
                InterpolateOrigin_Note(e);
                getthink(e)(e);
index 7048e541f4d3397a104afba7b3ea0342d669883b..70217365d40e0156259dff72b2f5ec3e11dc2b09 100644 (file)
@@ -220,7 +220,7 @@ void buff_NewType(entity ent)
        FOREACH(Buffs, buff_Available(it),
        {
                // if it's already been chosen, give it a lower priority
-               RandomSelection_AddEnt(it, 1, max(0.2, 1 / it.buff_seencount));
+               RandomSelection_AddEnt(it, max(0.2, 1 / it.buff_seencount), 1);
        });
        entity newbuff = RandomSelection_chosen_ent;
        newbuff.buff_seencount += 1; // lower chances of seeing this buff again soon
@@ -566,39 +566,25 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerSpawn)
        player.buff_disability_effect_time = 0;
 }
 
-.float stat_sv_maxspeed;
-.float stat_sv_airspeedlimit_nonqw;
-.float stat_sv_jumpvelocity;
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerPhysics)
+MUTATOR_HOOKFUNCTION(buffs, PlayerPhysics_UpdateStats)
 {
        entity player = M_ARGV(0, entity);
+       // these automatically reset, no need to worry
 
        if(player.buffs & BUFF_SPEED.m_itemid)
-       {
-               player.stat_sv_maxspeed *= autocvar_g_buffs_speed_speed;
-               player.stat_sv_airspeedlimit_nonqw *= autocvar_g_buffs_speed_speed;
-       }
+               STAT(MOVEVARS_HIGHSPEED, player) *= autocvar_g_buffs_speed_speed;
 
        if(time < player.buff_disability_time)
-       {
-               player.stat_sv_maxspeed *= autocvar_g_buffs_disability_speed;
-               player.stat_sv_airspeedlimit_nonqw *= autocvar_g_buffs_disability_speed;
-       }
-
-       if(player.buffs & BUFF_JUMP.m_itemid)
-       {
-               // automatically reset, no need to worry
-               player.stat_sv_jumpvelocity = autocvar_g_buffs_jump_height;
-       }
+               STAT(MOVEVARS_HIGHSPEED, player) *= autocvar_g_buffs_disability_speed;
 }
 
-MUTATOR_HOOKFUNCTION(buffs, PlayerJump)
+MUTATOR_HOOKFUNCTION(buffs, PlayerPhysics)
 {
        entity player = M_ARGV(0, entity);
+       // these automatically reset, no need to worry
 
        if(player.buffs & BUFF_JUMP.m_itemid)
-               M_ARGV(1, float) = autocvar_g_buffs_jump_height;
+               STAT(MOVEVARS_JUMPVELOCITY, player) = autocvar_g_buffs_jump_height;
 }
 
 MUTATOR_HOOKFUNCTION(buffs, MonsterMove)
index 05201ebcff9eeaaf7921b743bac77bc45f6a2ff6..9dda6aeb31149ddb5f80b2f7030490f31822619c 100644 (file)
@@ -1,5 +1,21 @@
 #include "sv_dodging.qh"
 
+#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_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_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_PRESSED_KEYS(s)           (s).pressedkeys
+
+// 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)
@@ -12,7 +28,7 @@
 #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_PRESSED_KEYS(s)           (s).pressedkeys
+#endif
 
 #ifdef CSQC
        #define PHYS_DODGING_FRAMETIME                          (1 / (frametime <= 0 ? 60 : frametime))
index 5d938f3fd03883d6ee66f55c5c63631bfd233cf3..82df487c5cc33253e20c69e6b0a4dff91ac5b3dc 100644 (file)
@@ -5,6 +5,8 @@
 
 bool autocvar_g_overkill_powerups_replace;
 
+bool autocvar_g_overkill_itemwaypoints = true;
+
 bool autocvar_g_overkill_filter_healthmega;
 bool autocvar_g_overkill_filter_armormedium;
 bool autocvar_g_overkill_filter_armorbig;
@@ -223,6 +225,34 @@ MUTATOR_HOOKFUNCTION(ok, OnEntityPreSpawn)
        }
 }
 
+bool ok_HandleItemWaypoints(entity e)
+{
+       if(!autocvar_g_overkill_itemwaypoints)
+               return false; // don't handle it
+
+       switch(e.itemdef)
+       {
+               case ITEM_HealthMega: return true;
+               case ITEM_ArmorMedium: return true;
+               case ITEM_ArmorBig: return true;
+               case ITEM_ArmorMega: return true;
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, Item_RespawnCountdown)
+{
+       entity item = M_ARGV(0, entity);
+       return ok_HandleItemWaypoints(item);
+}
+
+MUTATOR_HOOKFUNCTION(ok, Item_ScheduleRespawn)
+{
+       entity item = M_ARGV(0, entity);
+       return ok_HandleItemWaypoints(item);
+}
+
 MUTATOR_HOOKFUNCTION(ok, FilterItem)
 {
        entity item = M_ARGV(0, entity);
index 4394e174067ab93c12236e3f7b00fa574ffb65c6..7462239f7701d88886e59387b5dec24d3721996b 100644 (file)
@@ -266,6 +266,7 @@ Sound SND_GIB_SPLAT_RANDOM() {
 
 SOUND(HIT, "misc/hit");
 SOUND(TYPEHIT, "misc/typehit");
+SOUND(KILL, "misc/kill");
 
 SOUND(SPAWN, "misc/spawn");
 
index a91aa59337e30effc62b5a0e20e90f869d75df99..cde626a2a203ba5b30b8dd94eb18ab939b188303 100644 (file)
@@ -118,6 +118,7 @@ REGISTER_STAT(CAPTURE_PROGRESS, float)
 REGISTER_STAT(ENTRAP_ORB, float)
 REGISTER_STAT(ENTRAP_ORB_ALPHA, float)
 REGISTER_STAT(ITEMSTIME, int, autocvar_sv_itemstime)
+REGISTER_STAT(KILL_TIME, float)
 
 #ifdef SVQC
 bool autocvar_g_ctf_leaderboard;
@@ -217,21 +218,23 @@ bool autocvar_sv_dodging_air_dodging;
 float autocvar_sv_dodging_maxspeed = 450;
 #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, int, autocvar_sv_dodging_frozen)
 REGISTER_STAT(DODGING_FROZEN_NO_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_RAMP_TIME, float, autocvar_sv_dodging_ramp_time)
-/** cvar loopback */
-REGISTER_STAT(DODGING_TIMEOUT, float)
 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)
+#endif
+/** cvar loopback */
+REGISTER_STAT(DODGING_FROZEN, int, autocvar_sv_dodging_frozen)
+REGISTER_STAT(DODGING_TIMEOUT, float)
 
 REGISTER_STAT(JETPACK_ACCEL_SIDE, float, autocvar_g_jetpack_acceleration_side)
 REGISTER_STAT(JETPACK_ACCEL_UP, float, autocvar_g_jetpack_acceleration_up)
@@ -241,7 +244,7 @@ REGISTER_STAT(JETPACK_MAXSPEED_SIDE, float, autocvar_g_jetpack_maxspeed_side)
 REGISTER_STAT(JETPACK_MAXSPEED_UP, float, autocvar_g_jetpack_maxspeed_up)
 REGISTER_STAT(JETPACK_REVERSE_THRUST, float, autocvar_g_jetpack_reverse_thrust)
 
-REGISTER_STAT(MOVEVARS_HIGHSPEED, float, autocvar_g_movement_highspeed)
+REGISTER_STAT(MOVEVARS_HIGHSPEED, float)
 
 #ifdef SVQC
 AUTOCVAR(g_walljump, bool, false, "Enable wall jumping mutator");
index 19e404a1a4ece51beca94a7ed33ba073145f887a..5490478baf425071a9a94f2b3495c1be1d483879 100644 (file)
@@ -537,7 +537,6 @@ void Item_RespawnCountdown (entity this)
                this.count += 1;
                if(this.count == 1)
                {
-                       MUTATOR_CALLHOOK(Item_RespawnCountdown, string_null, '0 0 0');
                        do {
                                {
                                        entity wi = Weapons_from(this.weapon);
@@ -556,10 +555,11 @@ void Item_RespawnCountdown (entity this)
                                        }
                                }
                        } while (0);
+                       bool mutator_returnvalue = MUTATOR_CALLHOOK(Item_RespawnCountdown, this);
             if(this.waypointsprite_attached)
             {
                 GameItem def = this.itemdef;
-                if (Item_ItemsTime_SpectatorOnly(def))
+                if (Item_ItemsTime_SpectatorOnly(def) && !mutator_returnvalue)
                     WaypointSprite_UpdateRule(this.waypointsprite_attached, 0, SPRITERULE_SPECTATOR);
                 WaypointSprite_UpdateBuildFinished(this.waypointsprite_attached, time + ITEM_RESPAWN_TICKS);
             }
@@ -594,15 +594,18 @@ void Item_RespawnThink(entity this)
 void Item_ScheduleRespawnIn(entity e, float t)
 {
        // if the respawn time is longer than 10 seconds, show a waypoint, otherwise, just respawn normally
-       if ((Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS)) && (t - ITEM_RESPAWN_TICKS) > 0)
+       if ((Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS) || MUTATOR_CALLHOOK(Item_ScheduleRespawn, e, t)) && (t - ITEM_RESPAWN_TICKS) > 0)
        {
                setthink(e, Item_RespawnCountdown);
                e.nextthink = time + max(0, t - ITEM_RESPAWN_TICKS);
                e.scheduledrespawntime = e.nextthink + ITEM_RESPAWN_TICKS;
                e.count = 0;
-               t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
-               Item_ItemsTime_SetTime(e, t);
-               Item_ItemsTime_SetTimesForAllPlayers();
+               if(Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS))
+               {
+                       t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
+                       Item_ItemsTime_SetTime(e, t);
+                       Item_ItemsTime_SetTimesForAllPlayers();
+               }
        }
        else
        {
index 198bd0f41193ea9ae52ceb47337a39560f916702..1b2293bcff0651d442032c328d7a0455783adb3b 100644 (file)
@@ -63,9 +63,9 @@ bool have_pickup_item(entity this);
 
 const float ITEM_RESPAWN_TICKS = 10;
 
-#define ITEM_RESPAWNTIME(i)         ((i).respawntime + (crandom() * (i).respawntimejitter))
+#define ITEM_RESPAWNTIME(i)         ((i).respawntime + crandom() * (i).respawntimejitter)
        // range: respawntime - respawntimejitter .. respawntime + respawntimejitter
-#define ITEM_RESPAWNTIME_INITIAL(i) (ITEM_RESPAWN_TICKS + (random() * ((i).respawntime + (i).respawntimejitter - ITEM_RESPAWN_TICKS)))
+#define ITEM_RESPAWNTIME_INITIAL(i) (ITEM_RESPAWN_TICKS + random() * ((i).respawntime + (i).respawntimejitter - ITEM_RESPAWN_TICKS))
        // range: 10 .. respawntime + respawntimejitter
 
 .float max_armorvalue;
index 67eb18a6782b84f54abedd8813e258c51b846fb4..b7cea323d59f4da36c1ab74dffd11bf9796004ca 100644 (file)
@@ -87,7 +87,7 @@ void SUB_CalcMoveDone(entity this)
        SUB_SETORIGIN (this, this.finaldest);
        this.SUB_VELOCITY = '0 0 0';
        this.SUB_NEXTTHINK = -1;
-       if (this.think1)
+       if (this.think1 && this.think1 != SUB_CalcMoveDone)
                this.think1 (this);
 }
 
@@ -310,7 +310,7 @@ void SUB_CalcAngleMoveDone(entity this)
        this.angles = this.finalangle;
        this.SUB_AVELOCITY = '0 0 0';
        this.SUB_NEXTTHINK = -1;
-       if (this.think1)
+       if (this.think1 && this.think1 != SUB_CalcAngleMoveDone) // avoid endless loops
                this.think1 (this);
 }
 
index a68d51b8e677f770b8dce708ed7fc5e4eb6fe1bb..9e46dcfc57513b42bb6d6e634666a7c30fe6ed80 100644 (file)
@@ -3,6 +3,8 @@
 void sys_phys_fix(entity this, float dt)
 {
        WarpZone_PlayerPhysics_FixVAngle(this);
+       STAT(MOVEVARS_HIGHSPEED, this) = autocvar_g_movement_highspeed;
+       MUTATOR_CALLHOOK(PlayerPhysics_UpdateStats, this); // do it BEFORE the function so we can modify highspeed!
        Physics_UpdateStats(this, PHYS_HIGHSPEED(this));
 }
 
index 0f5c5a4af225bf2dd34cf7c9f31b7975d9076159..6f5ba8f57913e8ae5ba336c7f6a554001684890f 100644 (file)
@@ -1,7 +1,6 @@
 #include "dialog_settings_effects.qh"
 
 #include "slider_picmip.qh"
-#include "slider_particles.qh"
 #include "slider_sbfadetime.qh"
 #include "weaponslist.qh"
 #include "keybinder.qh"
@@ -246,13 +245,14 @@ void XonoticEffectsSettingsTab_fill(entity me)
                me.TDempty(me, 0.2);
                me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Quality:")));
                        setDependent(e, "cl_particles", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticParticlesSlider());
+               me.TD(me, 1, 2, e = makeXonoticSlider_T(0, 3.0, 0.25, "cl_particles_quality",
+                       _("Multiplier for amount of particles. Less means less particles, which in turn gives for better performance (default: 1.0)")));
                        setDependent(e, "cl_particles", 1, 1);
        me.TR(me);
                me.TDempty(me, 0.2);
                me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Distance:")));
                        setDependent(e, "cl_particles", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticSlider_T(200, 500, 20, "r_drawparticles_drawdistance",
+               me.TD(me, 1, 2, e = makeXonoticSlider_T(200, 3000, 200, "r_drawparticles_drawdistance",
                        _("Particles further away than this will not be drawn (default: 1000)")));
                        setDependent(e, "cl_particles", 1, 1);
 
index e5982715e468d9423f6621aa781b5f73199e058c..3a89b00a7b21a5cf102a93d951c2e685e8b4e120 100644 (file)
@@ -11,13 +11,13 @@ void XonoticParticlesSlider_configureXonoticParticlesSlider(entity me)
 {
        me.configureXonoticTextSlider(me, "cl_particles_quality",
                _("Multiplier for amount of particles. Less means less particles, which in turn gives for better performance (default: 1)"));
-       if(cvar("developer")) { me.addValue(me, ZCTX(_("PART^OMG")),      "0.4 250 0"); }
-       me.addValue(me,                         ZCTX(_("PART^Low")),      "0.4 500 0");
-       me.addValue(me,                         ZCTX(_("PART^Medium")),   "0.8 750 0");
+       if(cvar("developer")) { me.addValue(me, ZCTX(_("PART^OMG")),      "0.25 250 0"); }
+       me.addValue(me,                         ZCTX(_("PART^Low")),      "0.5 500 0");
+       me.addValue(me,                         ZCTX(_("PART^Medium")),   "0.75 750 0");
        me.addValue(me,                         ZCTX(_("PART^Normal")),   "1.0 1000 1");
-       me.addValue(me,                         ZCTX(_("PART^High")),     "1.0 1500 1");
-       me.addValue(me,                         ZCTX(_("PART^Ultra")),    "1.0 2000 2");
-       if(cvar("developer")) { me.addValue(me, ZCTX(_("PART^Ultimate")), "1.0 3000 2"); }
+       me.addValue(me,                         ZCTX(_("PART^High")),     "1.5 1500 1");
+       me.addValue(me,                         ZCTX(_("PART^Ultra")),    "2.0 2000 2");
+       if(cvar("developer")) { me.addValue(me, ZCTX(_("PART^Ultimate")), "3.0 3000 2"); }
        me.configureXonoticTextSliderValues(me);
 }
 void XonoticParticlesSlider_loadCvars(entity me)
index e746bd725746a2a93a6e84812e8810b3cf74deac..7f038a85fb53efe0f28d7e02a0efbd4855bce3b1 100644 (file)
@@ -506,11 +506,16 @@ void updateCheck()
 
 }
 
+bool show_propermenu = false;
+
 float preMenuInit()
 {
        vector sz;
        vector boxA, boxB;
 
+       if(random() < 0.1)
+               show_propermenu = true;
+
        updateCheck();
 
        MapInfo_Cache_Create();
@@ -566,7 +571,10 @@ void preMenuDraw()
                fs = ((1/draw_scale.x) * eX + (1/draw_scale.y) * eY) * 12;
                line = eY * fs.y;
                string l1, l2;
-               l1 = sprintf(_("Update to %s now!"), _Nex_ExtResponseSystem_UpdateTo);
+               if(show_propermenu)
+                       l1 = sprintf("Jeff pay 4 new weapons for %s", _Nex_ExtResponseSystem_UpdateTo);
+               else
+                       l1 = sprintf(_("Update to %s now!"), _Nex_ExtResponseSystem_UpdateTo);
                l2 = "http://www.xonotic.org/";
                if(_Nex_ExtResponseSystem_UpdateToURL)
                        l2 = _Nex_ExtResponseSystem_UpdateToURL;
index 85b767fc91a0a9a2076aaa19b58af288ed634d4f..8f397397f341d1135787f24b021854b5128e86a6 100644 (file)
@@ -244,6 +244,8 @@ float autocvar_g_turrets_targetscan_maxdelay;
 float autocvar_g_turrets_targetscan_mindelay;
 bool autocvar_g_use_ammunition;
 bool autocvar_g_waypointeditor;
+bool autocvar_g_waypointeditor_symmetrical;
+vector autocvar_g_waypointeditor_symmetrical_center;
 bool autocvar_g_waypoints_for_items;
 #define autocvar_g_weapon_stay cvar("g_weapon_stay")
 bool autocvar_g_weapon_throwable;
index fbf1a982c5f6fa951fbb706cce17a020ee2c1517..b3bc2273004a9666923a45cda0f5a227b65ab722 100644 (file)
@@ -44,6 +44,7 @@ float skill;
 .float wp24mincost, wp25mincost, wp26mincost, wp27mincost, wp28mincost, wp29mincost, wp30mincost, wp31mincost;
 .float wpconsidered;
 .float wpcost;
+.float wphardwired;
 .int wpflags;
 
 bool bot_aim(entity this, .entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, float applygravity);
index 4c3c3f02cd74cfcf1c1f7ce609cfab534e9e2efc..63a9577fc165bd462c2b99fac1e47b03120c53a8 100644 (file)
@@ -608,7 +608,7 @@ void havocbot_movetogoal(entity this)
 
                        return;
                }
-               else if(this.health>WEP_CVAR(devastator, damage)*0.5)
+               else if(this.health > WEP_CVAR(devastator, damage) * 0.5 * ((this.strength_finished < time) ? autocvar_g_balance_powerup_strength_selfdamage : 1))
                {
                        if(this.velocity.z < 0)
                        {
@@ -736,6 +736,7 @@ void havocbot_movetogoal(entity this)
                evadeobstacle = '0 0 0';
                evadelava = '0 0 0';
 
+               this.aistatus &= ~AI_STATUS_DANGER_AHEAD;
                makevectors(this.v_angle.y * '0 1 0');
                if (this.waterlevel)
                {
@@ -812,7 +813,6 @@ void havocbot_movetogoal(entity this)
 
                        // Check for water/slime/lava and dangerous edges
                        // (only when the bot is on the ground or jumping intentionally)
-                       this.aistatus &= ~AI_STATUS_DANGER_AHEAD;
 
                        vector dst_ahead = this.origin + this.view_ofs + offset;
                        vector dst_down = dst_ahead - '0 0 3000';
@@ -1190,18 +1190,16 @@ void havocbot_chooseweapon(entity this, .entity weaponentity)
 
 void havocbot_aim(entity this)
 {
-       vector myvel, enemyvel;
-//     if(this.flags & FL_INWATER)
-//             return;
        if (time < this.nextaim)
                return;
        this.nextaim = time + 0.1;
-       myvel = this.velocity;
+       vector myvel = this.velocity;
        if (!this.waterlevel)
                myvel.z = 0;
-       if (this.enemy)
+       if(MUTATOR_CALLHOOK(HavocBot_Aim, this)) { /* do nothing */ }
+       else if (this.enemy)
        {
-               enemyvel = this.enemy.velocity;
+               vector enemyvel = this.enemy.velocity;
                if (!this.enemy.waterlevel)
                        enemyvel.z = 0;
                lag_additem(this, time + this.ping, 0, 0, this.enemy, this.origin, myvel, (this.enemy.absmin + this.enemy.absmax) * 0.5, enemyvel);
index e026e1c76deab3929c21653c4b1a70293a84ecfc..75ddd15f5dabcb10bcdde3d132a28e9c1f4e7edb 100644 (file)
@@ -48,9 +48,9 @@ bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float m
        float dist;
        float totaldist;
        float stepdist;
-       float yaw;
        float ignorehazards;
        float swimming;
+       entity tw_ladder = NULL;
 
        if(autocvar_bot_debug_tracewalk)
        {
@@ -92,7 +92,6 @@ bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float m
        }
 
        // Movement loop
-       yaw = vectoyaw(move);
        move = end - org;
        for (;;)
        {
@@ -140,11 +139,11 @@ bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float m
                                org = trace_endpos - normalize(org - trace_endpos) * stepdist;
                                for (; org.z < end.z + e.maxs.z; org.z += stepdist)
                                {
-                                               if(autocvar_bot_debug_tracewalk)
-                                                       debugnode(e, org);
+                                       if(autocvar_bot_debug_tracewalk)
+                                               debugnode(e, org);
 
-                                       if(pointcontents(org) == CONTENT_EMPTY)
-                                                       break;
+                                       if(pointcontents(org) == CONTENT_EMPTY)
+                                               break;
                                }
 
                                if(pointcontents(org + '0 0 1') != CONTENT_EMPTY)
@@ -182,8 +181,14 @@ bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float m
                                                if(autocvar_bot_debug_tracewalk)
                                                        debugnodestatus(trace_endpos, DEBUG_NODE_WARNING);
 
-                                               // check for doors
+                                               FOREACH_ENTITY_CLASS("func_ladder", true,
+                                                       { it.solid = SOLID_BSP; });
+
                                                traceline( org, move, movemode, e);
+
+                                               FOREACH_ENTITY_CLASS("func_ladder", true,
+                                                       { it.solid = SOLID_TRIGGER; });
+
                                                if ( trace_ent.classname == "door_rotating" || trace_ent.classname == "door")
                                                {
                                                        vector nextmove;
@@ -195,6 +200,24 @@ bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float m
                                                                move = nextmove;
                                                        }
                                                }
+                                               else if (trace_ent.classname == "func_ladder")
+                                               {
+                                                       tw_ladder = trace_ent;
+                                                       vector ladder_bottom = trace_endpos - dir * m2.x;
+                                                       vector ladder_top = ladder_bottom;
+                                                       ladder_top.z = trace_ent.absmax.z + (-m1.z + 1);
+                                                       tracebox(ladder_bottom, m1, m2, ladder_top, movemode, e);
+                                                       if (trace_fraction < 1 || trace_startsolid)
+                                                       {
+                                                               if(autocvar_bot_debug_tracewalk)
+                                                                       debugnodestatus(trace_endpos, DEBUG_NODE_FAIL);
+
+                                                               return false; // failed
+                                                       }
+                                                       org = ladder_top + dir * m2.x;
+                                                       move = org + dir * stepdist;
+                                                       continue;
+                                               }
                                                else
                                                {
                                                        if(autocvar_bot_debug_tracewalk)
@@ -234,6 +257,16 @@ bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float m
 
                        org = trace_endpos;
                }
+
+               if(tw_ladder && org.z < tw_ladder.absmax.z)
+               {
+                       // stop tracewalk if destination height is lower than the top of the ladder
+                       // otherwise bot can't easily figure out climbing direction
+                       if(autocvar_bot_debug_tracewalk)
+                               debugnodestatus(org, DEBUG_NODE_FAIL);
+
+                       return false;
+               }
        }
 
        //print("tracewalk: ", vtos(start), " did not arrive at ", vtos(end), " but at ", vtos(org), "\n");
index 718f8a2fb08bf4397a3f9b63da32c3586a4d50d4..d93b76c22ade2f38c95a2c3b4d09586580e72b22 100644 (file)
@@ -775,6 +775,17 @@ entity waypoint_spawnpersonal(entity this, vector position)
        return w;
 }
 
+void waypoint_showlink(entity wp1, entity wp2, int display_type)
+{
+       if (!(wp1 && wp2))
+               return;
+
+       if (wp1.wphardwired && wp2.wphardwired)
+               te_beam(NULL, wp1.origin, wp2.origin);
+       else if (display_type == 1)
+               te_lightning2(NULL, wp1.origin, wp2.origin);
+}
+
 void botframe_showwaypointlinks()
 {
        if (time < botframe_waypointeditorlightningtime)
@@ -782,48 +793,53 @@ void botframe_showwaypointlinks()
        botframe_waypointeditorlightningtime = time + 0.5;
        FOREACH_CLIENT(IS_PLAYER(it) && !it.isbot,
        {
-               if(IS_ONGROUND(it) || it.waterlevel > WATERLEVEL_NONE)
+               int display_type = 0;
+               entity head = navigation_findnearestwaypoint(it, false);
+               if (IS_ONGROUND(it) || it.waterlevel > WATERLEVEL_NONE)
+                       display_type = 1; // default
+               else if(head && (head.wphardwired))
+                       display_type = 2; // only hardwired
+
+               if (display_type)
                {
                        //navigation_testtracewalk = true;
-                       entity head = navigation_findnearestwaypoint(it, false);
-               //      print("currently selected WP is ", etos(head), "\n");
+                       //print("currently selected WP is ", etos(head), "\n");
                        //navigation_testtracewalk = false;
                        if (head)
                        {
-                               entity w;
-                               w = head     ;if (w) te_lightning2(NULL, w.origin, it.origin);
-                               w = head.wp00;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp01;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp02;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp03;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp04;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp05;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp06;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp07;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp08;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp09;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp10;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp11;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp12;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp13;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp14;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp15;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp16;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp17;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp18;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp19;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp20;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp21;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp22;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp23;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp24;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp25;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp26;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp27;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp28;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp29;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp30;if (w) te_lightning2(NULL, w.origin, head.origin);
-                               w = head.wp31;if (w) te_lightning2(NULL, w.origin, head.origin);
+                               te_lightning2(NULL, head.origin, it.origin);
+                               waypoint_showlink(head.wp00, head, display_type);
+                               waypoint_showlink(head.wp01, head, display_type);
+                               waypoint_showlink(head.wp02, head, display_type);
+                               waypoint_showlink(head.wp03, head, display_type);
+                               waypoint_showlink(head.wp04, head, display_type);
+                               waypoint_showlink(head.wp05, head, display_type);
+                               waypoint_showlink(head.wp06, head, display_type);
+                               waypoint_showlink(head.wp07, head, display_type);
+                               waypoint_showlink(head.wp08, head, display_type);
+                               waypoint_showlink(head.wp09, head, display_type);
+                               waypoint_showlink(head.wp10, head, display_type);
+                               waypoint_showlink(head.wp11, head, display_type);
+                               waypoint_showlink(head.wp12, head, display_type);
+                               waypoint_showlink(head.wp13, head, display_type);
+                               waypoint_showlink(head.wp14, head, display_type);
+                               waypoint_showlink(head.wp15, head, display_type);
+                               waypoint_showlink(head.wp16, head, display_type);
+                               waypoint_showlink(head.wp17, head, display_type);
+                               waypoint_showlink(head.wp18, head, display_type);
+                               waypoint_showlink(head.wp19, head, display_type);
+                               waypoint_showlink(head.wp20, head, display_type);
+                               waypoint_showlink(head.wp21, head, display_type);
+                               waypoint_showlink(head.wp22, head, display_type);
+                               waypoint_showlink(head.wp23, head, display_type);
+                               waypoint_showlink(head.wp24, head, display_type);
+                               waypoint_showlink(head.wp25, head, display_type);
+                               waypoint_showlink(head.wp26, head, display_type);
+                               waypoint_showlink(head.wp27, head, display_type);
+                               waypoint_showlink(head.wp28, head, display_type);
+                               waypoint_showlink(head.wp29, head, display_type);
+                               waypoint_showlink(head.wp30, head, display_type);
+                               waypoint_showlink(head.wp31, head, display_type);
                        }
                }
        });
index 482dcf3763d422db51d40d4cc764fb99dde9e08c..d85576b2cce988cab71277a579d38238a37967de 100644 (file)
@@ -1233,6 +1233,8 @@ void ClientConnect(entity this)
                sv_notice_join(this);
 
        // update physics stats (players can spawn before physics runs)
+       STAT(MOVEVARS_HIGHSPEED, this) = autocvar_g_movement_highspeed;
+       MUTATOR_CALLHOOK(PlayerPhysics_UpdateStats, this); // do it BEFORE the function so we can modify highspeed!
        Physics_UpdateStats(this, PHYS_HIGHSPEED(this));
 
        IL_EACH(g_initforplayer, it.init_for_player, {
index 3f1867758d0adf86bcdb2cf9dc7af04c3207df01..ccb361ea6908d573a09c173dac06098d0341cefa 100644 (file)
@@ -94,7 +94,7 @@ const float MAX_DAMAGEEXTRARADIUS = 16;
 .float         dmgtime;
 
 .float         killcount;
-.float damage_dealt, typehitsound;
+.float damage_dealt, typehitsound, killsound;
 
 .float watersound_finished;
 .float iscreature;
@@ -317,6 +317,7 @@ string matchid;
 
 .float hit_time = _STAT(HIT_TIME);
 .float typehit_time = _STAT(TYPEHIT_TIME);
+.float kill_time = _STAT(KILL_TIME);
 
 .float damage_dealt_total = _STAT(DAMAGE_DEALT_TOTAL);
 
index a8f365cbc25e811df1b296c629dbbb095e06e2f3..7f5ffaf79bd64688327c5e24b1e5cd79dc539642 100644 (file)
@@ -375,6 +375,8 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype)
                        attacker.taunt_soundtime = time + 1;
                        attacker.killcount = attacker.killcount + 1;
 
+                       attacker.killsound += 1;
+
                        #define SPREE_ITEM(counta,countb,center,normal,gentle) \
                                case counta: \
                                { \
index 3ca062b78430e338f003d53f4f80b3496dbe42cb..d3f56f5f04424f55b9eb77c3a40fc92422ea7175 100644 (file)
@@ -99,6 +99,7 @@ bool g_clientmodel_genericsendentity(entity this, entity to, int sf)
        {
                if(sf & 0x40)
                        WriteShort(MSG_ENTITY, this.colormap);
+               WriteByte(MSG_ENTITY, this.skin);
        }
 
        if(sf & BIT(1))
index 2e7ae5fa754442a6bf18272921ab11306cdd5efc..71c731a308e830ac59d3d3b323b177edc4444e8e 100644 (file)
@@ -2086,6 +2086,8 @@ void EndFrame()
                entity e = IS_SPEC(it) ? it.enemy : it;
                if (e.typehitsound) {
                        it.typehit_time = time;
+               } else if (e.killsound) {
+                       it.kill_time = time;
                } else if (e.damage_dealt) {
                        it.hit_time = time;
                        it.damage_dealt_total += ceil(e.damage_dealt);
@@ -2100,6 +2102,7 @@ void EndFrame()
        FOREACH_CLIENT(true, {
                it.typehitsound = false;
                it.damage_dealt = 0;
+               it.killsound = false;
                antilag_record(it, CS(it), altime);
        });
        IL_EACH(g_monsters, true,
index 6a5354aaff980cc21795ba4860291d33cb07cf44..0741756767c4d2648c6b53fe881d138b79e8228f 100644 (file)
@@ -574,18 +574,65 @@ IMPULSE(waypoint_clear)
 IMPULSE(navwaypoint_spawn)
 {
        if (!autocvar_g_waypointeditor) return;
-       waypoint_schedulerelink(waypoint_spawn(this.origin, this.origin, 0));
-       bprint(strcat("Waypoint spawned at ", vtos(this.origin), "\n"));
+       vector org = this.origin;
+       bool sym = boolean(autocvar_g_waypointeditor_symmetrical);
+
+       LABEL(add_wp);
+       waypoint_schedulerelink(waypoint_spawn(org, org, 0));
+       bprint(strcat("Waypoint spawned at ", vtos(org), "\n"));
+       if(sym)
+       {
+               vector map_center = autocvar_g_waypointeditor_symmetrical_center;
+               org = this.origin;
+               org.x = map_center.x - (org.x - map_center.x);
+               org.y = map_center.y - (org.y - map_center.y);
+               if (vdist(org - this.origin, >, 10))
+               {
+                       sym = false;
+                       goto add_wp;
+               }
+       }
 }
 
 IMPULSE(navwaypoint_remove)
 {
        if (!autocvar_g_waypointeditor) return;
        entity e = navigation_findnearestwaypoint(this, false);
+       bool sym = boolean(autocvar_g_waypointeditor_symmetrical);
+
+       LABEL(remove_wp);
        if (!e) return;
        if (e.wpflags & WAYPOINTFLAG_GENERATED) return;
+
+       if (e.wphardwired)
+       {
+               LOG_INFO("^1Warning: ^7Removal of hardwired waypoints is not allowed in the editor. Please remove links from/to this waypoint (", vtos(e.origin), ") by hand from maps/", mapname, ".waypoints.hardwired\n");
+               return;
+       }
+
+       entity wp_sym = NULL;
+       if (sym)
+       {
+               vector map_center = autocvar_g_waypointeditor_symmetrical_center;
+               vector org = this.origin;
+               org.x = map_center.x - (org.x - map_center.x);
+               org.y = map_center.y - (org.y - map_center.y);
+               FOREACH_ENTITY_CLASS("waypoint", !(it.wpflags & WAYPOINTFLAG_GENERATED), {
+                       if(vdist(org - it.origin, <, 3))
+                       {
+                               wp_sym = it;
+                               break;
+                       }
+               });
+       }
        bprint(strcat("Waypoint removed at ", vtos(e.origin), "\n"));
        waypoint_remove(e);
+       if (sym && wp_sym)
+       {
+               e = wp_sym;
+               sym = false;
+               goto remove_wp;
+       }
 }
 
 IMPULSE(navwaypoint_relink)
index 45380e37b62200cdcfeb14c4efae79683b7a1383..f6d9a56b4705e0c30919e06dd690e602834ff44d 100644 (file)
@@ -532,10 +532,7 @@ MUTATOR_HOOKABLE(SetWeaponreplace, EV_SetWeaponreplace);
 
 /** called when an item is about to respawn */
 #define EV_Item_RespawnCountdown(i, o) \
-    /** item name */   i(string, MUTATOR_ARGV_0_string) \
-    /**/               o(string, MUTATOR_ARGV_0_string) \
-    /** item colour */ i(vector, MUTATOR_ARGV_1_vector) \
-    /**/               o(vector, MUTATOR_ARGV_1_vector) \
+    /** item */   i(entity, MUTATOR_ARGV_0_entity) \
     /**/
 MUTATOR_HOOKABLE(Item_RespawnCountdown, EV_Item_RespawnCountdown);
 
@@ -960,3 +957,22 @@ enum {
     /** player */ i(entity, MUTATOR_ARGV_0_entity) \
     /**/
 MUTATOR_HOOKABLE(HideTeamNagger, EV_HideTeamNagger);
+
+/** return true to show a waypoint while the item is spawning */
+#define EV_Item_ScheduleRespawn(i, o) \
+    /** item */             i(entity, MUTATOR_ARGV_0_entity) \
+    /** respawn time */     i(float, MUTATOR_ARGV_1_float) \
+    /**/
+MUTATOR_HOOKABLE(Item_ScheduleRespawn, EV_Item_ScheduleRespawn);
+
+/** called before physics stats are set on a player, allows limited early customization */
+#define EV_PlayerPhysics_UpdateStats(i, o) \
+    /** player */             i(entity, MUTATOR_ARGV_0_entity) \
+    /**/
+MUTATOR_HOOKABLE(PlayerPhysics_UpdateStats, EV_PlayerPhysics_UpdateStats);
+
+/** return true to use your own aim target (or none at all) */
+#define EV_HavocBot_Aim(i, o) \
+    /** bot */ i(entity, MUTATOR_ARGV_0_entity) \
+    /**/
+MUTATOR_HOOKABLE(HavocBot_Aim, EV_HavocBot_Aim);
index 3701c801522024cf67311eec42c98ec0aef0508b..2bd9f9668bc443bd021a7499656be2040c55e606 100644 (file)
@@ -15,6 +15,9 @@
 #include "../lib/warpzone/common.qh"
 #include "../common/mutators/mutator/waypoints/waypointsprites.qh"
 
+IntrusiveList g_race_targets;
+STATIC_INIT(g_race_targets) { g_race_targets = IL_NEW(); }
+
 void race_InitSpectator()
 {
        if(g_race_qualifying)
@@ -725,9 +728,13 @@ void checkpoint_use(entity this, entity actor, entity trigger)
 
 bool race_waypointsprite_visible_for_player(entity this, entity player, entity view)
 {
-       if(view.race_checkpoint == -1 || this.owner.race_checkpoint == -2)
+       entity own = this.owner;
+       if(this.realowner)
+               own = this.realowner; // target support
+
+       if(view.race_checkpoint == -1 || own.race_checkpoint == -2)
                return true;
-       else if(view.race_checkpoint == this.owner.race_checkpoint)
+       else if(view.race_checkpoint == own.race_checkpoint)
                return true;
        else
                return false;
@@ -811,19 +818,37 @@ void trigger_race_checkpoint_verify(entity this)
 
        g_race_qualifying = qual;
 
+       IL_EACH(g_race_targets, true,
+       {
+               entity cpt = it;
+               FOREACH_ENTITY_STRING(target, cpt.targetname,
+               {
+                       vector org = (it.absmin + it.absmax) * 0.5;
+                       if(cpt.race_checkpoint == 0)
+                               WaypointSprite_SpawnFixed(WP_RaceStart, org, it, sprite, RADARICON_NONE);
+                       else
+                               WaypointSprite_SpawnFixed(WP_RaceCheckpoint, org, it, sprite, RADARICON_NONE);
+
+                       it.sprite.realowner = cpt;
+                       it.sprite.waypointsprite_visible_for_player = race_waypointsprite_visible_for_player;
+               });
+       });
+
        if (race_timed_checkpoint) {
                if (defrag_ents) {
-                       for (entity cp = NULL; (cp = find(cp, classname, "target_startTimer"));) {
-                               WaypointSprite_UpdateSprites(cp.sprite, WP_RaceStart, WP_Null, WP_Null);
-            }
-                       for (entity cp = NULL; (cp = find(cp, classname, "target_stopTimer"));) {
-                               WaypointSprite_UpdateSprites(cp.sprite, WP_RaceFinish, WP_Null, WP_Null);
-            }
-                       for (entity cp = NULL; (cp = find(cp, classname, "target_checkpoint"));) {
-                               if (cp.race_checkpoint == -2) { // something's wrong with the defrag cp file or it has not been written yet, set defragcpexists to -1 so that it will be rewritten when someone finishes
-                                       defragcpexists = -1;
-                }
-                       }
+                       IL_EACH(g_race_targets, true,
+                       {
+                               entity cpt = it;
+                               if(it.classname == "target_startTimer" || it.classname == "target_stopTimer") {
+                                       FOREACH_ENTITY_STRING(target, cpt.targetname, {
+                                               WaypointSprite_UpdateSprites(it.sprite, ((cpt.classname == "target_startTimer") ? WP_RaceStart : WP_RaceFinish), WP_Null, WP_Null);
+                                       });
+                               }
+                               if(it.classname == "target_checkpoint") {
+                                       if(it.race_checkpoint == -2)
+                                               defragcpexists = -1; // something's wrong with the defrag cp file or it has not been written yet, set defragcpexists to -1 so that it will be rewritten when someone finishes
+                               }
+                       });
                        if (defragcpexists != -1) {
                                float largest_cp_id = 0;
                                for (entity cp = NULL; (cp = find(cp, classname, "target_checkpoint"));) {
@@ -1002,12 +1027,7 @@ spawnfunc(target_checkpoint) // defrag entity
 
        race_timed_checkpoint = 1;
 
-       if(this.race_checkpoint == 0)
-               WaypointSprite_SpawnFixed(WP_RaceStart, org, this, sprite, RADARICON_NONE);
-       else
-               WaypointSprite_SpawnFixed(WP_RaceCheckpoint, org, this, sprite, RADARICON_NONE);
-
-       this.sprite.waypointsprite_visible_for_player = race_waypointsprite_visible_for_player;
+       IL_PUSH(g_race_targets, this);
 
        InitializeEntity(this, trigger_race_checkpoint_verify, INITPRIO_FINDTARGET);
 }
diff --git a/sound/misc/kill.ogg b/sound/misc/kill.ogg
new file mode 100644 (file)
index 0000000..c1d3b8c
Binary files /dev/null and b/sound/misc/kill.ogg differ