-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include <lib/warpzone/common.qh>
- #include "../constants.qh"
- #include "../teams.qh"
- #include "../util.qh"
- #include "all.qh"
- #include "sv_monsters.qh"
- #include "../physics/movelib.qh"
- #include "../weapons/all.qh"
- #include <server/autocvars.qh>
- #include <server/defs.qh>
- #include "../deathtypes/all.qh"
- #include <server/mutators/all.qh>
- #include <server/steerlib.qh>
- #include "../turrets/sv_turrets.qh"
- #include "../turrets/util.qh"
- #include "../vehicles/all.qh"
- #include <server/campaign.qh>
- #include <server/command/common.qh>
- #include <server/command/cmd.qh>
- #include "../triggers/triggers.qh"
- #include <lib/csqcmodel/sv_model.qh>
- #include <server/round_handler.qh>
-#endif
+#include "sv_monsters.qh"
+
+#include <server/g_subs.qh>
+#include <lib/warpzone/common.qh>
+#include "../constants.qh"
+#include "../teams.qh"
+#include "../util.qh"
+#include "all.qh"
+#include "../physics/movelib.qh"
+#include "../weapons/_mod.qh"
+#include <server/autocvars.qh>
+#include <server/defs.qh>
+#include "../deathtypes/all.qh"
+#include <server/mutators/_mod.qh>
+#include <server/steerlib.qh>
+#include "../turrets/sv_turrets.qh"
+#include "../turrets/util.qh"
+#include "../vehicles/all.qh"
+#include <server/campaign.qh>
+#include <server/command/_mod.qh>
+#include "../triggers/triggers.qh"
+#include <lib/csqcmodel/sv_model.qh>
+#include <server/round_handler.qh>
+#include <server/weapons/_mod.qh>
void monsters_setstatus(entity this)
{
|| (SAME_TEAM(targ, this))
|| (STAT(FROZEN, targ))
|| (targ.alpha != 0 && targ.alpha < 0.5)
+ || (MUTATOR_CALLHOOK(MonsterValidTarget, this, targ))
)
{
// if any of the above checks fail, target is not valid
return false;
}
- traceline(this.origin + this.view_ofs, targ.origin, 0, this);
+ traceline(this.origin + this.view_ofs, targ.origin, MOVE_NOMONSTERS, this);
- if((trace_fraction < 1) && (trace_ent != targ))
- return false;
+ if(trace_fraction < 1)
+ return false; // solid
if(autocvar_g_monsters_target_infront || (this.spawnflags & MONSTERFLAG_INFRONT))
if(this.enemy != targ)
{
if(tokenize_console(s) != 3)
{
- LOG_TRACE("Invalid sound info line: ", s, "\n");
+ LOG_TRACE("Invalid sound info line: ", s);
continue;
}
PrecacheGlobalSound(strcat(argv(1), " ", argv(2)));
fh = fopen(f, FILE_READ);
if(fh < 0)
{
- LOG_TRACE("Monster sound file not found: ", f, "\n");
+ LOG_TRACE("Monster sound file not found: ", f);
return false;
}
while((s = fgets(fh)))
return true;
}
-void Monster_Attack_Check(entity this, entity targ)
+void Monster_Attack_Check(entity this, entity targ, .entity weaponentity)
{
+ int slot = weaponslot(weaponentity);
+
if((this == NULL || targ == NULL)
|| (!this.monster_attackfunc)
- || (time < this.attack_finished_single[0])
+ || (time < this.attack_finished_single[slot])
) { return; }
if(vdist(targ.origin - this.origin, <=, this.attack_range))
{
- bool attack_success = this.monster_attackfunc(MONSTER_ATTACK_MELEE, this, targ);
+ bool attack_success = this.monster_attackfunc(MONSTER_ATTACK_MELEE, this, targ, weaponentity);
if(attack_success == 1)
Monster_Sound(this, monstersound_melee, 0, false, CH_VOICE);
else if(attack_success > 0)
if(vdist(targ.origin - this.origin, >, this.attack_range))
{
- float attack_success = this.monster_attackfunc(MONSTER_ATTACK_RANGED, this, targ);
+ float attack_success = this.monster_attackfunc(MONSTER_ATTACK_RANGED, this, targ, weaponentity);
if(attack_success == 1)
Monster_Sound(this, monstersound_melee, 0, false, CH_VOICE);
else if(attack_success > 0)
void Monster_Respawn(entity this) { Monster_Spawn(this, this.monsterid); }
+.vector pos1, pos2;
+
void Monster_Dead_Fade(entity this)
{
if(Monster_Respawn_Check(this))
if(Monster_ValidTarget(this, actor)) { this.enemy = actor; }
}
+.float pass_distance;
vector Monster_Move_Target(entity this, entity targ)
{
// enemy is always preferred target
}
.entity draggedby;
+.entity target2;
void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed)
{
- if(this.target2) { this.goalentity = find(NULL, targetname, this.target2); }
+ // update goal entity if lost
+ if(this.target2 && this.goalentity.targetname != this.target2) { this.goalentity = find(NULL, targetname, this.target2); }
- entity targ;
+ entity targ = this.goalentity;
if(STAT(FROZEN, this) == 2)
{
}
}
- targ = this.goalentity;
-
if (MUTATOR_CALLHOOK(MonsterMove, this, runspeed, walkspeed, targ)
|| gameover
|| this.draggedby != NULL
}
else
{
- entity e = find(NULL, targetname, this.target2);
+ entity e = this.goalentity; //find(NULL, targetname, this.target2);
if(e.target2)
this.target2 = e.target2;
- else if(e.target)
+ else if(e.target) // compatibility
this.target2 = e.target;
movelib_brake_simple(this, stpspeed);
this.angles_y += turny;
}
- Monster_Attack_Check(this, this.enemy);
+ .entity weaponentity = weaponentities[0]; // TODO?
+ Monster_Attack_Check(this, this.enemy, weaponentity);
}
void Monster_Remove(entity this)
if(IS_CLIENT(this))
return; // don't remove it?
- .entity weaponentity = weaponentities[0];
if(!this) { return; }
if(!MUTATOR_CALLHOOK(MonsterRemove, this))
Send_Effect(EFFECT_ITEM_PICKUP, this.origin, '0 0 0', 1);
- if(this.(weaponentity)) { delete(this.(weaponentity)); }
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ if(this.(weaponentity))
+ delete(this.(weaponentity));
+ }
if(this.iceblock) { delete(this.iceblock); }
WaypointSprite_Kill(this.sprite);
delete(this);
mon.mr_death(mon, this);
if(this.candrop && this.weapon)
- W_ThrowNewWeapon(this, this.weapon, 0, this.origin, randomvec() * 150 + '0 0 325');
+ {
+ .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+ W_ThrowNewWeapon(this, this.weapon, 0, this.origin, randomvec() * 150 + '0 0 325', weaponentity);
+ }
}
void Monster_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
this.classname = "monster";
this.takedamage = DAMAGE_AIM;
this.bot_attack = true;
+ IL_PUSH(g_bot_targets, this);
this.iscreature = true;
this.teleportable = true;
this.damagedbycontents = true;