home *** CD-ROM | disk | FTP | other *** search
/ Quake 'em / QUAKEEM.BIN / quake / programs / psychoc2 / combat.qc < prev    next >
Encoding:
Text File  |  1996-08-10  |  6.5 KB  |  281 lines

  1.  
  2. void() T_MissileTouch;
  3. void() info_player_start;
  4. void(entity targ, entity attacker) ClientObituary;
  5.  
  6. void() monster_death_use;
  7.  
  8. //============================================================================
  9.  
  10. /*
  11. ============
  12. CanDamage
  13.  
  14. Returns true if the inflictor can directly damage the target.  Used for
  15. explosions and melee attacks.
  16. ============
  17. */
  18. float(entity targ, entity inflictor) CanDamage =
  19. {
  20. // bmodels need special checking because their origin is 0,0,0
  21.     if (targ.movetype == MOVETYPE_PUSH)
  22.     {
  23.         traceline(inflictor.origin, 0.5 * (targ.absmin + targ.absmax), TRUE, self);
  24.         if (trace_fraction == 1)
  25.             return TRUE;
  26.         if (trace_ent == targ)
  27.             return TRUE;
  28.         return FALSE;
  29.     }
  30.     
  31.     traceline(inflictor.origin, targ.origin, TRUE, self);
  32.     if (trace_fraction == 1)
  33.         return TRUE;
  34.     traceline(inflictor.origin, targ.origin + '15 15 0', TRUE, self);
  35.     if (trace_fraction == 1)
  36.         return TRUE;
  37.     traceline(inflictor.origin, targ.origin + '-15 -15 0', TRUE, self);
  38.     if (trace_fraction == 1)
  39.         return TRUE;
  40.     traceline(inflictor.origin, targ.origin + '-15 15 0', TRUE, self);
  41.     if (trace_fraction == 1)
  42.         return TRUE;
  43.     traceline(inflictor.origin, targ.origin + '15 -15 0', TRUE, self);
  44.     if (trace_fraction == 1)
  45.         return TRUE;
  46.  
  47.     return FALSE;
  48. };
  49.  
  50.  
  51. /*
  52. ============
  53. Killed
  54. ============
  55. */
  56. void(entity targ, entity attacker) Killed =
  57. {
  58.     local entity oself;
  59.  
  60.     oself = self;
  61.     self = targ;
  62.     
  63.     if (self.health < -99)
  64.         self.health = -99;        // don't let sbar look bad if a player
  65.  
  66.     if (self.movetype == MOVETYPE_PUSH || self.movetype == MOVETYPE_NONE)
  67.     {    // doors, triggers, etc
  68.         self.th_die ();
  69.         self = oself;
  70.         return;
  71.     }
  72.  
  73.     self.enemy = attacker;
  74.  
  75. // bump the monster counter
  76.     if (self.flags & FL_MONSTER)
  77.     {
  78.         killed_monsters = killed_monsters + 1;
  79.         WriteByte (MSG_ALL, SVC_KILLEDMONSTER);
  80.     }
  81.  
  82.     ClientObituary(self, attacker);
  83.     
  84.     self.takedamage = DAMAGE_NO;
  85.     self.touch = SUB_Null;
  86.  
  87.     monster_death_use();
  88.     self.th_die ();
  89.     
  90.     self = oself;
  91. };
  92.  
  93.  
  94. /*
  95. ============
  96. T_Damage
  97.  
  98. The damage is coming from inflictor, but get mad at attacker
  99. This should be the only function that ever reduces health.
  100. ============
  101. */
  102. void(entity targ, entity inflictor, entity attacker, float damage) T_Damage=
  103.    {
  104.    local vector dir;
  105.    local entity oldself;
  106.    local float save;
  107.    local float take;
  108.  
  109.    if(!targ.takedamage) return;
  110.  
  111. // used by buttons and triggers to set activator for target firing
  112.    damage_attacker = attacker;
  113.  
  114. // check for quad damage powerup on the attacker
  115.    if(attacker.super_damage_finished > time) damage = damage * 4;
  116.  
  117. // save damage based on the target's armor level
  118.  
  119.    save = ceil(targ.armortype*damage);
  120.    if(save >= targ.armorvalue)
  121.       {
  122.       save = targ.armorvalue;
  123.       targ.armortype = 0;     // lost all armor
  124.       targ.items = targ.items - (targ.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3));
  125.       }
  126.     
  127.    targ.armorvalue = targ.armorvalue - save;
  128.    take = ceil(damage-save);
  129.  
  130. // add to the damage total for clients, which will be sent as a single
  131. // message at the end of the frame
  132. // FIXME: remove after combining shotgun blasts?
  133.    if(targ.flags & FL_CLIENT)
  134.       {
  135.       targ.dmg_take = targ.dmg_take + take;
  136.       targ.dmg_save = targ.dmg_save + save;
  137.       targ.dmg_inflictor = inflictor;
  138.       }
  139.  
  140. // figure momentum add
  141.    if((inflictor != world) && (targ.movetype == MOVETYPE_WALK))
  142.       {
  143.       dir = targ.origin - (inflictor.absmin + inflictor.absmax) * 0.5;
  144.       dir = normalize(dir);
  145.       targ.velocity = targ.velocity + dir*damage*8;
  146.       }
  147.  
  148. // check for godmode or invincibility
  149.    if(attacker.weapon != IT_EXTRA_WEAPON)
  150.       {
  151.       if(targ.flags & FL_GODMODE) return;
  152.       if(targ.invincible_finished >= time)
  153.          {
  154.          if(self.invincible_sound < time)
  155.             {
  156.             sound(targ, CHAN_ITEM, "items/protect3.wav", 1, ATTN_NORM);
  157.             self.invincible_sound = time + 2;
  158.             }
  159.          return;
  160.          }
  161.       }
  162.  
  163. // do the damage
  164.    targ.health = targ.health - take;
  165.             
  166.    if(targ.health <= 0)
  167.       {
  168. // kill the player
  169.       Killed(targ, attacker);
  170.       return;
  171.       }
  172.  
  173.  
  174. // react to the damage
  175.    oldself = self;
  176.    self = targ;
  177.  
  178.    if((self.flags & FL_MONSTER) && attacker != world)
  179.       {
  180. // get mad unless of the same class (except for soldiers)
  181.       if(self != attacker && attacker != self.enemy)
  182.          {
  183.          if((self.classname != attacker.classname) || (self.classname == "monster_army"))
  184.             {
  185.             if(self.enemy.classname == "player") self.oldenemy = self.enemy;
  186.             self.enemy = attacker;
  187.             FoundTarget();
  188.             }
  189.          }
  190.       }
  191.  
  192.    if(self.th_pain)
  193.       {
  194.       self.th_pain(attacker, take);
  195. // nightmare mode monsters don't go into pain frames often
  196.       if(skill == 3) self.pain_finished = time + 5;   
  197.       }
  198.  
  199.    self = oldself;
  200.    };
  201.  
  202. /*
  203. ============
  204. T_RadiusDamage
  205. ============
  206. */
  207. void(entity inflictor, entity attacker, float damage, entity ignore) T_RadiusDamage =
  208. {
  209.     local    float     points;
  210.     local    entity    head;
  211.     local    vector    org;
  212.  
  213.     head = findradius(inflictor.origin, damage+40);
  214.     
  215.     while (head)
  216.     {
  217.         if (head != ignore)
  218.         {
  219.             if (head.takedamage)
  220.             {
  221.                 org = head.origin + (head.mins + head.maxs)*0.5;
  222.                 points = 0.5*vlen (inflictor.origin - org);
  223.                 if (points < 0)
  224.                     points = 0;
  225.                 points = damage - points;
  226.                 if (head == attacker)
  227.                     points = points * 0.5;
  228.                 if (points > 0)
  229.                 {
  230.                     if (CanDamage (head, inflictor))
  231.                     {    // shambler takes half damage from all explosions
  232.                         if (head.classname == "monster_shambler")                        
  233.                             T_Damage (head, inflictor, attacker, points*0.5);
  234.                         else
  235.                             T_Damage (head, inflictor, attacker, points);
  236.                     }
  237.                 }
  238.             }
  239.         }
  240.         head = head.chain;
  241.     }
  242. };
  243.  
  244. /*
  245. ============
  246. T_BeamDamage
  247. ============
  248. */
  249. void(entity attacker, float damage) T_BeamDamage =
  250. {
  251.     local    float     points;
  252.     local    entity    head;
  253.     
  254.     head = findradius(attacker.origin, damage+40);
  255.     
  256.     while (head)
  257.     {
  258.         if (head.takedamage)
  259.         {
  260.             points = 0.5*vlen (attacker.origin - head.origin);
  261.             if (points < 0)
  262.                 points = 0;
  263.             points = damage - points;
  264.             if (head == attacker)
  265.                 points = points * 0.5;
  266.             if (points > 0)
  267.             {
  268.                 if (CanDamage (head, attacker))
  269.                 {
  270.                     if (head.classname == "monster_shambler")                        
  271.                         T_Damage (head, attacker, attacker, points*0.5);
  272.                     else
  273.                         T_Damage (head, attacker, attacker, points);
  274.                 }
  275.             }
  276.         }
  277.         head = head.chain;
  278.     }
  279. };
  280.  
  281.