WriteVector(MSG_ENTITY, this.origin);
- WriteString(MSG_ENTITY, this.target);
- WriteString(MSG_ENTITY, this.target2);
- WriteString(MSG_ENTITY, this.target3);
- WriteString(MSG_ENTITY, this.target4);
- WriteString(MSG_ENTITY, this.targetname);
- WriteByte(MSG_ENTITY, this.target_random);
+ sf = 0;
+ sf = BITSET(sf, BIT(0), this.target_random);
+
+ sf = BITSET(sf, BIT(1), this.target && this.target != "");
+ sf = BITSET(sf, BIT(2), this.target2 && this.target2 != "");
+ sf = BITSET(sf, BIT(3), this.target3 && this.target3 != "");
+ sf = BITSET(sf, BIT(4), this.target4 && this.target4 != "");
+ sf = BITSET(sf, BIT(5), this.targetname && this.targetname != "");
+
+ WriteByte(MSG_ENTITY, sf);
+ if(sf & BIT(1))
+ WriteString(MSG_ENTITY, this.target);
+ if(sf & BIT(2))
+ WriteString(MSG_ENTITY, this.target2);
+ if(sf & BIT(3))
+ WriteString(MSG_ENTITY, this.target3);
+ if(sf & BIT(4))
+ WriteString(MSG_ENTITY, this.target4);
+ if(sf & BIT(5))
+ WriteString(MSG_ENTITY, this.targetname);
WriteByte(MSG_ENTITY, this.wait);
this.origin = ReadVector();
setorigin(this, this.origin);
- this.target = strzone(ReadString());
- this.target2 = strzone(ReadString());
- this.target3 = strzone(ReadString());
- this.target4 = strzone(ReadString());
- this.targetname = strzone(ReadString());
- this.target_random = ReadByte();
+ int targbits = ReadByte();
+ this.target_random = (targbits & BIT(0));
+
+ this.target = ((targbits & BIT(1)) ? strzone(ReadString()) : string_null);
+ this.target2 = ((targbits & BIT(2)) ? strzone(ReadString()) : string_null);
+ this.target3 = ((targbits & BIT(3)) ? strzone(ReadString()) : string_null);
+ this.target4 = ((targbits & BIT(4)) ? strzone(ReadString()) : string_null);
+ this.targetname = ((targbits & BIT(5)) ? strzone(ReadString()) : string_null);
this.wait = ReadByte();
void dynlight_find_aiment(entity this)
{
entity targ;
- if (!this.target)
+ if (!this.target || this.target == "")
objerror (this, "dynlight: no target to follow");
targ = find(NULL, targetname, this.target);
void dynlight_find_path(entity this)
{
entity targ;
- if (!this.target)
+ if (!this.target || this.target == "")
objerror (this, "dynlight: no target to follow");
targ = find(NULL, targetname, this.target);
void dynlight_find_target(entity this)
{
entity targ;
- if (!this.target)
+ if (!this.target || this.target == "")
objerror (this, "dynlight: no target to follow");
targ = find(NULL, targetname, this.target);
void Ent_TriggerMusic_Think(entity this)
{
- if(this.active == ACTIVE_NOT)
+ if(this.active == ACTIVE_NOT || intermission)
{
return;
}
void counter_use(entity this, entity actor, entity trigger)
{
entity store = this;
- if(this.spawnflags & COUNTER_PER_PLAYER)
+ if(this.spawnflags & COUNTER_PER_PLAYER) // FIXME: multiple counters in the map will not function correctly, and upon trigger reset the player won't be able to use it again!
{
if(!IS_PLAYER(actor))
return;
toucher.triggerhealtime = time + this.delay;
bool playthesound = (this.spawnflags & HEAL_SOUND_ALWAYS);
- bool healed = Heal(toucher, this, GetResource(this, RES_HEALTH), this.max_health);
+ bool healed = Heal(toucher, this, this.health, this.max_health);
if(playthesound || healed)
_sound (toucher, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
this.active = ACTIVE_ACTIVE;
if(!this.delay)
this.delay = 1;
- if(!GetResource(this, RES_HEALTH))
- SetResourceExplicit(this, RES_HEALTH, 10); // TODO: use a special field for this, it doesn't have actual health!
+ if(!this.health)
+ this.health = 10;
if(!this.max_health)
this.max_health = 200; // max health topoff for field
if(this.noise == "")
#include "magicear.qh"
#ifdef SVQC
-float magicear_matched;
-float W_Tuba_HasPlayed(entity pl, .entity weaponentity, string melody, float instrument, float ignorepitch, float mintempo, float maxtempo);
+#include <common/weapons/weapon/tuba.qh>
+bool magicear_matched;
string trigger_magicear_processmessage(entity ear, entity source, float teamsay, entity privatesay, string msgin)
{
float domatch, dotrigger, matchstart, l;
/*
* t_swamp.c
-* Adds spawnfunc_trigger_swamp and suppoart routines for xonotic 1.2.1+
+* Adds spawnfunc_trigger_swamp and support routines for nexuiz 1.2.1+ and xonotic
* Author tZork (Jakob MG)
* jakob@games43.se
* 2005 11 29
*/
-.float swamp_interval; //Hurt players in swamp with this interval
-.float swamp_slowdown; //Players in swamp get slowd down by this mutch 0-1 is slowdown 1-~ is speedup (!?)
-.float swamp_lifetime; // holds the points remaining until slug dies (not quite health!)
-.entity swampslug;
-
-#ifdef SVQC
-spawnfunc(trigger_swamp);
-#endif
-void swamp_touch(entity this, entity toucher);
-void swampslug_think(entity this);
-
/*
* Uses a entity calld swampslug to handle players in the swamp
//Slug dead? then remove curses.
if(GetResource(this, RES_HEALTH) <= 0)
{
- this.owner.in_swamp = 0;
+ if(this.owner.swampslug == this)
+ {
+ this.owner.in_swamp = false;
+ this.owner.swampslug = NULL;
+ }
delete(this);
//centerprint(this.owner,"Killing slug...\n");
return;
EXACTTRIGGER_TOUCH(this, toucher);
// Chech if player alredy got a swampslug.
- if(toucher.in_swamp != 1)
+ if(!toucher.in_swamp)
{
// If not attach one.
//centerprint(toucher,"Entering swamp!\n");
- toucher.swampslug = spawn();
+ if(!toucher.swampslug) // just incase
+ toucher.swampslug = spawn();
toucher.swampslug.swamp_lifetime = 2;
setthink(toucher.swampslug, swampslug_think);
toucher.swampslug.nextthink = time;
toucher.swampslug.dmg = this.dmg;
toucher.swampslug.swamp_interval = this.swamp_interval;
toucher.swamp_slowdown = this.swamp_slowdown;
- toucher.in_swamp = 1;
+ toucher.in_swamp = true;
return;
}
- //toucher.in_swamp = 1;
+ //toucher.in_swamp = true;
//Revitalize players swampslug
toucher.swampslug.swamp_lifetime = 2;
}
/*QUAKED spawnfunc_trigger_swamp (.5 .5 .5) ?
-Players gettin into the swamp will
-get slowd down and damaged
+Players in the swamp will be
+slowed down and damaged over time
*/
spawnfunc(trigger_swamp)
{
.float swamp_interval; //Hurt players in swamp with this interval
.float swamp_slowdown; //Players in swamp get slowd down by this mutch 0-1 is slowdown 1-~ is speedup (!?)
-.entity swampslug;
-.float in_swamp; // bool
+.bool in_swamp;
.entity swampslug; // Uses this to release from swamp ("untouch" fix)
+
+.float swamp_interval; //Hurt players in swamp with this interval
+.float swamp_slowdown; //Players in swamp get slowd down by this mutch 0-1 is slowdown 1-~ is speedup (!?)
+.float swamp_lifetime; // holds the points remaining until slug dies (not quite health!)
+
+#ifdef SVQC
+spawnfunc(trigger_swamp);
+#endif
+void swamp_touch(entity this, entity toucher);
+void swampslug_think(entity this);
LOG_WARNF("Missing model: \"%s\"", s);
return;
}
- profile(sprintf("precache_model(\"%s\")", s));
+ //profile(sprintf("precache_model(\"%s\")", s));
precache_model(s);
strcpy(this.model_str_, s);
}
if(trace_ent && IS_MONSTER(trace_ent))
reverse = true;
- // TODO: fix this... tracing is broken if the floor is thin
- /*
- if(!allow_jumpoff)
+ if(!allow_jumpoff && IS_ONGROUND(this))
{
- a = b - '0 0 32';
- traceline(b, a, MOVE_WORLDONLY, this);
+ traceline(b, b - '0 0 32', MOVE_NORMAL, this);
if(trace_fraction == 1.0)
reverse = true;
- } */
+ }
if(reverse)
{
e.noalign = this.noalign;
e.angles = this.angles;
e.monster_skill = this.monster_skill;
+ e.skin = this.skin;
e = spawnmonster(e, this.spawnmob, 0, this, this, this.origin, false, true, this.monster_moveflags);
}
TC(Sound, this);
string s = _Sound_fixpath(this.sound_str());
if (!s) return;
- profile(sprintf("precache_sound(\"%s\")", s));
+ //profile(sprintf("precache_sound(\"%s\")", s));
precache_sound(s);
strcpy(this.sound_str_, s);
}
#ifdef SVQC
-/**
- turret_checkpoint
-**/
-
-
-//.entity checkpoint_target;
-
-/*
-#define checkpoint_cache_who flagcarried
-#define checkpoint_cache_from lastrocket
-#define checkpoint_cache_to selected_player
-*/
-
-/*
-entity path_makeorcache(entity forwho,entity start, entity end)
-{
- entity pth;
-
- //pth = pathlib_makepath(forwho, start.origin,end.origin,PFL_GROUNDSNAP,500,1.5,PT_QUICKSTAR);
-
- return pth;
-}
-*/
-
-void turret_checkpoint_use()
-{
-}
-
-#if 0
-void turret_checkpoint_think(entity this)
-{
- if(this.enemy)
- te_lightning1(this,this.origin, this.enemy.origin);
-
- this.nextthink = time + 0.25;
-}
-#endif
/*QUAKED turret_checkpoint (1 0 1) (-32 -32 -32) (32 32 32)
-----------KEYS------------
target: .targetname of next waypoint in chain.
-----------SPAWNFLAGS-----------
---------NOTES----------
If a loop is of targets are formed, any unit entering this loop will patrol it indefinitly.
-If the checkpoint chain in not looped, the unit will go "Roaming" when the last point is reached.
+If the checkpoint chain is not looped, the unit will go "Roaming" when the last point is reached.
*/
-//float tc_acum;
void turret_checkpoint_init(entity this)
{
traceline(this.origin + '0 0 16', this.origin - '0 0 1024', MOVE_WORLDONLY, this);
setorigin(this, trace_endpos + '0 0 32');
- if(this.target != "")
+ if(this.target && this.target != "")
{
this.enemy = find(NULL, targetname, this.target);
- if(this.enemy == NULL)
- LOG_TRACE("A turret_checkpoint faild to find its target!");
+ if(!this.enemy)
+ LOG_TRACE("A turret_checkpoint failed to find its target!");
}
- //setthink(this, turret_checkpoint_think);
- //this.nextthink = time + tc_acum + 0.25;
- //tc_acum += 0.25;
}
spawnfunc(turret_checkpoint)
{
setorigin(this, this.origin);
- setthink(this, turret_checkpoint_init);
- this.nextthink = time + 0.2;
+ InitializeEntity(this, turret_checkpoint_init, INITPRIO_FINDTARGET);
}
// Compat.
classfield(Tuba) .float tuba_volume_initial;
classfield(Tuba) .int tuba_instrument;
#endif
+
+#ifdef SVQC
+bool W_Tuba_HasPlayed(entity pl, .entity weaponentity, string melody, int instrument, bool ignorepitch, float mintempo, float maxtempo);
+#endif
FIELD_SCALAR(fld, health) \
FIELD_SCALAR(fld, height) \
FIELD_SCALAR(fld, impulse) \
+ FIELD_SCALAR(fld, item_pickupsound) \
FIELD_SCALAR(fld, killtarget) \
FIELD_SCALAR(fld, lerpfrac) \
FIELD_SCALAR(fld, light_lev) \
FIELD_SCALAR(fld, lip) \
FIELD_SCALAR(fld, loddistance1) \
FIELD_SCALAR(fld, lodmodel1) \
+ FIELD_SCALAR(fld, lodmodel2) \
FIELD_SCALAR(fld, ltime) \
FIELD_SCALAR(fld, map) \
FIELD_SCALAR(fld, max_health) \
int autocvar_g_pickup_items;
float autocvar_g_player_alpha;
float autocvar_g_player_brightness;
+float autocvar_g_player_damageforcescale = 2;
bool autocvar_g_playerclip_collisions;
int autocvar_g_powerups;
int autocvar_g_projectiles_damage;
#include "havocbot.qh"
+#include "roles.qh"
+
#include <server/defs.qh>
#include <server/miscfunctions.qh>
#include "../cvars.qh"
#include <lib/warpzone/common.qh>
-.float speed;
-
void havocbot_ai(entity this)
{
if(this.draggedby)
void havocbot_keyboard_movement(entity this, vector destorg)
{
- vector keyboard;
+ if(time <= this.havocbot_keyboardtime)
+ return;
- if (time > this.havocbot_keyboardtime)
+ float sk = skill + this.bot_moveskill;
+ this.havocbot_keyboardtime =
+ max(
+ this.havocbot_keyboardtime
+ + 0.05 / max(1, sk + this.havocbot_keyboardskill)
+ + random() * 0.025 / max(0.00025, skill + this.havocbot_keyboardskill)
+ , time);
+ vector keyboard = CS(this).movement / autocvar_sv_maxspeed;
+
+ float trigger = autocvar_bot_ai_keyboard_threshold;
+
+ // categorize forward movement
+ // at skill < 1.5 only forward
+ // at skill < 2.5 only individual directions
+ // at skill < 4.5 only individual directions, and forward diagonals
+ // at skill >= 4.5, all cases allowed
+ if (keyboard.x > trigger)
{
- float sk = skill + this.bot_moveskill;
- this.havocbot_keyboardtime =
- max(
- this.havocbot_keyboardtime
- + 0.05 / max(1, sk + this.havocbot_keyboardskill)
- + random() * 0.025 / max(0.00025, skill + this.havocbot_keyboardskill)
- , time);
- keyboard = CS(this).movement / autocvar_sv_maxspeed;
-
- float trigger = autocvar_bot_ai_keyboard_threshold;
-
- // categorize forward movement
- // at skill < 1.5 only forward
- // at skill < 2.5 only individual directions
- // at skill < 4.5 only individual directions, and forward diagonals
- // at skill >= 4.5, all cases allowed
- if (keyboard.x > trigger)
- {
- keyboard.x = 1;
- if (sk < 2.5)
- keyboard.y = 0;
- }
- else if (keyboard.x < -trigger && sk > 1.5)
- {
- keyboard.x = -1;
- if (sk < 4.5)
- keyboard.y = 0;
- }
- else
- {
- keyboard.x = 0;
- if (sk < 1.5)
- keyboard.y = 0;
- }
+ keyboard.x = 1;
+ if (sk < 2.5)
+ keyboard.y = 0;
+ }
+ else if (keyboard.x < -trigger && sk > 1.5)
+ {
+ keyboard.x = -1;
if (sk < 4.5)
- keyboard.z = 0;
-
- if (keyboard.y > trigger)
- keyboard.y = 1;
- else if (keyboard.y < -trigger)
- keyboard.y = -1;
- else
keyboard.y = 0;
+ }
+ else
+ {
+ keyboard.x = 0;
+ if (sk < 1.5)
+ keyboard.y = 0;
+ }
+ if (sk < 4.5)
+ keyboard.z = 0;
- if (keyboard.z > trigger)
- keyboard.z = 1;
- else if (keyboard.z < -trigger)
- keyboard.z = -1;
- else
- keyboard.z = 0;
+ if (keyboard.y > trigger)
+ keyboard.y = 1;
+ else if (keyboard.y < -trigger)
+ keyboard.y = -1;
+ else
+ keyboard.y = 0;
- // make sure bots don't get stuck if havocbot_keyboardtime is very high
- if (keyboard == '0 0 0')
- this.havocbot_keyboardtime = min(this.havocbot_keyboardtime, time + 0.2);
+ if (keyboard.z > trigger)
+ keyboard.z = 1;
+ else if (keyboard.z < -trigger)
+ keyboard.z = -1;
+ else
+ keyboard.z = 0;
- this.havocbot_keyboard = keyboard * autocvar_sv_maxspeed;
- if (this.havocbot_ducktime > time)
- PHYS_INPUT_BUTTON_CROUCH(this) = true;
+ // make sure bots don't get stuck if havocbot_keyboardtime is very high
+ if (keyboard == '0 0 0')
+ this.havocbot_keyboardtime = min(this.havocbot_keyboardtime, time + 0.2);
- keyboard = this.havocbot_keyboard;
- float blend = bound(0, vlen(destorg - this.origin) / autocvar_bot_ai_keyboard_distance, 1); // When getting close move with 360 degree
- //dprint("movement ", vtos(CS(this).movement), " keyboard ", vtos(keyboard), " blend ", ftos(blend), "\n");
- CS(this).movement = CS(this).movement + (keyboard - CS(this).movement) * blend;
- }
+ this.havocbot_keyboard = keyboard * autocvar_sv_maxspeed;
+ if (this.havocbot_ducktime > time)
+ PHYS_INPUT_BUTTON_CROUCH(this) = true;
+
+ keyboard = this.havocbot_keyboard;
+ float blend = bound(0, vlen(destorg - this.origin) / autocvar_bot_ai_keyboard_distance, 1); // When getting close move with 360 degree
+ //dprint("movement ", vtos(CS(this).movement), " keyboard ", vtos(keyboard), " blend ", ftos(blend), "\n");
+ CS(this).movement = CS(this).movement + (keyboard - CS(this).movement) * blend;
}
void havocbot_bunnyhop(entity this, vector dir)
{
- float bunnyhopdistance;
- vector deviation;
- float maxspeed;
-
// Don't jump when attacking
if(this.aistatus & AI_STATUS_ATTACKING)
return;
if(IS_PLAYER(this.goalcurrent))
return;
- maxspeed = autocvar_sv_maxspeed;
-
- if(this.aistatus & AI_STATUS_RUNNING && vdist(this.velocity, <, autocvar_sv_maxspeed * 0.75)
- || this.aistatus & AI_STATUS_DANGER_AHEAD)
+ if((this.aistatus & AI_STATUS_RUNNING) && vdist(this.velocity, <, autocvar_sv_maxspeed * 0.75)
+ || (this.aistatus & AI_STATUS_DANGER_AHEAD))
{
this.aistatus &= ~AI_STATUS_RUNNING;
PHYS_INPUT_BUTTON_JUMP(this) = false;
}
vector gco = get_closer_dest(this.goalcurrent, this.origin);
- bunnyhopdistance = vlen(this.origin - gco);
// Run only to visible goals
if(IS_ONGROUND(this))
- if(vdist(vec2(this.velocity), >=, autocvar_sv_maxspeed)) // if -really- running
+ if(vdist(vec2(this.velocity), >=, autocvar_sv_maxspeed))
if(checkpvs(this.origin + this.view_ofs, this.goalcurrent))
{
- this.bot_lastseengoal = this.goalcurrent;
+ this.bot_lastseengoal = this.goalcurrent;
- // seen it before
- if(this.bot_timelastseengoal)
+ // seen it before
+ if(this.bot_timelastseengoal)
+ {
+ // for a period of time
+ if(time - this.bot_timelastseengoal > autocvar_bot_ai_bunnyhop_firstjumpdelay)
{
- // for a period of time
- if(time - this.bot_timelastseengoal > autocvar_bot_ai_bunnyhop_firstjumpdelay)
- {
- float checkdistance;
- checkdistance = true;
+ bool checkdistance = true;
- // don't run if it is too close
- if(this.bot_canruntogoal==0)
- {
- if(bunnyhopdistance > autocvar_bot_ai_bunnyhop_startdistance)
- this.bot_canruntogoal = 1;
- else
- this.bot_canruntogoal = -1;
- }
+ // don't run if it is too close
+ if(this.bot_canruntogoal==0)
+ {
+ if(vdist(this.origin - gco, >, autocvar_bot_ai_bunnyhop_startdistance))
+ this.bot_canruntogoal = 1;
+ else
+ this.bot_canruntogoal = -1;
+ }
- if(this.bot_canruntogoal != 1)
- return;
+ if(this.bot_canruntogoal != 1)
+ return;
- if(this.aistatus & AI_STATUS_ROAMING)
- if(this.goalcurrent.classname=="waypoint")
- if (!(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL))
- if(fabs(gco.z - this.origin.z) < this.maxs.z - this.mins.z)
- if(this.goalstack01 && !wasfreed(this.goalstack01))
+ if(this.aistatus & AI_STATUS_ROAMING)
+ if(this.goalcurrent.classname == "waypoint")
+ if(!(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL))
+ if(fabs(gco.z - this.origin.z) < this.maxs.z - this.mins.z)
+ if(this.goalstack01 && !wasfreed(this.goalstack01))
+ {
+ vector gno = (this.goalstack01.absmin + this.goalstack01.absmax) * 0.5;
+ vector deviation = vectoangles(gno - this.origin) - vectoangles(gco - this.origin);
+ while (deviation.y < -180) deviation.y = deviation.y + 360;
+ while (deviation.y > 180) deviation.y = deviation.y - 360;
+
+ if(fabs(deviation.y) < 20)
+ if(vlen2(this.origin - gco) < vlen2(this.origin - gno))
+ if(fabs(gno.z - gco.z) < this.maxs.z - this.mins.z)
{
- vector gno = (this.goalstack01.absmin + this.goalstack01.absmax) * 0.5;
- deviation = vectoangles(gno - this.origin) - vectoangles(gco - this.origin);
- while (deviation.y < -180) deviation.y = deviation.y + 360;
- while (deviation.y > 180) deviation.y = deviation.y - 360;
-
- if(fabs(deviation.y) < 20)
- if(bunnyhopdistance < vlen(this.origin - gno))
- if(fabs(gno.z - gco.z) < this.maxs.z - this.mins.z)
+ if(vdist(gco - gno, >, autocvar_bot_ai_bunnyhop_startdistance))
+ if(checkpvs(this.origin + this.view_ofs, this.goalstack01))
{
- if(vdist(gco - gno, >, autocvar_bot_ai_bunnyhop_startdistance))
- if(checkpvs(this.origin + this.view_ofs, this.goalstack01))
- {
- checkdistance = false;
- }
+ checkdistance = false;
}
}
+ }
- if(checkdistance)
- {
- this.aistatus &= ~AI_STATUS_RUNNING;
- // increase stop distance in case the goal is on a slope or a lower platform
- if(bunnyhopdistance > autocvar_bot_ai_bunnyhop_stopdistance + (this.origin.z - gco.z))
- PHYS_INPUT_BUTTON_JUMP(this) = true;
- }
- else
- {
- this.aistatus |= AI_STATUS_RUNNING;
+ if(checkdistance)
+ {
+ this.aistatus &= ~AI_STATUS_RUNNING;
+ // increase stop distance in case the goal is on a slope or a lower platform
+ if(vdist(this.origin - gco, >, autocvar_bot_ai_bunnyhop_stopdistance + (this.origin.z - gco.z)))
PHYS_INPUT_BUTTON_JUMP(this) = true;
- }
+ }
+ else
+ {
+ this.aistatus |= AI_STATUS_RUNNING;
+ PHYS_INPUT_BUTTON_JUMP(this) = true;
}
}
- else
- {
- this.bot_timelastseengoal = time;
- }
+ }
+ else
+ {
+ this.bot_timelastseengoal = time;
+ }
}
else
{
this.bot_timelastseengoal = 0;
}
-
-#if 0
- // Release jump button
- if(!cvar("sv_pogostick"))
- if((IS_ONGROUND(this)) == 0)
- {
- if(this.velocity.z < 0 || vlen(this.velocity)<maxspeed)
- PHYS_INPUT_BUTTON_JUMP(this) = false;
-
- // Strafe
- if(this.aistatus & AI_STATUS_RUNNING)
- if(vlen(this.velocity)>maxspeed)
- {
- deviation = vectoangles(dir) - vectoangles(this.velocity);
- while (deviation.y < -180) deviation.y = deviation.y + 360;
- while (deviation.y > 180) deviation.y = deviation.y - 360;
-
- if(fabs(deviation.y)>10)
- CS(this).movement_x = 0;
-
- if(deviation.y>10)
- CS(this).movement_y = maxspeed * -1;
- else if(deviation.y<10)
- CS(this).movement_y = maxspeed;
-
- }
- }
-#endif
}
// return true when bot isn't getting closer to the current goal
vector havocbot_dodge(entity this);
-.void(entity this) havocbot_role;
-.void(entity this) havocbot_previous_role;
-
void(entity this, float ratingscale, vector org, float sradius) havocbot_goalrating_items;
void(entity this, float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
#include "../bot.qh"
#include "../navigation.qh"
-.float bot_ratingscale;
-.float bot_ratingscale_time;
-.float max_armorvalue;
-.float havocbot_role_timeout;
-
-.void(entity this) havocbot_previous_role;
-.void(entity this) havocbot_role;
-
void havocbot_goalrating_waypoints(entity this, float ratingscale, vector org, float sradius)
{
// rate waypoints only if there's no alternative goal
if(!teamplay)
return true;
- // actually these variables hold the squared distances in order to optimize code
- float friend_distance = FLOAT_MAX;
- float enemy_distance = FLOAT_MAX;
- float dist;
+ // these variables hold squared distances in order to optimize code
+ float friend_dist2 = FLOAT_MAX;
+ float enemy_dist2 = FLOAT_MAX;
+ float dist2;
FOREACH_CLIENT(IS_PLAYER(it) && it != this && !(IS_DEAD(it) || STAT(FROZEN, it)),
{
if (!IS_REAL_CLIENT(it))
continue;
- dist = vlen2(it.origin - item_org);
- if(dist > friend_distance)
+ dist2 = vlen2(it.origin - item_org);
+ if (dist2 > friend_dist2)
continue;
if(havocbot_goalrating_item_can_be_left_to_teammate(this, it, item))
{
- friend_distance = dist;
+ friend_dist2 = dist2;
continue;
}
}
{
// If enemy only track distances
// TODO: track only if visible ?
- dist = vlen2(it.origin - item_org);
- if(dist < enemy_distance)
- enemy_distance = dist;
+ dist2 = vlen2(it.origin - item_org);
+ if (dist2 < enemy_dist2)
+ enemy_dist2 = dist2;
}
});
// Rate the item only if no one needs it, or if an enemy is closer to it
- dist = vlen2(item_org - org);
- if ((enemy_distance < friend_distance && dist < enemy_distance) ||
- (friend_distance > autocvar_bot_ai_friends_aware_pickup_radius ** 2) ||
- (dist < friend_distance && dist < 200 ** 2))
+ dist2 = vlen2(item_org - org);
+ if ((enemy_dist2 < friend_dist2 && dist2 < enemy_dist2)
+ || (friend_dist2 > autocvar_bot_ai_friends_aware_pickup_radius ** 2)
+ || (dist2 < friend_dist2 && dist2 < 200 ** 2))
return true;
return false;
};
void havocbot_goalrating_items(entity this, float ratingscale, vector org, float sradius)
{
- float rating;
- vector o;
ratingscale = ratingscale * 0.0001;
IL_EACH(g_items, it.bot_pickup,
it.bot_pickup_respawning = true;
}
- o = (it.absmin + it.absmax) * 0.5;
+ vector o = (it.absmin + it.absmax) * 0.5;
if(vdist(o - org, >, sradius) || (it == this.ignoregoal && time < this.ignoregoaltime) )
continue;
it.bot_ratingscale_time = time;
it.bot_ratingscale = ratingscale;
- rating = it.bot_pickupevalfunc(this, it);
+ float rating = it.bot_pickupevalfunc(this, it);
if(rating > 0)
navigation_routerating(this, it, rating * ratingscale, 2000);
});
}
-#define BOT_RATING_ENEMY 2500
void havocbot_goalrating_enemyplayers(entity this, float ratingscale, vector org, float sradius)
{
if (autocvar_bot_nofire)
return;
// don't chase players if we're under water
- if(this.waterlevel>WATERLEVEL_WETFEET)
+ if(this.waterlevel > WATERLEVEL_WETFEET)
return;
ratingscale = ratingscale * 0.0001;
- float t;
FOREACH_CLIENT(IS_PLAYER(it) && bot_shouldattack(this, it), {
// TODO: Merge this logic with the bot_shouldattack function
if(vdist(it.origin - org, <, 100) || vdist(it.origin - org, >, sradius))
continue;
*/
- t = ((GetResource(this, RES_HEALTH) + GetResource(this, RES_ARMOR)) - (GetResource(it, RES_HEALTH) + GetResource(it, RES_ARMOR))) / 150;
+ float t = ((GetResource(this, RES_HEALTH) + GetResource(this, RES_ARMOR)) - (GetResource(it, RES_HEALTH) + GetResource(it, RES_ARMOR))) / 150;
t = bound(0, 1 + t, 3);
if (skill > 3)
{
#pragma once
+
+const float BOT_RATING_ENEMY = 2500;
+
+.float bot_ratingscale;
+.float bot_ratingscale_time;
+.float havocbot_role_timeout;
+
+.void(entity this) havocbot_previous_role;
+.void(entity this) havocbot_role;
#include "../common/mapobjects/teleporters.qh"
#include "../common/mapobjects/target/spawnpoint.qh"
#include <common/mapobjects/trigger/counter.qh>
+#include <common/mapobjects/trigger/swamp.qh>
#include "../common/vehicles/all.qh"
this.pauseregen_finished += f;
}
- this.damageforcescale = 2;
+ this.damageforcescale = autocvar_g_player_damageforcescale;
this.death_time = 0;
this.respawn_flags = 0;
this.respawn_time = 0;
if(this.conveyor)
IL_REMOVE(g_conveyed, this);
this.conveyor = NULL; // prevent conveyors at the previous location from moving a freshly spawned player
+ if(this.swampslug)
+ delete(this.swampslug);
+ this.in_swamp = false;
STAT(HUD, this) = HUD_NORMAL;
this.event_damage = PlayerDamage;
bool radar_showennemies;
-#ifdef PROFILING
-float client_cefc_accumulator;
-float client_cefc_accumulatortime;
-#endif
-
.float weapon_load[Weapons_MAX];
.int ammo_none; // used by the reloading system, must always be 0
.int clip_load;
#include "../lib/warpzone/common.qh"
#include "../lib/warpzone/server.qh"
-.int state;
-
/*============================================
Wazat's Xonotic Grappling Hook
============================================*/
-.float hook_length;
-
void RemoveGrapplingHooks(entity pl)
{
if(pl.move_movetype == MOVETYPE_FLY)
// (note: you can change the hook impulse #'s to whatever you please)
.float hook_time;
+.float hook_length;
+
const float HOOK_FIRING = BIT(0);
const float HOOK_REMOVING = BIT(1);
const float HOOK_PULLING = BIT(2);
const float HOOK_RELEASING = BIT(3);
const float HOOK_WAITING_FOR_RELEASE = BIT(4);
.float hook_state;
+.int state;
void GrappleHookInit();
vector hook_shotorigin[4];
+
continue;
if(argv(0) == "cd")
{
+ string trackname = argv(2);
LOG_INFO("Found ^1UNSUPPORTED^7 cd loop command in .cfg file; put this line in mapinfo instead:");
- LOG_INFO(" cdtrack ", argv(2));
+ LOG_INFO(" cdtrack ", trackname);
+ if (cvar_value_issafe(trackname))
+ {
+ string newstuff = strcat(clientstuff, "cd loop \"", trackname, "\"\n");
+ strcpy(clientstuff, newstuff);
+ }
}
else if(argv(0) == "fog")
{
string Map_Current_Name;
// NOTE: this now expects the map list to be already tokenized and the count in Map_Count
-float GetMaplistPosition()
+int GetMaplistPosition()
{
- float pos, idx;
- string map;
-
- map = GetMapname();
- idx = autocvar_g_maplist_index;
+ string map = GetMapname();
+ int idx = autocvar_g_maplist_index;
if(idx >= 0)
+ {
if(idx < Map_Count)
+ {
if(map == argv(idx))
+ {
return idx;
+ }
+ }
+ }
- for(pos = 0; pos < Map_Count; ++pos)
+ for(int pos = 0; pos < Map_Count; ++pos)
+ {
if(map == argv(pos))
return pos;
+ }
// resume normal maplist rotation if current map is not in g_maplist
return idx;
string GetNextMap()
{
- float nextMap;
-
Maplist_Init();
- nextMap = -1;
+ float nextMap = -1;
if(nextMap == -1)
if(autocvar_g_maplist_shuffle > 0)
return;
alreadychangedlevel = true;
- string nextMap;
-
- nextMap = GetNextMap();
+ string nextMap = GetNextMap();
if(nextMap == "")
error("Everything is broken - cannot find a next map. Please report this to the developers.");
Map_Goto(reinit);
allow_mutatorblocked = M_ARGV(3, bool);
if(allguns)
- d = boolean(weaponinfo.spawnflags & WEP_FLAG_NORMAL);
+ d = boolean((weaponinfo.spawnflags & WEP_FLAG_NORMAL) && !(weaponinfo.spawnflags & WEP_FLAG_HIDDEN));
else if(!mutator_returnvalue)
d = !(!weaponinfo.weaponstart);
#include "../lib/warpzone/common.qh"
#include "../lib/warpzone/server.qh"
-.float lastground;
-.int state;
-
void CreatureFrame_hotliquids(entity this)
{
- if (this.dmgtime < time)
+ if (this.dmgtime > time)
{
- this.dmgtime = time + autocvar_g_balance_contents_damagerate;
+ return;
+ }
- if (this.flags & FL_PROJECTILE)
- {
- if (this.watertype == CONTENT_LAVA)
- Damage (this, NULL, NULL, autocvar_g_balance_contents_projectiledamage * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_LAVA.m_id, DMG_NOWEP, this.origin, '0 0 0');
- else if (this.watertype == CONTENT_SLIME)
- Damage (this, NULL, NULL, autocvar_g_balance_contents_projectiledamage * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_SLIME.m_id, DMG_NOWEP, this.origin, '0 0 0');
- }
- else
+ this.dmgtime = time + autocvar_g_balance_contents_damagerate;
+
+ if (this.flags & FL_PROJECTILE)
+ {
+ if (this.watertype == CONTENT_LAVA)
+ Damage (this, NULL, NULL, autocvar_g_balance_contents_projectiledamage * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_LAVA.m_id, DMG_NOWEP, this.origin, '0 0 0');
+ else if (this.watertype == CONTENT_SLIME)
+ Damage (this, NULL, NULL, autocvar_g_balance_contents_projectiledamage * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_SLIME.m_id, DMG_NOWEP, this.origin, '0 0 0');
+ }
+ else
+ {
+ if (this.watertype == CONTENT_LAVA)
{
- if (this.watertype == CONTENT_LAVA)
+ if (this.watersound_finished < time)
{
- if (this.watersound_finished < time)
- {
- this.watersound_finished = time + 0.5;
- sound (this, CH_PLAYER_SINGLE, SND_LAVA, VOL_BASE, ATTEN_NORM);
- }
- Damage (this, NULL, NULL, autocvar_g_balance_contents_playerdamage_lava * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_LAVA.m_id, DMG_NOWEP, this.origin, '0 0 0');
- if(autocvar_g_balance_contents_playerdamage_lava_burn)
- Fire_AddDamage(this, NULL, autocvar_g_balance_contents_playerdamage_lava_burn * this.waterlevel, autocvar_g_balance_contents_playerdamage_lava_burn_time * this.waterlevel, DEATH_LAVA.m_id);
+ this.watersound_finished = time + 0.5;
+ sound (this, CH_PLAYER_SINGLE, SND_LAVA, VOL_BASE, ATTEN_NORM);
}
- else if (this.watertype == CONTENT_SLIME)
+ Damage (this, NULL, NULL, autocvar_g_balance_contents_playerdamage_lava * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_LAVA.m_id, DMG_NOWEP, this.origin, '0 0 0');
+ if(autocvar_g_balance_contents_playerdamage_lava_burn)
+ Fire_AddDamage(this, NULL, autocvar_g_balance_contents_playerdamage_lava_burn * this.waterlevel, autocvar_g_balance_contents_playerdamage_lava_burn_time * this.waterlevel, DEATH_LAVA.m_id);
+ }
+ else if (this.watertype == CONTENT_SLIME)
+ {
+ if (this.watersound_finished < time)
{
- if (this.watersound_finished < time)
- {
- this.watersound_finished = time + 0.5;
- sound (this, CH_PLAYER_SINGLE, SND_SLIME, VOL_BASE, ATTEN_NORM);
- }
- Damage (this, NULL, NULL, autocvar_g_balance_contents_playerdamage_slime * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_SLIME.m_id, DMG_NOWEP, this.origin, '0 0 0');
+ this.watersound_finished = time + 0.5;
+ sound (this, CH_PLAYER_SINGLE, SND_SLIME, VOL_BASE, ATTEN_NORM);
}
+ Damage (this, NULL, NULL, autocvar_g_balance_contents_playerdamage_slime * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_SLIME.m_id, DMG_NOWEP, this.origin, '0 0 0');
}
}
}
void CreatureFrame_FallDamage(entity this)
{
- if(!IS_VEHICLE(this) && !(this.flags & FL_PROJECTILE)) // vehicles don't get falling damage
- if(this.velocity || this.oldvelocity) // moving or has moved
+ if(IS_VEHICLE(this) || (this.flags & FL_PROJECTILE))
+ return; // vehicles and projectiles don't receive fall damage
+ if(!(this.velocity || this.oldvelocity))
+ return; // if the entity hasn't moved and isn't moving, then don't do anything
+
+ // check for falling damage
+ float velocity_len = vlen(this.velocity);
+ bool have_hook = false;
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{
- // check for falling damage
- float velocity_len = vlen(this.velocity);
- bool have_hook = false;
- for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ .entity weaponentity = weaponentities[slot];
+ if(this.(weaponentity).hook && this.(weaponentity).hook.state)
{
- .entity weaponentity = weaponentities[slot];
- if(this.(weaponentity).hook && this.(weaponentity).hook.state)
- {
- have_hook = true;
- break;
- }
+ have_hook = true;
+ break;
}
- if(!have_hook)
- {
- float dm = vlen(this.oldvelocity) - velocity_len; // dm is now the velocity DECREASE. Velocity INCREASE should never cause a sound or any damage.
- if (IS_DEAD(this))
- dm = (dm - autocvar_g_balance_falldamage_deadminspeed) * autocvar_g_balance_falldamage_factor;
- else
- dm = min((dm - autocvar_g_balance_falldamage_minspeed) * autocvar_g_balance_falldamage_factor, autocvar_g_balance_falldamage_maxdamage);
- if (dm > 0)
- Damage (this, NULL, NULL, dm, DEATH_FALL.m_id, DMG_NOWEP, this.origin, '0 0 0');
- }
-
- if(autocvar_g_maxspeed > 0 && velocity_len > autocvar_g_maxspeed)
- Damage (this, NULL, NULL, 100000, DEATH_SHOOTING_STAR.m_id, DMG_NOWEP, this.origin, '0 0 0');
}
+ if(!have_hook)
+ {
+ float dm = vlen(this.oldvelocity) - velocity_len; // dm is now the velocity DECREASE. Velocity INCREASE should never cause a sound or any damage.
+ if (IS_DEAD(this))
+ dm = (dm - autocvar_g_balance_falldamage_deadminspeed) * autocvar_g_balance_falldamage_factor;
+ else
+ dm = min((dm - autocvar_g_balance_falldamage_minspeed) * autocvar_g_balance_falldamage_factor, autocvar_g_balance_falldamage_maxdamage);
+ if (dm > 0)
+ Damage (this, NULL, NULL, dm, DEATH_FALL.m_id, DMG_NOWEP, this.origin, '0 0 0');
+ }
+
+ if(autocvar_g_maxspeed > 0 && velocity_len > autocvar_g_maxspeed)
+ Damage (this, NULL, NULL, 100000, DEATH_SHOOTING_STAR.m_id, DMG_NOWEP, this.origin, '0 0 0');
}
void CreatureFrame_All()
bool expr_evaluate(string s);
+#ifdef PROFILING
+float client_cefc_accumulator;
+float client_cefc_accumulatortime;
+#endif
+
/*
==================
main
set g_cloaked 0 "display all players mostly invisible"
set g_player_alpha 1 "default opacity of players"
set g_player_brightness 0 "set to 2 for brighter players"
+set g_player_damageforcescale 2 "push multiplier of attacks against players"
set g_balance_cloaked_alpha 0.25 "opacity of cloaked players"
set g_playerclip_collisions 1 "0 = disable collision testing against playerclips, might be useful on some defrag maps"