commit e026ee781dc381f626aa1f8cf0edfa60999bc4e0 Author: /dev/humancontroller Date: Fri Aug 5 22:55:15 2011 +0200 allow movers to have >1 health, and be immune to specified attacks diff --git a/src/game/g_combat.c b/src/game/g_combat.c index 287c7ad..e51036c 100644 --- a/src/game/g_combat.c +++ b/src/game/g_combat.c @@ -913,24 +913,114 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, int save; int asave = 0; int knockback; + int k; + weapon_t weapon = WP_NONE; + upgrade_t upgrade = UP_NONE; + class_t class = PCL_NONE; // Can't deal damage sometimes if( !targ->takedamage || targ->health <= 0 || level.intermissionQueued ) return; + if( attacker && attacker->client && ( mod == MOD_MACHINEGUN || mod == MOD_PAINSAW || + mod == MOD_SHOTGUN || mod == MOD_LASGUN || mod == MOD_MDRIVER || + mod == MOD_CHAINGUN || mod == MOD_ABUILDER_CLAW || mod == MOD_LEVEL0_BITE || + mod == MOD_LEVEL1_CLAW || mod == MOD_LEVEL2_CLAW || mod == MOD_LEVEL2_ZAP || + mod == MOD_LEVEL3_CLAW || mod == MOD_LEVEL3_POUNCE || mod == MOD_LEVEL4_CLAW || + mod == MOD_LEVEL4_TRAMPLE || mod == MOD_LEVEL4_CRUSH ) ) + { + // instantaneous attack done by a client, the appropriate data can be accurately gathered + weapon = attacker->client->ps.weapon; + class = attacker->client->pers.classSelection; + + if( attacker->client->pers.teamSelection == TEAM_HUMANS ) + { + if( BG_InventoryContainsUpgrade( UP_BATTPACK, attacker->client->ps.stats ) ) + upgrade = UP_BATTPACK; + else if( BG_InventoryContainsUpgrade( UP_JETPACK, attacker->client->ps.stats ) ) + upgrade = UP_JETPACK; + else if( BG_InventoryContainsUpgrade( UP_BATTLESUIT, attacker->client->ps.stats ) ) + upgrade = UP_BATTLESUIT; + else + upgrade = UP_NONE; + } + else + upgrade = UP_NONE; + } + else + { + // unforseen case, attempt approximation + switch( mod ) + { + case MOD_BLASTER: weapon = WP_BLASTER; class = PCL_HUMAN; break; + case MOD_MACHINEGUN: weapon = WP_MACHINEGUN; class = PCL_HUMAN; break; + case MOD_PAINSAW: weapon = WP_PAIN_SAW; class = PCL_HUMAN; break; + case MOD_SHOTGUN: weapon = WP_SHOTGUN; class = PCL_HUMAN; break; + case MOD_LASGUN: weapon = WP_LAS_GUN; class = PCL_HUMAN; break; + case MOD_MDRIVER: weapon = WP_MASS_DRIVER; class = PCL_HUMAN; break; + case MOD_CHAINGUN: weapon = WP_CHAINGUN; class = PCL_HUMAN; break; + case MOD_PRIFLE: weapon = WP_PULSE_RIFLE; class = PCL_HUMAN; break; + case MOD_FLAMER: weapon = WP_FLAMER; class = PCL_HUMAN; break; + case MOD_FLAMER_SPLASH: weapon = WP_FLAMER; class = PCL_HUMAN; break; + case MOD_LCANNON: weapon = WP_LUCIFER_CANNON; class = PCL_HUMAN; break; + case MOD_LCANNON_SPLASH: weapon = WP_LUCIFER_CANNON; class = PCL_HUMAN; break; + case MOD_GRENADE: weapon = WP_GRENADE; class = PCL_HUMAN; break; + case MOD_ABUILDER_CLAW: weapon = WP_ABUILD; class = PCL_ALIEN_BUILDER0; break; + case MOD_SLOWBLOB: weapon = WP_ABUILD2; class = PCL_ALIEN_BUILDER0_UPG; break; + case MOD_LEVEL0_BITE: weapon = WP_ALEVEL0; class = PCL_ALIEN_LEVEL0; break; + case MOD_LEVEL1_CLAW: weapon = WP_ALEVEL1; class = PCL_ALIEN_LEVEL1; break; + case MOD_LEVEL1_PCLOUD: weapon = WP_ALEVEL1_UPG; class = PCL_ALIEN_LEVEL1_UPG; break; + case MOD_LEVEL2_CLAW: weapon = WP_ALEVEL2; class = PCL_ALIEN_LEVEL2; break; + case MOD_LEVEL2_ZAP: weapon = WP_ALEVEL2_UPG; class = PCL_ALIEN_LEVEL2_UPG; break; + case MOD_LEVEL3_CLAW: weapon = WP_ALEVEL3; class = PCL_ALIEN_LEVEL3; break; + case MOD_LEVEL3_POUNCE: weapon = WP_ALEVEL3; class = PCL_ALIEN_LEVEL3; break; + case MOD_LEVEL3_BOUNCEBALL: weapon = WP_ALEVEL3_UPG; class = PCL_ALIEN_LEVEL3_UPG; break; + case MOD_LEVEL4_CLAW: weapon = WP_ALEVEL4; class = PCL_ALIEN_LEVEL4; break; + case MOD_LEVEL4_TRAMPLE: weapon = WP_ALEVEL4; class = PCL_ALIEN_LEVEL4; break; + case MOD_LEVEL4_CRUSH: weapon = WP_ALEVEL4; class = PCL_ALIEN_LEVEL4; break; + case MOD_MGTURRET: weapon = WP_MGTURRET; class = PCL_NONE; break; + default: weapon = WP_NONE; class = PCL_NONE; break; + } + upgrade = UP_NONE; + } + if( !inflictor ) inflictor = &g_entities[ ENTITYNUM_WORLD ]; if( !attacker ) attacker = &g_entities[ ENTITYNUM_WORLD ]; - // shootable doors / buttons don't actually have any health if( targ->s.eType == ET_MOVER ) { - if( targ->use && ( targ->moverState == MOVER_POS1 || - targ->moverState == ROTATOR_POS1 ) ) - targ->use( targ, inflictor, attacker ); + if( !( targ->use && + ( targ->moverState == MOVER_POS1 || targ->moverState == ROTATOR_POS1 ) ) ) + { + return; + } + + for( k = 0; targ->wTriggers[ k ]; ++k ) + { + if( targ->wTriggers[ k ] == weapon ) + return; + } + for( k = 0; targ->uTriggers[ k ]; ++k ) + { + if( targ->uTriggers[ k ] == upgrade ) + return; + } + for( k = 0; targ->cTriggers[ k ]; ++k ) + { + if( targ->cTriggers[ k ] == class ) + return; + } + + targ->health -= damage; + if( targ->health > 0 ) + return; + + targ->use( targ, inflictor, attacker ); + targ->health = targ->resetValue; return; } diff --git a/src/game/g_local.h b/src/game/g_local.h index 548f587..72b04c9 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -242,6 +242,8 @@ struct gentity_s int buildPointZone; // index for zone int usesBuildPointZone; // does it use a zone? + + int resetValue; }; typedef enum diff --git a/src/game/g_mover.c b/src/game/g_mover.c index be6530e..862402c 100644 --- a/src/game/g_mover.c +++ b/src/game/g_mover.c @@ -554,6 +554,9 @@ void SetMoverState( gentity_t *ent, moverState_t moverState, int time ) BG_EvaluateTrajectory( &ent->s.apos, level.time, ent->r.currentAngles ); trap_LinkEntity( ent ); + + if( moverState == MOVER_POS1 || moverState == ROTATOR_POS1 ) + ent->health = ent->resetValue; } /* @@ -1200,6 +1203,30 @@ void InitRotator( gentity_t *ent ) /* +================ +InitHealth +================ +*/ +void InitHealth( gentity_t *ent ) +{ + char *s; + + if( ent->health < 0 ) + ent->health = 0; + + if( ent->health ) + { + ent->takedamage = qtrue; + ent->resetValue = ent->health; + G_SpawnString( "equipment", "", &s ); + BG_ParseCSVEquipmentList( s, ent->wTriggers, WP_NUM_WEAPONS, ent->uTriggers, UP_NUM_UPGRADES ); + G_SpawnString( "classes", "", &s ); + BG_ParseCSVClassList( s, ent->cTriggers, PCL_NUM_CLASSES ); + } +} + + +/* =============================================================================== DOOR @@ -1489,7 +1516,6 @@ void SP_func_door( gentity_t *ent ) vec3_t size; float lip; char *s; - int health; G_SpawnString( "sound2to1", "sound/movers/doors/dr1_strt.wav", &s ); ent->sound2to1 = G_SoundIndex( s ); @@ -1546,11 +1572,9 @@ void SP_func_door( gentity_t *ent ) ent->nextthink = level.time + FRAMETIME; - G_SpawnInt( "health", "0", &health ); - if( health ) - ent->takedamage = qtrue; + InitHealth( ent ); - if( ent->targetnames[ 0 ] || health ) + if( ent->targetnames[ 0 ] || ent->health ) { // non touch/shoot doors ent->think = Think_MatchTeam; @@ -1581,7 +1605,6 @@ void SP_func_door( gentity_t *ent ) void SP_func_door_rotating( gentity_t *ent ) { char *s; - int health; G_SpawnString( "sound2to1", "sound/movers/doors/dr1_strt.wav", &s ); ent->sound2to1 = G_SoundIndex( s ); @@ -1660,9 +1683,7 @@ void SP_func_door_rotating( gentity_t *ent ) ent->nextthink = level.time + FRAMETIME; - G_SpawnInt( "health", "0", &health ); - if( health ) - ent->takedamage = qtrue; + InitHealth( ent ); if( ent->targetnames[ 0 ] || ent->health ) { @@ -1694,7 +1715,6 @@ void SP_func_door_model( gentity_t *ent ) qboolean lightSet, colorSet; char *sound; gentity_t *clipBrush; - int health; G_SpawnString( "sound2to1", "sound/movers/doors/dr1_strt.wav", &s ); ent->sound2to1 = G_SoundIndex( s ); @@ -1798,9 +1818,7 @@ void SP_func_door_model( gentity_t *ent ) trap_LinkEntity( ent ); - G_SpawnInt( "health", "0", &health ); - if( health ) - ent->takedamage = qtrue; + InitHealth( ent ); if( !( ent->targetnames[ 0 ] || ent->health ) ) { @@ -2038,12 +2056,9 @@ void SP_func_button( gentity_t *ent ) distance = abs_movedir[ 0 ] * size[ 0 ] + abs_movedir[ 1 ] * size[ 1 ] + abs_movedir[ 2 ] * size[ 2 ] - lip; VectorMA( ent->pos1, distance, ent->movedir, ent->pos2 ); - if( ent->health ) - { - // shootable button - ent->takedamage = qtrue; - } - else + InitHealth( ent ); + + if( !ent->health ) { // touchable button ent->touch = Touch_Button;