]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into Lyberta/StandaloneOverkillWeapons
authorLyberta <lyberta@lyberta.net>
Fri, 17 Mar 2017 20:13:19 +0000 (23:13 +0300)
committerLyberta <lyberta@lyberta.net>
Fri, 17 Mar 2017 20:13:19 +0000 (23:13 +0300)
24 files changed:
bal-wep-overkill.cfg
balance-overkill.cfg
defaultOverkill.cfg
defaultXonotic.cfg
mutators.cfg
physicsXDF.cfg
qcsrc/client/wall.qc
qcsrc/common/ent_cs.qc
qcsrc/common/mutators/mutator/buffs/sv_buffs.qc
qcsrc/common/mutators/mutator/overkill/sv_overkill.qc
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/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/client.qc
qcsrc/server/g_models.qc
qcsrc/server/impulse.qc
qcsrc/server/mutators/events.qh

index a7b30e4d24b3c5f077834b4a70341445704c5cce..5949be955693adb5f0984e299c6b648e3af42b30 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 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 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 f6fedde848da86d91c7105052c0da1d44cafe630..70217365d40e0156259dff72b2f5ec3e11dc2b09 100644 (file)
@@ -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 b36bae733476dea98ceffa773c9a9980283858a7..1a6faa16fa5209a5eacd8f327a9cbcfb83f24c22 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 095635dda7846b3dc947d2f34bb1bbe7815edf66..bea426a3412513f65256ab8a8ef73cfbf0feebc8 100644 (file)
@@ -246,7 +246,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 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 038aea0f647ca6764c17f796e8994e169d4a8fc2..63a9577fc165bd462c2b99fac1e47b03120c53a8 100644 (file)
@@ -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 488da59d47ace5d5ac92190b1d25e29c928912d8..75ddd15f5dabcb10bcdde3d132a28e9c1f4e7edb 100644 (file)
@@ -50,6 +50,7 @@ bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float m
        float stepdist;
        float ignorehazards;
        float swimming;
+       entity tw_ladder = NULL;
 
        if(autocvar_bot_debug_tracewalk)
        {
@@ -138,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)
@@ -201,6 +202,7 @@ bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float m
                                                }
                                                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);
@@ -255,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 51f0a39530647c4ccf27212ea6fd56faf0de79b5..eeded4b25343337a526a6e05584d08bdb250324c 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 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 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 7523b3aac6ca26a3b54daaec7d2ad1de09a89f1d..89fec0178c7f01c7d00c22d54f0474a38039d449 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);
 
@@ -948,3 +945,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);