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

  1. void() player_fall;
  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. Killed
  53. ============
  54. */
  55. void(entity targ, entity attacker) Killed =
  56. {
  57.     local entity oself;
  58.  
  59.     oself = self;
  60.     self = targ;
  61.     
  62.     if (self.health < -99)
  63.         self.health = -99;        // don't let sbar look bad if a player
  64.  
  65.     if (self.movetype == MOVETYPE_PUSH || self.movetype == MOVETYPE_NONE)
  66.     {    // doors, triggers, etc
  67.         self.th_die ();
  68.         self = oself;
  69.         return;
  70.     }
  71.  
  72.     self.enemy = attacker;
  73.  
  74. // bump the monster counter
  75.     if (self.flags & FL_MONSTER)
  76.     {
  77.         killed_monsters = killed_monsters + 1;
  78.         WriteByte (MSG_ALL, SVC_KILLEDMONSTER);
  79.     }
  80.  
  81.     ClientObituary(self, attacker);
  82.     
  83.     self.takedamage = DAMAGE_NO;
  84.     self.touch = SUB_Null;
  85.  
  86.     monster_death_use();
  87.     self.th_die ();
  88.     
  89.     self = oself;
  90. };
  91.  
  92.  
  93. /*
  94. ============
  95. T_Damage
  96.  
  97. The damage is coming from inflictor, but get mad at attacker
  98. This should be the only function that ever reduces health.
  99. ============
  100. */
  101. void(entity targ, entity inflictor, entity attacker, float damage) T_Damage=
  102. {
  103.     local    vector    dir;
  104.     local    entity    oldself;
  105.     local    float    save;
  106.     local    float    take;
  107.  
  108.     if (!targ.takedamage)
  109.         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)
  116.         damage = damage * 4;
  117.  
  118. // save damage based on the target's armor level
  119. // added a check to see if damage is drowning damage, if so, no
  120. // armor save or degredation
  121.  
  122.     if (targ.radsuit_finished == -1)
  123.         save = 0;
  124.     else
  125.     {
  126.         save = ceil(targ.armortype*damage);
  127.         if (save >= targ.armorvalue)
  128.         {
  129.             save = targ.armorvalue;
  130.             targ.armortype = 0;    // lost all armor
  131.             targ.items = targ.items - (targ.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3));
  132.         }
  133.     
  134.         targ.armorvalue = targ.armorvalue - save;
  135.     }
  136.     take = ceil(damage-save);
  137.  
  138. // add to the damage total for clients, which will be sent as a single
  139. // message at the end of the frame
  140. // FIXME: remove after combining shotgun blasts?
  141.     if (targ.flags & FL_CLIENT)
  142.     {
  143.         targ.dmg_take = targ.dmg_take + take;
  144.         targ.dmg_save = targ.dmg_save + save;
  145.         targ.dmg_inflictor = inflictor;
  146.     }
  147.  
  148. // figure momentum add
  149.     if ( (inflictor != world) && (targ.movetype == MOVETYPE_WALK) )
  150.     {
  151.         dir = targ.origin - (inflictor.absmin + inflictor.absmax) * 0.5;
  152.         dir = normalize(dir);
  153.         targ.velocity = targ.velocity + dir*damage*8;
  154.     }
  155.  
  156. // check for godmode or invincibility
  157.     if (targ.flags & FL_GODMODE)
  158.         return;
  159.     if (targ.invincible_finished >= time)
  160.     {
  161.         if (self.invincible_sound < time)
  162.         {
  163.             sound (targ, CHAN_ITEM, "items/protect3.wav", 1, ATTN_NORM);
  164.             self.invincible_sound = time + 2;
  165.         }
  166.         return;
  167.     }
  168.  
  169. // team play damage avoidance
  170. //added skins for avoidance (teamplay 3 and 4 ignore this of course)
  171.  
  172.         if (attacker != targ)
  173.         {
  174.                 if ( (teamplay == 1) && (targ.team > 0)&&(targ.team == attacker.team) )
  175.                         return;
  176.                 if ( (teamplay == 2) && (targ.skin == attacker.skin) )
  177.                         return;
  178.         }
  179.         
  180. // do the damage
  181.     targ.health = targ.health - take;
  182.             
  183.     if (targ.health <= 0)
  184.     {
  185.         Killed (targ, attacker);
  186.         return;
  187.     }
  188.  
  189. // react to the damage
  190.     oldself = self;
  191.     self = targ;
  192.  
  193.     if ( (self.flags & FL_MONSTER) && attacker != world)
  194.     {
  195.     // get mad unless of the same class (except for soldiers)
  196.         if (self != attacker && attacker != self.enemy)
  197.         {
  198.             if ( (self.classname != attacker.classname) 
  199.             || (self.classname == "monster_army" ) )
  200.             {
  201.                 if (self.enemy.classname == "player")
  202.                     self.oldenemy = self.enemy;
  203.                 self.enemy = attacker;
  204.                 FoundTarget ();
  205.             }
  206.         }
  207.     }
  208.  
  209.     if ( (take > 40) && (self.classname == "player") )
  210.         self.th_pain = player_fall;
  211.     if (self.th_pain)
  212.     {
  213.         self.th_pain (attacker, take);
  214.     // nightmare mode monsters don't go into pain frames often
  215.         if (skill == 3)
  216.             self.pain_finished = time + 5;        
  217.     }
  218.  
  219.     self = oldself;
  220. };
  221.  
  222. /*
  223. ============
  224. T_RadiusDamage
  225. ============
  226. */
  227. void(entity inflictor, entity attacker, float damage, entity ignore) T_RadiusDamage =
  228. {
  229.     local    float     points;
  230.     local    entity    head;
  231.     local    vector    org;
  232.  
  233.     head = findradius(inflictor.origin, damage+40);
  234.     
  235.     while (head)
  236.     {
  237.         if (head != ignore)
  238.         {
  239.             if (head.takedamage)
  240.             {
  241.                 org = head.origin + (head.mins + head.maxs)*0.5;
  242.                 points = 0.5*vlen (inflictor.origin - org);
  243.                 if (points < 0)
  244.                     points = 0;
  245.                 points = damage - points;
  246.                 if (head == attacker)
  247.                     points = points * 0.5;
  248.                 if (points > 0)
  249.                 {
  250.                     if (CanDamage (head, inflictor))
  251.                     {    // shambler takes half damage from all explosions
  252.                         if (head.classname == "monster_shambler")                        
  253.                             T_Damage (head, inflictor, attacker, points*0.5);
  254.                         else
  255.                             T_Damage (head, inflictor, attacker, points);
  256.                     }
  257.                 }
  258.             }
  259.         }
  260.         head = head.chain;
  261.     }
  262. };
  263.  
  264. /*
  265. ============
  266. T_BeamDamage
  267. ============
  268. */
  269. void(entity attacker, float damage) T_BeamDamage =
  270. {
  271.     local    float     points;
  272.     local    entity    head;
  273.     
  274.     head = findradius(attacker.origin, damage+40);
  275.     
  276.     while (head)
  277.     {
  278.         if (head.takedamage)
  279.         {
  280.             points = 0.5*vlen (attacker.origin - head.origin);
  281.             if (points < 0)
  282.                 points = 0;
  283.             points = damage - points;
  284.             if (head == attacker)
  285.                 points = points * 0.5;
  286.             if (points > 0)
  287.             {
  288.                 if (CanDamage (head, attacker))
  289.                 {
  290.                     if (head.classname == "monster_shambler")                        
  291.                         T_Damage (head, attacker, attacker, points*0.5);
  292.                     else
  293.                         T_Damage (head, attacker, attacker, points);
  294.                 }
  295.             }
  296.         }
  297.         head = head.chain;
  298.     }
  299. };
  300.  
  301.