- wget -O data/maps/stormkeep.waypoints https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints
- wget -O data/maps/stormkeep.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints.cache
- make
- - EXPECT=422d5d8a0490e961463fda69da1975bc
+ - EXPECT=fb771b180a47f7acf09eb12dddd391f8
- HASH=$(${ENGINE} -noconfig -nohome +exec serverbench.cfg
| tee /dev/stderr
| grep '^:'
QCC=${QCC:-$PWD/../../gmqcc/gmqcc${CMAKE_EXECUTABLE_SUFFIX}}
case $1 in
compile)
- ${CPP} ${@:3} | sed 's/^#\(line\)\? \([[:digit:]]\+\) "\(.*\)".*/\n#pragma file(\3)\n#pragma line(\2)/g' > $2
+ ${CPP} ${@:3} | sed -E 's/^#(line)? ([[:digit:]]+) "(.*)".*/'$'\\\n''#pragma file(\3)'$'\\\n''#pragma line(\2)/g' > $2
;;
link)
${QCC} \
#include <common/mutators/base.qh>
+// register all possible hooks here
+
+// to use a hook, first register your mutator using REGISTER_MUTATOR
+// then create your function using MUTATOR_HOOKFUNCTION
+
/**
* Called when a client command is parsed
* NOTE: hooks MUST start with if (MUTATOR_RETURNVALUE) return false;
#define debug_text_3d_5(pos, msg, align, dur, vel) debug_text_3d_fn(pos, msg, align, dur, vel)
ERASEABLE
-void debug_text_3d_fn(vector pos, string msg, float align, float duration, vector velocity) {
+void debug_text_3d_fn(vector pos, string msg, float align, float duration, vector vel) {
WriteHeader(MSG_BROADCAST, debug_text_3d);
WriteVector(MSG_BROADCAST, pos);
WriteString(MSG_BROADCAST, msg);
WriteFloat(MSG_BROADCAST, align);
WriteFloat(MSG_BROADCAST, duration);
- WriteVector(MSG_BROADCAST, velocity);
+ WriteVector(MSG_BROADCAST, vel);
}
#endif // SVQC
this.realowner.mage_spike = NULL;
Send_Effect(EFFECT_EXPLOSION_SMALL, this.origin, '0 0 0', 1);
- RadiusDamage (this, this.realowner, (autocvar_g_monster_mage_attack_spike_damage), (autocvar_g_monster_mage_attack_spike_damage) * 0.5, (autocvar_g_monster_mage_attack_spike_radius),
+ RadiusDamage (this, this.realowner, (autocvar_g_monster_mage_attack_spike_damage), (autocvar_g_monster_mage_attack_spike_damage) * 0.5, (autocvar_g_monster_mage_attack_spike_radius),
NULL, NULL, 0, DEATH_MONSTER_MAGE.m_id, DMG_NOWEP, directhitentity);
delete(this);
void M_Mage_Attack_Push(entity this)
{
sound(this, CH_SHOTS, SND_TAGEXP1, 1, ATTEN_NORM);
- RadiusDamage (this, this, (autocvar_g_monster_mage_attack_push_damage), (autocvar_g_monster_mage_attack_push_damage), (autocvar_g_monster_mage_attack_push_radius),
+ RadiusDamage (this, this, (autocvar_g_monster_mage_attack_push_damage), (autocvar_g_monster_mage_attack_push_damage), (autocvar_g_monster_mage_attack_push_radius),
NULL, NULL, (autocvar_g_monster_mage_attack_push_force), DEATH_MONSTER_MAGE.m_id, DMG_NOWEP, this.enemy);
Send_Effect(EFFECT_TE_EXPLOSION, this.origin, '0 0 0', 1);
entity own = this.realowner;
- RadiusDamage(this, own, autocvar_g_monster_wyvern_attack_fireball_damage, autocvar_g_monster_wyvern_attack_fireball_edgedamage, autocvar_g_monster_wyvern_attack_fireball_force,
+ RadiusDamage(this, own, autocvar_g_monster_wyvern_attack_fireball_damage, autocvar_g_monster_wyvern_attack_fireball_edgedamage, autocvar_g_monster_wyvern_attack_fireball_force,
NULL, NULL, autocvar_g_monster_wyvern_attack_fireball_radius, this.projectiledeathtype, DMG_NOWEP, NULL);
FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_monster_wyvern_attack_fireball_radius, it.takedamage == DAMAGE_AIM,
// generated file; do not modify
#include <common/mutators/mutator/instagib/items.qh>
+#ifdef SVQC
+ #include <common/mutators/mutator/instagib/sv_items.qh>
+#endif
#ifdef SVQC
#include <common/mutators/mutator/instagib/sv_instagib.qh>
#endif
+#include "sv_items.qh"
+
#include "items.qh"
/// \brief Time of ivisibility powerup in seconds.
--- /dev/null
+#pragma once
// generated file; do not modify
+#ifdef SVQC
+ #include <common/mutators/mutator/kick_teamkiller/sv_kick_teamkiller.qh>
+#endif
+#include "sv_kick_teamkiller.qh"
float autocvar_g_kick_teamkiller_rate;
float autocvar_g_kick_teamkiller_lower_limit;
// use the players actual playtime
float playtime = time - CS(attacker).startplaytime;
// rate is in teamkills/minutes, playtime in seconds
- if (teamkills >= autocvar_g_kick_teamkiller_lower_limit &&
+ if (teamkills >= autocvar_g_kick_teamkiller_lower_limit &&
teamkills >= autocvar_g_kick_teamkiller_rate*playtime/60.0)
{
Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_KICK_TEAMKILL, attacker.netname);
--- /dev/null
+#pragma once
// generated file; do not modify
+#ifdef SVQC
+ #include <common/mutators/mutator/offhand_blaster/sv_offhand_blaster.qh>
+#endif
+#include "sv_offhand_blaster.qh"
+
string autocvar_g_offhand_blaster = "0";
REGISTER_MUTATOR(offhand_blaster, expr_evaluate(autocvar_g_offhand_blaster));
--- /dev/null
+#pragma once
AUTOCVAR(g_pickup_respawntime_initial_random, int, 1,
"For items that don't start spawned: 0: spawn after their normal respawntime; 1: spawn after `random * respawntime` with the *same* random; 2: same as 1 but each item has separate random");
-float shared_random;
-STATIC_INIT(shared_random) { shared_random = random(); }
void Item_ScheduleInitialRespawn(entity e)
{
Item_Show(e, 0);
// range: respawntime .. respawntime + respawntimejitter
spawn_in = e.respawntime + random() * e.respawntimejitter;
}
- else if (autocvar_g_pickup_respawntime_initial_random == 1)
+ else
{
+ float rnd;
+ if (autocvar_g_pickup_respawntime_initial_random == 1)
+ {
+ static float shared_random = 0;
+ // NOTE this code works only if items are scheduled at the same time (normal case)
+ // NOTE2 random() can't return exactly 1 so this check always work as intended
+ if (!shared_random || floor(time) > shared_random)
+ shared_random = floor(time) + random();
+ rnd = shared_random - floor(time);
+ }
+ else
+ rnd = random();
+
// range:
// if respawntime >= ITEM_RESPAWN_TICKS: ITEM_RESPAWN_TICKS .. respawntime + respawntimejitter
// else: 0 .. ITEM_RESPAWN_TICKS
// this is to prevent powerups spawning unexpectedly without waypoints
- spawn_in = ITEM_RESPAWN_TICKS + shared_random * (e.respawntime + e.respawntimejitter - ITEM_RESPAWN_TICKS);
- }
- else
- {
- // range: same as 1
- spawn_in = ITEM_RESPAWN_TICKS + random() * (e.respawntime + e.respawntimejitter - ITEM_RESPAWN_TICKS);
+ spawn_in = ITEM_RESPAWN_TICKS + rnd * (e.respawntime + e.respawntimejitter - ITEM_RESPAWN_TICKS);
}
Item_ScheduleRespawnIn(e, max(0, game_starttime - time) + ((e.respawntimestart) ? e.respawntimestart : spawn_in));
if(a)
f *= a;
- float totaldamage = RadiusDamage(this, this.realowner, WEP_CVAR_BOTH(crylink, isprimary, damage) * f, WEP_CVAR_BOTH(crylink, isprimary, edgedamage) * f, WEP_CVAR_BOTH(crylink, isprimary, radius),
+ float totaldamage = RadiusDamage(this, this.realowner, WEP_CVAR_BOTH(crylink, isprimary, damage) * f, WEP_CVAR_BOTH(crylink, isprimary, edgedamage) * f, WEP_CVAR_BOTH(crylink, isprimary, radius),
NULL, NULL, WEP_CVAR_BOTH(crylink, isprimary, force) * f, this.projectiledeathtype, this.weaponentity_fld, toucher);
if(totaldamage && ((WEP_CVAR_BOTH(crylink, isprimary, linkexplode) == 2) || ((WEP_CVAR_BOTH(crylink, isprimary, linkexplode) == 1) && !W_Crylink_Touch_WouldHitFriendly(this, WEP_CVAR_BOTH(crylink, isprimary, radius)))))
isprimary = !(this.projectiledeathtype & HITTYPE_SECONDARY);
- RadiusDamage(this, this.realowner, WEP_CVAR_BOTH(hlac, isprimary, damage), WEP_CVAR_BOTH(hlac, isprimary, edgedamage), WEP_CVAR_BOTH(hlac, isprimary, radius),
+ RadiusDamage(this, this.realowner, WEP_CVAR_BOTH(hlac, isprimary, damage), WEP_CVAR_BOTH(hlac, isprimary, edgedamage), WEP_CVAR_BOTH(hlac, isprimary, radius),
NULL, NULL, WEP_CVAR_BOTH(hlac, isprimary, force), this.projectiledeathtype, this.weaponentity_fld, toucher);
delete(this);
if(this.move_movetype == MOVETYPE_NONE || this.move_movetype == MOVETYPE_FOLLOW)
this.velocity = this.mine_orientation; // particle fx and decals need .velocity
- RadiusDamage(this, this.realowner, WEP_CVAR(minelayer, remote_damage), WEP_CVAR(minelayer, remote_edgedamage), WEP_CVAR(minelayer, remote_radius),
+ RadiusDamage(this, this.realowner, WEP_CVAR(minelayer, remote_damage), WEP_CVAR(minelayer, remote_edgedamage), WEP_CVAR(minelayer, remote_radius),
NULL, NULL, WEP_CVAR(minelayer, remote_force), this.projectiledeathtype | HITTYPE_BOUNCE, this.weaponentity_fld, NULL);
.entity weaponentity = this.weaponentity_fld;
}
/// Maps values between the src and dest range: src_min to dest_min, src_max to dest_max, values between them
-/// to the curresponding values between and extrapolates for values outside the range.
+/// to the corresponding values between and extrapolates for values outside the range.
///
-/// src_min and src_max must not be the same or division by zero accurs.
+/// src_min and src_max must not be the same or division by zero occurs.
///
/// dest_max can be smaller than dest_min if you want the resulting range to be inverted, all values can be negative.
ERASEABLE
#define ATTRIB(...) EVAL_ATTRIB(OVERLOAD_(ATTRIB, __VA_ARGS__))
#define EVAL_ATTRIB(...) __VA_ARGS__
-#define ATTRIB_3(cname, name, type) INIT(cname) {} class(cname) .type name
+#define ATTRIB_3(cname, name, type) class(cname) .type name
#define ATTRIB_4(cname, name, type, val) \
ATTRIB_3(cname, name, type); \
INIT(cname) \
#include <common/mutators/base.qh>
+// register all possible hooks here
+
+// to use a hook, first register your mutator using REGISTER_MUTATOR
+// then create your function using MUTATOR_HOOKFUNCTION
+
// globals
string cmd_name;
diff = destorg - this.origin;
- if (fabs(diff.x) < 10 && fabs(diff.y) < 10
- && this.goalcurrent == this.goalentity && time < this.goalentity_lock_timeout)
+ // 1. stop if too close to target player (even if frozen)
+ // 2. stop if the locked goal has been reached
+ if ((IS_PLAYER(this.goalcurrent) && vdist(diff, <, 80))
+ || (this.goalcurrent == this.goalentity && time < this.goalentity_lock_timeout && vdist(diff, <, 10)))
{
destorg = this.origin;
- diff.x = 0;
- diff.y = 0;
+ diff = '0 0 0';
}
dir = normalize(diff);
- flatdir = diff;flatdir.z = 0;
- flatdir = normalize(flatdir);
+ flatdir = (diff.z == 0) ? dir : normalize(vec2(diff));
//if (this.bot_dodgevector_time < time)
{
if (trace_ent == this || tracewalk(this, this.origin, this.mins, this.maxs,
tracewalk_dest, tracewalk_dest_height, bot_navigation_movemode))
{
- LOG_DEBUG("path optimized for ", this.netname, ", removed a goal from the queue");
+ LOG_DEBUG("path optimized for ", this.netname, ", removed a goal from the queue");
navigation_poproute(this);
}
}
}
}
-float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe,
+float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe,
float inflictorselfdamage, float forceintensity, int deathtype, .entity weaponentity, entity directhitentity)
// Returns total damage applies to creatures
{
#include <common/mutators/base.qh>
// register all possible hooks here
+
+// to use a hook, first register your mutator using REGISTER_MUTATOR
+// then create your function using MUTATOR_HOOKFUNCTION
/** called when a player becomes observer, after shared setup */
#define EV_MakePlayerObserver(i, o) \
err=$?
set -e
if [ ${err} -ne 0 ]; then return ${err}; fi
- sed 's/^#\(line\)\? \([[:digit:]]\+\) "\(.*\)".*/\n#pragma file(\3)\n#pragma line(\2)/g' "${WORKDIR}/${MODE}.txt"
+ sed -E 's/^#(line)? ([[:digit:]]+) "(.*)".*/'$'\\\n''#pragma file(\3)'$'\\\n''#pragma line(\2)/g' "${WORKDIR}/${MODE}.txt"
}
function qcc() {