]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/attic/monsters/fight.qc
Moar things to attic
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / attic / monsters / fight.qc
diff --git a/qcsrc/server/attic/monsters/fight.qc b/qcsrc/server/attic/monsters/fight.qc
new file mode 100644 (file)
index 0000000..a8fcd8e
--- /dev/null
@@ -0,0 +1,252 @@
+
+/*
+
+A monster is in fight mode if it thinks it can effectively attack its
+enemy.
+
+When it decides it can't attack, it goes into hunt mode.
+
+*/
+
+void SUB_AttackFinished (float normal)
+{
+       self.cnt = 0;           // refire count for nightmare
+       if (skill < 3)
+               ATTACK_FINISHED(self) = time + normal;
+}
+
+float CanDamage(entity targ, entity inflictor)
+{
+       if (targ.movetype == MOVETYPE_PUSH)
+       {
+               traceline(inflictor.origin, 0.5 * (targ.absmin + targ.absmax), TRUE, self);
+               if (trace_fraction == 1)
+                       return TRUE;
+               if (trace_ent == targ)
+                       return TRUE;
+               return FALSE;
+       }
+
+       traceline(inflictor.origin, targ.origin, TRUE, self);
+       if (trace_fraction == 1)
+               return TRUE;
+       traceline(inflictor.origin, targ.origin + '15 15 0', TRUE, self);
+       if (trace_fraction == 1)
+               return TRUE;
+       traceline(inflictor.origin, targ.origin + '-15 -15 0', TRUE, self);
+       if (trace_fraction == 1)
+               return TRUE;
+       traceline(inflictor.origin, targ.origin + '-15 15 0', TRUE, self);
+       if (trace_fraction == 1)
+               return TRUE;
+       traceline(inflictor.origin, targ.origin + '15 -15 0', TRUE, self);
+       if (trace_fraction == 1)
+               return TRUE;
+
+       return FALSE;
+}
+
+float(float v) anglemod;
+
+void(vector dest) ChooseTurn;
+
+void() ai_face;
+
+
+float enemy_range;
+
+
+//=============================================================================
+
+/*
+===========
+GenericCheckAttack
+
+The player is in view, so decide to move or launch an attack
+Returns FALSE if movement should continue
+============
+*/
+float() GenericCheckAttack =
+{
+       vector spot1, spot2;
+       entity targ;
+       float chance;
+
+       if (self.health < 1)
+               return FALSE;
+       targ = self.enemy;
+
+       if (vlen(targ.origin - self.origin) > 5000) // long traces are slow
+               return FALSE;
+
+// see if any entities are in the way of the shot
+       spot1 = self.origin + self.view_ofs;
+       spot2 = targ.origin + targ.view_ofs;
+
+       traceline (spot1, spot2, FALSE, self);
+
+       if (trace_ent != targ)
+               return FALSE; // don't have a clear shot
+
+       if (trace_inopen && trace_inwater)
+               return FALSE; // sight line crossed contents
+
+       if (enemy_range == RANGE_MELEE)
+       {       // melee attack
+               if (self.th_melee)
+               {
+                       self.th_melee ();
+                       return TRUE;
+               }
+       }
+
+// missile attack
+       if (time < ATTACK_FINISHED(self))
+               return FALSE;
+
+       if (!self.th_missile)
+               return FALSE;
+
+       if (enemy_range == RANGE_FAR)
+               return FALSE;
+
+       if (enemy_range == RANGE_MELEE)
+       {
+               chance = 0.9;
+               ATTACK_FINISHED(self) = 0;
+       }
+       else if (enemy_range == RANGE_NEAR)
+       {
+               if (self.th_melee)
+                       chance = 0.2;
+               else
+                       chance = 0.4;
+       }
+       else if (enemy_range == RANGE_MID)
+       {
+               if (self.th_melee)
+                       chance = 0.05;
+               else
+                       chance = 0.1;
+       }
+       else
+               chance = 0;
+
+       if (random () < chance)
+       if (self.th_missile ())
+       {
+               SUB_AttackFinished (2*random());
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+
+/*
+=============
+ai_face
+
+Stay facing the enemy
+=============
+*/
+void() ai_face =
+{
+       self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin);
+       ChangeYaw ();
+}
+
+/*
+=============
+ai_charge
+
+The monster is in a melee attack, so get as close as possible to .enemy
+=============
+*/
+float (entity targ) visible;
+float(entity targ) infront;
+float(entity targ) range;
+
+void(float d) ai_charge =
+{
+       if (self.health < 1)
+               return;
+       ai_face ();
+       movetogoal (d);         // done in C code...
+}
+
+void() ai_charge_side =
+{
+       if (self.health < 1)
+               return;
+       vector dtemp;
+       float heading;
+
+// aim to the left of the enemy for a flyby
+
+       self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin);
+       ChangeYaw ();
+
+       makevectors (self.angles);
+       dtemp = self.enemy.origin - 30*v_right;
+       heading = vectoyaw(dtemp - self.origin);
+
+       walkmove(heading, 20);
+}
+
+
+/*
+=============
+ai_melee
+
+=============
+*/
+void() ai_melee =
+{
+       vector delta;
+       float ldmg;
+
+       if (self.health < 1)
+               return;
+       if (!self.enemy)
+               return;         // removed before stroke
+
+       delta = self.enemy.origin - self.origin;
+
+       if (vlen(delta) > 60)
+               return;
+
+       ldmg = DMG_KNIGHT_MELEE_BASE + DMG_KNIGHT_MELEE_RANDOM1 * random();
+       ldmg = ldmg + DMG_KNIGHT_MELEE_RANDOM2 * random();
+       ldmg = ldmg + DMG_KNIGHT_MELEE_RANDOM3 * random();
+       traceline(self.origin, self.enemy.origin, FALSE, self);
+
+       Damage (self.enemy, self, self, ldmg, self.projectiledeathtype, trace_endpos, '0 0 0'); // TODO add force to monster melee attacks?
+}
+
+
+void() ai_melee_side =
+{
+       vector delta;
+       float ldmg;
+
+       if (self.health < 1)
+               return;
+       if (!self.enemy)
+               return;         // removed before stroke
+
+       ai_charge_side();
+
+       delta = self.enemy.origin - self.origin;
+
+       if (vlen(delta) > 60)
+               return;
+       if (!CanDamage (self.enemy, self))
+               return;
+       ldmg = DMG_KNIGHT_MELEE_BASE + DMG_KNIGHT_MELEE_RANDOM1 * random();
+       ldmg = ldmg + DMG_KNIGHT_MELEE_RANDOM2 * random();
+       ldmg = ldmg + DMG_KNIGHT_MELEE_RANDOM3 * random();
+       traceline(self.origin, self.enemy.origin, FALSE, self);
+       Damage (self.enemy, self, self, ldmg, self.projectiledeathtype, trace_endpos, '0 0 0');
+}
+