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)
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)
return true;
}
-void Monster_Respawn(entity this) { Monster_Spawn(this, this.monsterid); }
+void Monster_Respawn(entity this) { Monster_Spawn(this, true, this.monsterid); }
.vector pos1, pos2;
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)
void Monster_Appear(entity this, entity actor, entity trigger)
{
this.enemy = actor;
- this.spawnflags &= ~MONSTERFLAG_APPEAR; // otherwise, we get an endless loop
- Monster_Spawn(this, this.monsterid);
+ Monster_Spawn(this, false, this.monsterid);
}
bool Monster_Appear_Check(entity this, int monster_id)
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)
return;
}
- float reverse = false;
- vector a, b;
-
makevectors(this.angles);
- a = this.origin + '0 0 16';
- b = this.origin + '0 0 16' + v_forward * 32;
+ vector a = CENTER_OR_VIEWOFS(this);
+ vector b = CENTER_OR_VIEWOFS(this) + v_forward * 32;
traceline(a, b, MOVE_NORMAL, this);
+ bool reverse = false;
if(trace_fraction != 1.0)
- {
reverse = true;
-
- if(trace_ent)
- if(IS_PLAYER(trace_ent) && !(trace_ent.items & IT_STRENGTH))
- reverse = false;
- }
+ if(trace_ent && IS_PLAYER(trace_ent) && !(trace_ent.items & ITEM_Strength.m_itemid))
+ reverse = false;
+ if(trace_ent && IS_MONSTER(trace_ent))
+ reverse = true;
// TODO: fix this... tracing is broken if the floor is thin
/*
void Monster_Think(entity this)
{
setthink(this, Monster_Think);
- this.nextthink = this.ticrate;
+ this.nextthink = time + this.ticrate;
if(this.monster_lifetime)
if(time >= this.monster_lifetime)
return true;
}
-bool Monster_Spawn(entity this, int mon_id)
+bool Monster_Spawn(entity this, bool check_appear, int mon_id)
{
// setup the basic required properties for a monster
entity mon = Monsters_from(mon_id);
if(!autocvar_g_monsters) { Monster_Remove(this); return false; }
if(!(this.spawnflags & MONSTERFLAG_RESPAWNED))
- {
IL_PUSH(g_monsters, this);
- IL_PUSH(g_damagedbycontents, this);
- }
- if(Monster_Appear_Check(this, mon_id)) { return true; } // return true so the monster isn't removed
+ if(check_appear && Monster_Appear_Check(this, mon_id)) { return true; } // return true so the monster isn't removed
if(!this.monster_skill)
this.monster_skill = cvar("g_monsters_skill");
this.flags = FL_MONSTER;
this.classname = "monster";
this.takedamage = DAMAGE_AIM;
+ if(!this.bot_attack)
+ IL_PUSH(g_bot_targets, this);
this.bot_attack = true;
- IL_PUSH(g_bot_targets, this);
this.iscreature = true;
this.teleportable = true;
+ if(!this.damagedbycontents)
+ IL_PUSH(g_damagedbycontents, this);
this.damagedbycontents = true;
this.monsterid = mon_id;
this.event_damage = Monster_Damage;
this.oldtarget2 = this.target2;
this.pass_distance = 0;
this.deadflag = DEAD_NO;
- this.noalign = ((mon.spawnflags & MONSTER_TYPE_FLY) || (mon.spawnflags & MONSTER_TYPE_SWIM));
this.spawn_time = time;
this.gravity = 1;
this.monster_moveto = '0 0 0';
this.monster_face = '0 0 0';
this.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_BOTCLIP | DPCONTENTS_MONSTERCLIP;
+ if(!this.noalign) { this.noalign = ((mon.spawnflags & MONSTER_TYPE_FLY) || (mon.spawnflags & MONSTER_TYPE_SWIM)); }
if(!this.scale) { this.scale = 1; }
if(autocvar_g_monsters_edit) { this.grab = 1; }
if(autocvar_g_fullbrightplayers) { this.effects |= EF_FULLBRIGHT; }