Annotation of quake2/rogue/g_combat.c, revision 1.1.1.1

1.1       root        1: // g_combat.c
                      2: 
                      3: #include "g_local.h"
                      4: 
                      5: void M_SetEffects (edict_t *self);
                      6: 
                      7: /*
                      8: ROGUE
                      9: clean up heal targets for medic
                     10: */
                     11: void cleanupHealTarget (edict_t *ent)
                     12: {
                     13:        ent->monsterinfo.healer = NULL;
                     14:        ent->takedamage = DAMAGE_YES;
                     15:        ent->monsterinfo.aiflags &= ~AI_RESURRECTING;
                     16:        M_SetEffects (ent);
                     17: }
                     18: /*
                     19: ============
                     20: CanDamage
                     21: 
                     22: Returns true if the inflictor can directly damage the target.  Used for
                     23: explosions and melee attacks.
                     24: ============
                     25: */
                     26: qboolean CanDamage (edict_t *targ, edict_t *inflictor)
                     27: {
                     28:        vec3_t  dest;
                     29:        trace_t trace;
                     30: 
                     31: // bmodels need special checking because their origin is 0,0,0
                     32:        if (targ->movetype == MOVETYPE_PUSH)
                     33:        {
                     34:                VectorAdd (targ->absmin, targ->absmax, dest);
                     35:                VectorScale (dest, 0.5, dest);
                     36:                trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
                     37:                if (trace.fraction == 1.0)
                     38:                        return true;
                     39:                if (trace.ent == targ)
                     40:                        return true;
                     41:                return false;
                     42:        }
                     43:        
                     44:        trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, targ->s.origin, inflictor, MASK_SOLID);
                     45:        if (trace.fraction == 1.0)
                     46:                return true;
                     47: 
                     48:        VectorCopy (targ->s.origin, dest);
                     49:        dest[0] += 15.0;
                     50:        dest[1] += 15.0;
                     51:        trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
                     52:        if (trace.fraction == 1.0)
                     53:                return true;
                     54: 
                     55:        VectorCopy (targ->s.origin, dest);
                     56:        dest[0] += 15.0;
                     57:        dest[1] -= 15.0;
                     58:        trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
                     59:        if (trace.fraction == 1.0)
                     60:                return true;
                     61: 
                     62:        VectorCopy (targ->s.origin, dest);
                     63:        dest[0] -= 15.0;
                     64:        dest[1] += 15.0;
                     65:        trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
                     66:        if (trace.fraction == 1.0)
                     67:                return true;
                     68: 
                     69:        VectorCopy (targ->s.origin, dest);
                     70:        dest[0] -= 15.0;
                     71:        dest[1] -= 15.0;
                     72:        trace = gi.trace (inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
                     73:        if (trace.fraction == 1.0)
                     74:                return true;
                     75: 
                     76: 
                     77:        return false;
                     78: }
                     79: 
                     80: 
                     81: /*
                     82: ============
                     83: Killed
                     84: ============
                     85: */
                     86: void Killed (edict_t *targ, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
                     87: {
                     88:        if (targ->health < -999)
                     89:                targ->health = -999;
                     90: 
                     91:        if (targ->monsterinfo.aiflags & AI_MEDIC)
                     92:        {
                     93:                if (targ->enemy)  // god, I hope so
                     94:                {
                     95:                        cleanupHealTarget (targ->enemy);
                     96:                }
                     97: 
                     98:                // clean up self
                     99:                targ->monsterinfo.aiflags &= ~AI_MEDIC;
                    100:                targ->enemy = attacker;
                    101:        }
                    102:        else
                    103:        {
                    104:                targ->enemy = attacker;
                    105:        }
                    106: 
                    107:        if ((targ->svflags & SVF_MONSTER) && (targ->deadflag != DEAD_DEAD))
                    108:        {
                    109: //             targ->svflags |= SVF_DEADMONSTER;       // now treat as a different content type
                    110:                //ROGUE - free up slot for spawned monster if it's spawned
                    111:                if (targ->monsterinfo.aiflags & AI_SPAWNED_CARRIER)
                    112:                {
                    113:                        if (targ->monsterinfo.commander && targ->monsterinfo.commander->inuse && 
                    114:                                !strcmp(targ->monsterinfo.commander->classname, "monster_carrier"))
                    115:                        {
                    116:                                targ->monsterinfo.commander->monsterinfo.monster_slots++;
                    117: //                             if ((g_showlogic) && (g_showlogic->value))
                    118: //                                     gi.dprintf ("g_combat: freeing up carrier slot - %d left\n", targ->monsterinfo.commander->monsterinfo.monster_slots);
                    119:                        }
                    120:                }
                    121:                if (targ->monsterinfo.aiflags & AI_SPAWNED_MEDIC_C)
                    122:                {
                    123:                        if (targ->monsterinfo.commander)
                    124:                        {
                    125:                                if (targ->monsterinfo.commander->inuse && !strcmp(targ->monsterinfo.commander->classname, "monster_medic_commander"))
                    126:                                {
                    127:                                        targ->monsterinfo.commander->monsterinfo.monster_slots++;
                    128: //                                     if ((g_showlogic) && (g_showlogic->value))
                    129: //                                             gi.dprintf ("g_combat: freeing up medic slot - %d left\n", targ->monsterinfo.commander->monsterinfo.monster_slots);
                    130:                                }
                    131:                                else
                    132:                                        if ((g_showlogic) && (g_showlogic->value))
                    133:                                                gi.dprintf ("my commander is dead!  he's a %s\n", targ->monsterinfo.commander->classname);
                    134:                        }
                    135:                        else if ((g_showlogic) && (g_showlogic->value))
                    136:                                gi.dprintf ("My commander is GONE\n");
                    137: 
                    138:                }
                    139:                if (targ->monsterinfo.aiflags & AI_SPAWNED_WIDOW)
                    140:                {
                    141:                        // need to check this because we can have variable numbers of coop players
                    142:                        if (targ->monsterinfo.commander && targ->monsterinfo.commander->inuse && 
                    143:                                !strncmp(targ->monsterinfo.commander->classname, "monster_widow", 13))
                    144:                        {
                    145:                                if (targ->monsterinfo.commander->monsterinfo.monster_used > 0)
                    146:                                        targ->monsterinfo.commander->monsterinfo.monster_used--;
                    147: //                             if ((g_showlogic) && (g_showlogic->value))
                    148: //                                     gi.dprintf ("g_combat: freeing up black widow slot - %d used\n", targ->monsterinfo.commander->monsterinfo.monster_used);
                    149:                        }
                    150:                }
                    151:                //rogue
                    152:                if ((!(targ->monsterinfo.aiflags & AI_GOOD_GUY)) && (!(targ->monsterinfo.aiflags & AI_DO_NOT_COUNT)))
                    153:                {
                    154:                        level.killed_monsters++;
                    155:                        if (coop->value && attacker->client)
                    156:                                attacker->client->resp.score++;
                    157:                        // medics won't heal monsters that they kill themselves
                    158:                        // PMM - now they will
                    159: //                     if (strcmp(attacker->classname, "monster_medic") == 0)
                    160: //                             targ->owner = attacker;
                    161:                }
                    162:        }
                    163: 
                    164:        if (targ->movetype == MOVETYPE_PUSH || targ->movetype == MOVETYPE_STOP || targ->movetype == MOVETYPE_NONE)
                    165:        {       // doors, triggers, etc
                    166:                targ->die (targ, inflictor, attacker, damage, point);
                    167:                return;
                    168:        }
                    169: 
                    170:        if ((targ->svflags & SVF_MONSTER) && (targ->deadflag != DEAD_DEAD))
                    171:        {
                    172:                targ->touch = NULL;
                    173:                monster_death_use (targ);
                    174:        }
                    175: 
                    176:        targ->die (targ, inflictor, attacker, damage, point);
                    177: }
                    178: 
                    179: 
                    180: /*
                    181: ================
                    182: SpawnDamage
                    183: ================
                    184: */
                    185: void SpawnDamage (int type, vec3_t origin, vec3_t normal, int damage)
                    186: {
                    187:        if (damage > 255)
                    188:                damage = 255;
                    189:        gi.WriteByte (svc_temp_entity);
                    190:        gi.WriteByte (type);
                    191: //     gi.WriteByte (damage);
                    192:        gi.WritePosition (origin);
                    193:        gi.WriteDir (normal);
                    194:        gi.multicast (origin, MULTICAST_PVS);
                    195: }
                    196: 
                    197: 
                    198: /*
                    199: ============
                    200: T_Damage
                    201: 
                    202: targ           entity that is being damaged
                    203: inflictor      entity that is causing the damage
                    204: attacker       entity that caused the inflictor to damage targ
                    205:        example: targ=monster, inflictor=rocket, attacker=player
                    206: 
                    207: dir                    direction of the attack
                    208: point          point at which the damage is being inflicted
                    209: normal         normal vector from that point
                    210: damage         amount of damage being inflicted
                    211: knockback      force to be applied against targ as a result of the damage
                    212: 
                    213: dflags         these flags are used to control how T_Damage works
                    214:        DAMAGE_RADIUS                   damage was indirect (from a nearby explosion)
                    215:        DAMAGE_NO_ARMOR                 armor does not protect from this damage
                    216:        DAMAGE_ENERGY                   damage is from an energy based weapon
                    217:        DAMAGE_NO_KNOCKBACK             do not affect velocity, just view angles
                    218:        DAMAGE_BULLET                   damage is from a bullet (used for ricochets)
                    219:        DAMAGE_NO_PROTECTION    kills godmode, armor, everything
                    220: ============
                    221: */
                    222: static int CheckPowerArmor (edict_t *ent, vec3_t point, vec3_t normal, int damage, int dflags)
                    223: {
                    224:        gclient_t       *client;
                    225:        int                     save;
                    226:        int                     power_armor_type;
                    227:        int                     index;
                    228:        int                     damagePerCell;
                    229:        int                     pa_te_type;
                    230:        int                     power;
                    231:        int                     power_used;
                    232: 
                    233:        if (!damage)
                    234:                return 0;
                    235: 
                    236:        client = ent->client;
                    237: 
                    238:        if (dflags & (DAMAGE_NO_ARMOR | DAMAGE_NO_POWER_ARMOR))         // PGM
                    239:                return 0;                                       
                    240: 
                    241:        if (client)
                    242:        {
                    243:                power_armor_type = PowerArmorType (ent);
                    244:                if (power_armor_type != POWER_ARMOR_NONE)
                    245:                {
                    246:                        index = ITEM_INDEX(FindItem("Cells"));
                    247:                        power = client->pers.inventory[index];
                    248:                }
                    249:        }
                    250:        else if (ent->svflags & SVF_MONSTER)
                    251:        {
                    252:                power_armor_type = ent->monsterinfo.power_armor_type;
                    253:                power = ent->monsterinfo.power_armor_power;
                    254:        }
                    255:        else
                    256:                return 0;
                    257: 
                    258:        if (power_armor_type == POWER_ARMOR_NONE)
                    259:                return 0;
                    260:        if (!power)
                    261:                return 0;
                    262: 
                    263:        if (power_armor_type == POWER_ARMOR_SCREEN)
                    264:        {
                    265:                vec3_t          vec;
                    266:                float           dot;
                    267:                vec3_t          forward;
                    268: 
                    269:                // only works if damage point is in front
                    270:                AngleVectors (ent->s.angles, forward, NULL, NULL);
                    271:                VectorSubtract (point, ent->s.origin, vec);
                    272:                VectorNormalize (vec);
                    273:                dot = DotProduct (vec, forward);
                    274:                if (dot <= 0.3)
                    275:                        return 0;
                    276: 
                    277:                damagePerCell = 1;
                    278:                pa_te_type = TE_SCREEN_SPARKS;
                    279:                damage = damage / 3;
                    280:        }
                    281:        else
                    282:        {
                    283:                damagePerCell = 2;
                    284:                pa_te_type = TE_SHIELD_SPARKS;
                    285:                damage = (2 * damage) / 3;
                    286:        }
                    287: 
                    288:        // etf rifle
                    289:        if (dflags & DAMAGE_NO_REG_ARMOR)
                    290:                save = (power * damagePerCell) / 2;
                    291:        else
                    292:                save = power * damagePerCell;
                    293: 
                    294:        if (!save)
                    295:                return 0;
                    296:        if (save > damage)
                    297:                save = damage;
                    298: 
                    299:        SpawnDamage (pa_te_type, point, normal, save);
                    300:        ent->powerarmor_time = level.time + 0.2;
                    301: 
                    302:        if (dflags & DAMAGE_NO_REG_ARMOR)
                    303:                power_used = (save / damagePerCell) * 2;
                    304:        else
                    305:                power_used = save / damagePerCell;
                    306: 
                    307:        if (client)
                    308:                client->pers.inventory[index] -= power_used;
                    309:        else
                    310:                ent->monsterinfo.power_armor_power -= power_used;
                    311:        return save;
                    312: }
                    313: 
                    314: static int CheckArmor (edict_t *ent, vec3_t point, vec3_t normal, int damage, int te_sparks, int dflags)
                    315: {
                    316:        gclient_t       *client;
                    317:        int                     save;
                    318:        int                     index;
                    319:        gitem_t         *armor;
                    320: 
                    321:        if (!damage)
                    322:                return 0;
                    323: 
                    324:        client = ent->client;
                    325: 
                    326:        if (!client)
                    327:                return 0;
                    328: 
                    329:        // ROGUE - added DAMAGE_NO_REG_ARMOR for atf rifle
                    330:        if (dflags & (DAMAGE_NO_ARMOR | DAMAGE_NO_REG_ARMOR))
                    331:                return 0;
                    332: 
                    333:        index = ArmorIndex (ent);
                    334:        if (!index)
                    335:                return 0;
                    336: 
                    337:        armor = GetItemByIndex (index);
                    338: 
                    339:        if (dflags & DAMAGE_ENERGY)
                    340:                save = ceil(((gitem_armor_t *)armor->info)->energy_protection*damage);
                    341:        else
                    342:                save = ceil(((gitem_armor_t *)armor->info)->normal_protection*damage);
                    343:        if (save >= client->pers.inventory[index])
                    344:                save = client->pers.inventory[index];
                    345: 
                    346:        if (!save)
                    347:                return 0;
                    348: 
                    349:        client->pers.inventory[index] -= save;
                    350:        SpawnDamage (te_sparks, point, normal, save);
                    351: 
                    352:        return save;
                    353: }
                    354: 
                    355: void M_ReactToDamage (edict_t *targ, edict_t *attacker, edict_t *inflictor)
                    356: {
                    357:        // pmm
                    358:        qboolean new_tesla;
                    359: 
                    360:        if (!(attacker->client) && !(attacker->svflags & SVF_MONSTER))
                    361:                return;
                    362: 
                    363: //=======
                    364: //ROGUE
                    365:        // logic for tesla - if you are hit by a tesla, and can't see who you should be mad at (attacker)
                    366:        // attack the tesla
                    367:        // also, target the tesla if it's a "new" tesla
                    368:        if ((inflictor) && (!strcmp(inflictor->classname, "tesla")))
                    369:        {
                    370:                new_tesla = MarkTeslaArea(targ, inflictor);
                    371:                if (new_tesla)
                    372:                        TargetTesla (targ, inflictor);
                    373:                return;
                    374:                // FIXME - just ignore teslas when you're TARGET_ANGER or MEDIC
                    375: /*             if (!(targ->enemy && (targ->monsterinfo.aiflags & (AI_TARGET_ANGER|AI_MEDIC))))
                    376:                {
                    377:                        // FIXME - coop issues?
                    378:                        if ((!targ->enemy) || (!visible(targ, targ->enemy)))
                    379:                        {
                    380:                                gi.dprintf ("can't see player, switching to tesla\n");
                    381:                                TargetTesla (targ, inflictor);
                    382:                                return;
                    383:                        }
                    384:                        gi.dprintf ("can see player, ignoring tesla\n");
                    385:                }
                    386:                else if ((g_showlogic) && (g_showlogic->value))
                    387:                        gi.dprintf ("no enemy, or I'm doing other, more important things, than worrying about a damned tesla!\n");
                    388: */
                    389:        }
                    390: //ROGUE
                    391: //=======
                    392: 
                    393:        if (attacker == targ || attacker == targ->enemy)
                    394:                return;
                    395: 
                    396:        // if we are a good guy monster and our attacker is a player
                    397:        // or another good guy, do not get mad at them
                    398:        if (targ->monsterinfo.aiflags & AI_GOOD_GUY)
                    399:        {
                    400:                if (attacker->client || (attacker->monsterinfo.aiflags & AI_GOOD_GUY))
                    401:                        return;
                    402:        }
                    403: 
                    404: //PGM
                    405:        // if we're currently mad at something a target_anger made us mad at, ignore
                    406:        // damage
                    407:        if (targ->enemy && targ->monsterinfo.aiflags & AI_TARGET_ANGER)
                    408:        {
                    409:                float   percentHealth;
                    410: 
                    411:                // make sure whatever we were pissed at is still around.
                    412:                if(targ->enemy->inuse)
                    413:                {
                    414:                        percentHealth = (float)(targ->health) / (float)(targ->max_health);
                    415:                        if( targ->enemy->inuse && percentHealth > 0.33)
                    416:                                return;
                    417:                }
                    418: 
                    419:                // remove the target anger flag
                    420:                targ->monsterinfo.aiflags &= ~AI_TARGET_ANGER;
                    421:        }
                    422: //PGM
                    423: 
                    424: // PMM
                    425: // if we're healing someone, do like above and try to stay with them
                    426:        if ((targ->enemy) && (targ->monsterinfo.aiflags & AI_MEDIC))
                    427:        {
                    428:                float   percentHealth;
                    429: 
                    430:                percentHealth = (float)(targ->health) / (float)(targ->max_health);
                    431:                // ignore it some of the time
                    432:                if( targ->enemy->inuse && percentHealth > 0.25)
                    433:                        return;
                    434: 
                    435:                // remove the medic flag
                    436:                targ->monsterinfo.aiflags &= ~AI_MEDIC;
                    437:                cleanupHealTarget (targ->enemy);
                    438:        }
                    439: // PMM
                    440: 
                    441:        // we now know that we are not both good guys
                    442: 
                    443:        // if attacker is a client, get mad at them because he's good and we're not
                    444:        if (attacker->client)
                    445:        {
                    446:                targ->monsterinfo.aiflags &= ~AI_SOUND_TARGET;
                    447: 
                    448:                // this can only happen in coop (both new and old enemies are clients)
                    449:                // only switch if can't see the current enemy
                    450:                if (targ->enemy && targ->enemy->client)
                    451:                {
                    452:                        if (visible(targ, targ->enemy))
                    453:                        {
                    454:                                targ->oldenemy = attacker;
                    455:                                return;
                    456:                        }
                    457:                        targ->oldenemy = targ->enemy;
                    458:                }
                    459:                targ->enemy = attacker;
                    460:                if (!(targ->monsterinfo.aiflags & AI_DUCKED))
                    461:                        FoundTarget (targ); 
                    462:                return;
                    463:        }
                    464: 
                    465:        // it's the same base (walk/swim/fly) type and a different classname and it's not a tank
                    466:        // (they spray too much), get mad at them
                    467:        // PMM
                    468:        // added medics to this 
                    469:        // FIXME -
                    470:        // this really should be turned into an AI flag marking appropriate monsters as "don't shoot me"
                    471:        //   this also leads to the problem of tanks and medics being able to, at will, kill monsters with
                    472:        //   no chance of retaliation.  My vote is to make those monsters who are designed as "don't shoot me"
                    473:        //   such that they also ignore being shot by monsters as well
                    474:        /*
                    475:        if (((targ->flags & (FL_FLY|FL_SWIM)) == (attacker->flags & (FL_FLY|FL_SWIM))) &&
                    476:                 (strcmp (targ->classname, attacker->classname) != 0) &&
                    477:                 (strcmp(attacker->classname, "monster_tank") != 0) &&
                    478:                 (strcmp(attacker->classname, "monster_supertank") != 0) &&
                    479:                 (strcmp(attacker->classname, "monster_makron") != 0) &&
                    480:                 (strcmp(attacker->classname, "monster_jorg") != 0) &&
                    481:                 (strcmp(attacker->classname, "monster_carrier") != 0) && 
                    482:                 (strncmp(attacker->classname, "monster_medic", 12) != 0) ) // this should get medics & medic_commanders
                    483:        */
                    484:        if (((targ->flags & (FL_FLY|FL_SWIM)) == (attacker->flags & (FL_FLY|FL_SWIM))) &&
                    485:                (strcmp (targ->classname, attacker->classname) != 0) &&
                    486:                !(attacker->monsterinfo.aiflags & AI_IGNORE_SHOTS) &&
                    487:                !(targ->monsterinfo.aiflags & AI_IGNORE_SHOTS) )
                    488:        {
                    489:                if (targ->enemy && targ->enemy->client)
                    490:                        targ->oldenemy = targ->enemy;
                    491:                targ->enemy = attacker;
                    492:                if (!(targ->monsterinfo.aiflags & AI_DUCKED))
                    493:                        FoundTarget (targ);
                    494:        }
                    495:        // if they *meant* to shoot us, then shoot back
                    496:        else if (attacker->enemy == targ)
                    497:        {
                    498:                if (targ->enemy && targ->enemy->client)
                    499:                        targ->oldenemy = targ->enemy;
                    500:                targ->enemy = attacker;
                    501:                if (!(targ->monsterinfo.aiflags & AI_DUCKED))
                    502:                        FoundTarget (targ);
                    503:        }
                    504:        // otherwise get mad at whoever they are mad at (help our buddy) unless it is us!
                    505:        else if (attacker->enemy && attacker->enemy != targ)
                    506:        {
                    507:                if (targ->enemy && targ->enemy->client)
                    508:                        targ->oldenemy = targ->enemy;
                    509:                targ->enemy = attacker->enemy;
                    510:                if (!(targ->monsterinfo.aiflags & AI_DUCKED))
                    511:                        FoundTarget (targ);
                    512:        }
                    513: }
                    514: 
                    515: qboolean CheckTeamDamage (edict_t *targ, edict_t *attacker)
                    516: {
                    517:                //FIXME make the next line real and uncomment this block
                    518:                // if ((ability to damage a teammate == OFF) && (targ's team == attacker's team))
                    519:        return false;
                    520: }
                    521: 
                    522: void T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod)
                    523: {
                    524:        gclient_t       *client;
                    525:        int                     take;
                    526:        int                     save;
                    527:        int                     asave;
                    528:        int                     psave;
                    529:        int                     te_sparks;
                    530:        int                     sphere_notified;        // PGM
                    531: 
                    532:        if (!targ->takedamage)
                    533:                return;
                    534: 
                    535:        sphere_notified = false;                // PGM
                    536: 
                    537:        // friendly fire avoidance
                    538:        // if enabled you can't hurt teammates (but you can hurt yourself)
                    539:        // knockback still occurs
                    540:        if ((targ != attacker) && ((deathmatch->value && ((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS))) || coop->value))
                    541:        {
                    542:                if (OnSameTeam (targ, attacker))
                    543:                {
                    544:                        // PMM - nukes kill everyone
                    545:                        if (((int)(dmflags->value) & DF_NO_FRIENDLY_FIRE) && (mod != MOD_NUKE))
                    546:                                damage = 0;
                    547:                        else
                    548:                                mod |= MOD_FRIENDLY_FIRE;
                    549:                }
                    550:        }
                    551:        meansOfDeath = mod;
                    552: 
                    553: //ROGUE
                    554:        // allow the deathmatch game to change values
                    555:        if (deathmatch->value && gamerules && gamerules->value)
                    556:        {
                    557:                if(DMGame.ChangeDamage)
                    558:                        damage = DMGame.ChangeDamage(targ, attacker, damage, mod);
                    559:                if(DMGame.ChangeKnockback)
                    560:                        knockback = DMGame.ChangeKnockback(targ, attacker, knockback, mod);
                    561: 
                    562:                if(!damage)
                    563:                        return;
                    564:        }
                    565: //ROGUE
                    566: 
                    567:        // easy mode takes half damage
                    568:        if (skill->value == 0 && deathmatch->value == 0 && targ->client)
                    569:        {
                    570:                damage *= 0.5;
                    571:                if (!damage)
                    572:                        damage = 1;
                    573:        }
                    574: 
                    575:        client = targ->client;
                    576: 
                    577:        // PMM - defender sphere takes half damage
                    578:        if ((client) && (client->owned_sphere) && (client->owned_sphere->spawnflags == 1))
                    579:        {
                    580:                damage *= 0.5;
                    581:                if (!damage)
                    582:                        damage = 1;
                    583:        }
                    584: 
                    585:        if (dflags & DAMAGE_BULLET)
                    586:                te_sparks = TE_BULLET_SPARKS;
                    587:        else
                    588:                te_sparks = TE_SPARKS;
                    589: 
                    590:        VectorNormalize(dir);
                    591: 
                    592: // bonus damage for suprising a monster
                    593:        if (!(dflags & DAMAGE_RADIUS) && (targ->svflags & SVF_MONSTER) && (attacker->client) && (!targ->enemy) && (targ->health > 0))
                    594:                damage *= 2;
                    595: 
                    596:        if (targ->flags & FL_NO_KNOCKBACK)
                    597:                knockback = 0;
                    598: 
                    599: // figure momentum add
                    600:        if (!(dflags & DAMAGE_NO_KNOCKBACK))
                    601:        {
                    602:                if ((knockback) && (targ->movetype != MOVETYPE_NONE) && (targ->movetype != MOVETYPE_BOUNCE) && (targ->movetype != MOVETYPE_PUSH) && (targ->movetype != MOVETYPE_STOP))
                    603:                {
                    604:                        vec3_t  kvel;
                    605:                        float   mass;
                    606: 
                    607:                        if (targ->mass < 50)
                    608:                                mass = 50;
                    609:                        else
                    610:                                mass = targ->mass;
                    611: 
                    612:                        if (targ->client  && attacker == targ)
                    613:                                VectorScale (dir, 1600.0 * (float)knockback / mass, kvel);      // the rocket jump hack...
                    614:                        else
                    615:                                VectorScale (dir, 500.0 * (float)knockback / mass, kvel);
                    616: 
                    617:                        VectorAdd (targ->velocity, kvel, targ->velocity);
                    618:                }
                    619:        }
                    620: 
                    621:        take = damage;
                    622:        save = 0;
                    623: 
                    624:        // check for godmode
                    625:        if ( (targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION) )
                    626:        {
                    627:                take = 0;
                    628:                save = damage;
                    629:                SpawnDamage (te_sparks, point, normal, save);
                    630:        }
                    631: 
                    632:        // check for invincibility
                    633:        if ((client && client->invincible_framenum > level.framenum ) && !(dflags & DAMAGE_NO_PROTECTION))
                    634:        {
                    635:                if (targ->pain_debounce_time < level.time)
                    636:                {
                    637:                        gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0);
                    638:                        targ->pain_debounce_time = level.time + 2;
                    639:                }
                    640:                take = 0;
                    641:                save = damage;
                    642:        }
                    643:        // ROGUE
                    644:        // check for monster invincibility      
                    645:        if (((targ->svflags & SVF_MONSTER) && targ->monsterinfo.invincible_framenum > level.framenum ) && !(dflags & DAMAGE_NO_PROTECTION))
                    646:        {
                    647:                if (targ->pain_debounce_time < level.time)
                    648:                {
                    649:                        gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0);
                    650:                        targ->pain_debounce_time = level.time + 2;
                    651:                }
                    652:                take = 0;
                    653:                save = damage;
                    654:        }
                    655:        // ROGUE
                    656: 
                    657:        psave = CheckPowerArmor (targ, point, normal, take, dflags);
                    658:        take -= psave;
                    659: 
                    660:        asave = CheckArmor (targ, point, normal, take, te_sparks, dflags);
                    661:        take -= asave;
                    662: 
                    663:        //treat cheat/powerup savings the same as armor
                    664:        asave += save;
                    665: 
                    666:        // team damage avoidance
                    667:        if (!(dflags & DAMAGE_NO_PROTECTION) && CheckTeamDamage (targ, attacker))
                    668:                return;
                    669: 
                    670: // ROGUE - this option will do damage both to the armor and person. originally for DPU rounds
                    671:        if (dflags & DAMAGE_DESTROY_ARMOR)
                    672:        {
                    673:                if(!(targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION) &&
                    674:                   !(client && client->invincible_framenum > level.framenum))
                    675:                {
                    676:                        take = damage;
                    677:                }
                    678:        }
                    679: // ROGUE
                    680: 
                    681: // do the damage
                    682:        if (take)
                    683:        {
                    684: //PGM          need more blood for chainfist.
                    685:                if(targ->flags & FL_MECHANICAL)
                    686:                {
                    687:                        SpawnDamage ( TE_ELECTRIC_SPARKS, point, normal, take);
                    688:                }
                    689:                else if ((targ->svflags & SVF_MONSTER) || (client))
                    690:                {
                    691:                        if(mod == MOD_CHAINFIST)
                    692:                                SpawnDamage (TE_MOREBLOOD, point, normal, 255);
                    693:                        else
                    694:                                SpawnDamage (TE_BLOOD, point, normal, take);
                    695:                }
                    696:                else
                    697:                        SpawnDamage (te_sparks, point, normal, take);
                    698: //PGM
                    699: 
                    700:                targ->health = targ->health - take;
                    701:                        
                    702: //PGM - spheres need to know who to shoot at
                    703:                if(client && client->owned_sphere)
                    704:                {
                    705:                        sphere_notified = true;
                    706:                        if(client->owned_sphere->pain)
                    707:                                client->owned_sphere->pain (client->owned_sphere, attacker, 0, 0);
                    708:                }
                    709: //PGM
                    710: 
                    711:                if (targ->health <= 0)
                    712:                {
                    713:                        if ((targ->svflags & SVF_MONSTER) || (client))
                    714:                                targ->flags |= FL_NO_KNOCKBACK;
                    715:                        Killed (targ, inflictor, attacker, take, point);
                    716:                        return;
                    717:                }
                    718:        }
                    719: 
                    720: //PGM - spheres need to know who to shoot at
                    721:        if (!sphere_notified)
                    722:        {
                    723:                if(client && client->owned_sphere)
                    724:                {
                    725:                        sphere_notified = true;
                    726:                        if(client->owned_sphere->pain)
                    727:                                client->owned_sphere->pain (client->owned_sphere, attacker, 0, 0);
                    728:                }
                    729:        }
                    730: //PGM
                    731: 
                    732:        if (targ->svflags & SVF_MONSTER)
                    733:        {
                    734:                M_ReactToDamage (targ, attacker, inflictor);
                    735:                // PMM - fixme - if anyone else but the medic ever uses AI_MEDIC, check for it here instead
                    736:                // of in the medic's pain function
                    737:                if (!(targ->monsterinfo.aiflags & AI_DUCKED) && (take))
                    738:                {
                    739:                        targ->pain (targ, attacker, knockback, take);
                    740:                        // nightmare mode monsters don't go into pain frames often
                    741:                        if (skill->value == 3)
                    742:                                targ->pain_debounce_time = level.time + 5;
                    743:                }
                    744:        }
                    745:        else if (client)
                    746:        {
                    747:                if (!(targ->flags & FL_GODMODE) && (take))
                    748:                        targ->pain (targ, attacker, knockback, take);
                    749:        }
                    750:        else if (take)
                    751:        {
                    752:                if (targ->pain)
                    753:                        targ->pain (targ, attacker, knockback, take);
                    754:        }
                    755: 
                    756:        // add to the damage inflicted on a player this frame
                    757:        // the total will be turned into screen blends and view angle kicks
                    758:        // at the end of the frame
                    759:        if (client)
                    760:        {
                    761:                client->damage_parmor += psave;
                    762:                client->damage_armor += asave;
                    763:                client->damage_blood += take;
                    764:                client->damage_knockback += knockback;
                    765:                VectorCopy (point, client->damage_from);
                    766:        }
                    767: }
                    768: 
                    769: 
                    770: /*
                    771: ============
                    772: T_RadiusDamage
                    773: ============
                    774: */
                    775: void T_RadiusDamage (edict_t *inflictor, edict_t *attacker, float damage, edict_t *ignore, float radius, int mod)
                    776: {
                    777:        float   points;
                    778:        edict_t *ent = NULL;
                    779:        vec3_t  v;
                    780:        vec3_t  dir;
                    781: 
                    782:        while ((ent = findradius(ent, inflictor->s.origin, radius)) != NULL)
                    783:        {
                    784:                if (ent == ignore)
                    785:                        continue;
                    786:                if (!ent->takedamage)
                    787:                        continue;
                    788: 
                    789:                VectorAdd (ent->mins, ent->maxs, v);
                    790:                VectorMA (ent->s.origin, 0.5, v, v);
                    791:                VectorSubtract (inflictor->s.origin, v, v);
                    792:                points = damage - 0.5 * VectorLength (v);
                    793:                if (ent == attacker)
                    794:                        points = points * 0.5;
                    795:                if (points > 0)
                    796:                {
                    797:                        if (CanDamage (ent, inflictor))
                    798:                        {
                    799:                                VectorSubtract (ent->s.origin, inflictor->s.origin, dir);
                    800:                                T_Damage (ent, inflictor, attacker, dir, inflictor->s.origin, vec3_origin, (int)points, (int)points, DAMAGE_RADIUS, mod);
                    801:                        }
                    802:                }
                    803:        }
                    804: }
                    805: 
                    806: // **********************
                    807: // ROGUE
                    808: 
                    809: /*
                    810: ============
                    811: T_RadiusNukeDamage
                    812: 
                    813: Like T_RadiusDamage, but ignores walls (skips CanDamage check, among others)
                    814: // up to KILLZONE radius, do 10,000 points
                    815: // after that, do damage linearly out to KILLZONE2 radius
                    816: ============
                    817: */
                    818: 
                    819: void T_RadiusNukeDamage (edict_t *inflictor, edict_t *attacker, float damage, edict_t *ignore, float radius, int mod)
                    820: {
                    821:        float   points;
                    822:        edict_t *ent = NULL;
                    823:        vec3_t  v;
                    824:        vec3_t  dir;
                    825:        float   len;
                    826:        float   killzone, killzone2;
                    827:        trace_t tr;
                    828:        float   dist;
                    829: 
                    830:        killzone = radius;
                    831:        killzone2 = radius*2.0;
                    832: 
                    833:        while ((ent = findradius(ent, inflictor->s.origin, killzone2)) != NULL)
                    834:        {
                    835: // ignore nobody
                    836:                if (ent == ignore)
                    837:                        continue;
                    838:                if (!ent->takedamage)
                    839:                        continue;
                    840:                if (!ent->inuse)
                    841:                        continue;
                    842:                if (!(ent->client || (ent->svflags & SVF_MONSTER) || (ent->svflags & SVF_DAMAGEABLE)))
                    843:                        continue;
                    844: 
                    845:                VectorAdd (ent->mins, ent->maxs, v);
                    846:                VectorMA (ent->s.origin, 0.5, v, v);
                    847:                VectorSubtract (inflictor->s.origin, v, v);
                    848:                len = VectorLength(v);
                    849:                if (len <= killzone)
                    850:                {
                    851:                        if (ent->client)
                    852:                                ent->flags |= FL_NOGIB;
                    853:                        points = 10000;
                    854:                }
                    855:                else if (len <= killzone2)
                    856:                        points = (damage/killzone)*(killzone2 - len);
                    857:                else
                    858:                        points = 0;
                    859: //             points = damage - 0.005 * len*len;
                    860: //             if (ent == attacker)
                    861: //                     points = points * 0.5;
                    862:                if ((g_showlogic) && (g_showlogic->value))
                    863:                {
                    864:                        if (!(strcmp(ent->classname, "player")))
                    865:                                gi.dprintf ("dist = %2.2f doing %6.0f damage to %s\n", len, points, inflictor->teammaster->client->pers.netname);
                    866:                        else
                    867:                                gi.dprintf ("dist = %2.2f doing %6.0f damage to %s\n", len, points, ent->classname);
                    868:                }
                    869:                if (points > 0)
                    870:                {
                    871: //                     if (CanDamage (ent, inflictor))
                    872: //                     {
                    873:                                if (ent->client)
                    874:                                        ent->client->nuke_framenum = level.framenum + 20;
                    875:                                VectorSubtract (ent->s.origin, inflictor->s.origin, dir);
                    876:                                T_Damage (ent, inflictor, attacker, dir, inflictor->s.origin, vec3_origin, (int)points, (int)points, DAMAGE_RADIUS, mod);
                    877: //                     }
                    878:                }
                    879:        }
                    880:        ent = g_edicts+1; // skip the worldspawn
                    881:        // cycle through players
                    882:        while (ent)
                    883:        {
                    884:                if ((ent->client) && (ent->client->nuke_framenum != level.framenum+20) && (ent->inuse))
                    885:                {
                    886:                        tr = gi.trace (inflictor->s.origin, NULL, NULL, ent->s.origin, inflictor, MASK_SOLID);
                    887:                        if (tr.fraction == 1.0)
                    888:                        {
                    889:                                if ((g_showlogic) && (g_showlogic->value))
                    890:                                        gi.dprintf ("Undamaged player in LOS with nuke, flashing!\n");
                    891:                                ent->client->nuke_framenum = level.framenum + 20;
                    892:                        }
                    893:                        else
                    894:                        {
                    895:                                dist = realrange (ent, inflictor);
                    896:                                if (dist < 2048)
                    897:                                        ent->client->nuke_framenum = max(ent->client->nuke_framenum,level.framenum + 15);
                    898:                                else
                    899:                                        ent->client->nuke_framenum = max(ent->client->nuke_framenum,level.framenum + 10);
                    900:                        }
                    901:                        ent++;
                    902:                }
                    903:                else
                    904:                        ent = NULL;
                    905:        }
                    906: }
                    907: 
                    908: /*
                    909: ============
                    910: T_RadiusClassDamage
                    911: 
                    912: Like T_RadiusDamage, but ignores anything with classname=ignoreClass
                    913: ============
                    914: */
                    915: void T_RadiusClassDamage (edict_t *inflictor, edict_t *attacker, float damage, char *ignoreClass, float radius, int mod)
                    916: {
                    917:        float   points;
                    918:        edict_t *ent = NULL;
                    919:        vec3_t  v;
                    920:        vec3_t  dir;
                    921: 
                    922:        while ((ent = findradius(ent, inflictor->s.origin, radius)) != NULL)
                    923:        {
                    924:                if (ent->classname && !strcmp(ent->classname, ignoreClass))
                    925:                        continue;
                    926:                if (!ent->takedamage)
                    927:                        continue;
                    928: 
                    929:                VectorAdd (ent->mins, ent->maxs, v);
                    930:                VectorMA (ent->s.origin, 0.5, v, v);
                    931:                VectorSubtract (inflictor->s.origin, v, v);
                    932:                points = damage - 0.5 * VectorLength (v);
                    933:                if (ent == attacker)
                    934:                        points = points * 0.5;
                    935:                if (points > 0)
                    936:                {
                    937:                        if (CanDamage (ent, inflictor))
                    938:                        {
                    939:                                VectorSubtract (ent->s.origin, inflictor->s.origin, dir);
                    940:                                T_Damage (ent, inflictor, attacker, dir, inflictor->s.origin, vec3_origin, (int)points, (int)points, DAMAGE_RADIUS, mod);
                    941:                        }
                    942:                }
                    943:        }
                    944: }
                    945: 
                    946: // ROGUE
                    947: // ********************

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.