// DeadTakeDamage - takedamage function called when a monster's corpse is damaged. int CBaseMonster::DeadTakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) { // grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit). Vector vecDir(0, 0, 0); if (!FNullEnt(pevInflictor)) { CBaseEntity *pInflictor = CBaseEntity::Instance(pevInflictor); if (pInflictor) { vecDir = (pInflictor->Center() - Vector(0, 0, 10) - Center()).Normalize(); vecDir = g_vecAttackDir = vecDir.Normalize(); } } // turn this back on when the bounding box issues are resolved. #if 0 pev->flags &= ~FL_ONGROUND; pev->origin.z += 1; // let the damage scoot the corpse around a bit. if (!FNullEnt(pevInflictor) && (pevAttacker->solid != SOLID_TRIGGER)) { pev->velocity = pev->velocity + vecDir * -DamageForce(flDamage); } #endif // kill the corpse if enough damage was done to destroy the corpse and the damage is of a type that is allowed to destroy the corpse. if (bitsDamageType & DMG_GIB_CORPSE) { if (pev->health <= flDamage) { pev->health = -50; Killed(pevAttacker, GIB_ALWAYS); return 0; } // Accumulate corpse gibbing damage, so you can gib with multiple hits pev->health -= flDamage * 0.1; } return 1; }
void CFuncWallDetail::Think( void ) { //MAKE FAKE Level Of Detail CBaseEntity *pEntity = NULL; while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, 9999 )) != NULL) { if ( pEntity->IsPlayer() ) { float flDist = (pEntity->Center() - pev->origin).Length(); ALERT ( at_console, "flDist is: %f\n",flDist ); if ( flDist >= 800) { //ALERT ( at_console, "m_iszWallNormal\n" ); FireTargets( STRING(m_iszWallLow), this, this, USE_ON, 0 );//LOW FireTargets( STRING(m_iszWallNormal), this, this, USE_OFF, 0 ); FireTargets( STRING(m_iszWallDetail), this, this, USE_OFF, 0 ); } else if ( flDist >= 400) { //ALERT ( at_console, "m_iszWallLow\n" ); FireTargets( STRING(m_iszWallLow), this, this, USE_OFF, 0 ); FireTargets( STRING(m_iszWallNormal), this, this, USE_ON, 0 );//NORMAL FireTargets( STRING(m_iszWallDetail), this, this, USE_OFF, 0 ); } else//detallado { //ALERT ( at_console, "m_iszWallDetail\n" ); FireTargets( STRING(m_iszWallLow), this, this, USE_OFF, 0 ); FireTargets( STRING(m_iszWallNormal), this, this, USE_OFF, 0 ); FireTargets( STRING(m_iszWallDetail), this, this, USE_ON, 0 );//DETAILED } } } pev->nextthink = gpGlobals->time + 0.1; }
/* ============ TakeDamage The damage is coming from inflictor, but get mad at attacker This should be the only function that ever reduces health. bitsDamageType indicates the type of damage sustained, ie: DMG_SHOCK Time-based damage: only occurs while the monster is within the trigger_hurt. When a monster is poisoned via an arrow etc it takes all the poison damage at once. GLOBALS ASSUMED SET: g_iSkillLevel ============ */ int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { float flTake; Vector vecDir; if (!pev->takedamage) return 0; if ( !IsAlive() ) { return DeadTakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); } if ( pev->deadflag == DEAD_NO ) { // no pain sound during death animation. PainSound();// "Ouch!" } //!!!LATER - make armor consideration here! flTake = flDamage; // set damage type sustained m_bitsDamageType |= bitsDamageType; // grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit). vecDir = Vector( 0, 0, 0 ); if (!FNullEnt( pevInflictor )) { CBaseEntity *pInflictor = CBaseEntity :: Instance( pevInflictor ); if (pInflictor) { vecDir = ( pInflictor->Center() - Vector ( 0, 0, 10 ) - Center() ).Normalize(); vecDir = g_vecAttackDir = vecDir.Normalize(); } } // add to the damage total for clients, which will be sent as a single // message at the end of the frame // todo: remove after combining shotgun blasts? if ( IsPlayer() ) { if ( pevInflictor ) pev->dmg_inflictor = ENT(pevInflictor); pev->dmg_take += flTake; // check for godmode or invincibility if ( pev->flags & FL_GODMODE ) { return 0; } } // if this is a player, move him around! if ( ( !FNullEnt( pevInflictor ) ) && (pev->movetype == MOVETYPE_WALK) && (!pevAttacker || pevAttacker->solid != SOLID_TRIGGER) ) { pev->velocity = pev->velocity + vecDir * -DamageForce( flDamage ); } // do the damage pev->health -= flTake; // HACKHACK Don't kill monsters in a script. Let them break their scripts first if ( m_MonsterState == MONSTERSTATE_SCRIPT ) { SetConditions( bits_COND_LIGHT_DAMAGE ); return 0; } if ( pev->health <= 0 ) { g_pevLastInflictor = pevInflictor; if ( bitsDamageType & DMG_ALWAYSGIB ) { Killed( pevAttacker, GIB_ALWAYS ); } else if ( bitsDamageType & DMG_NEVERGIB ) { Killed( pevAttacker, GIB_NEVER ); } else { Killed( pevAttacker, GIB_NORMAL ); } g_pevLastInflictor = NULL; return 0; } // react to the damage (get mad) if ( (pev->flags & FL_MONSTER) && !FNullEnt(pevAttacker) ) { if ( pevAttacker->flags & (FL_MONSTER | FL_CLIENT) ) {// only if the attack was a monster or client! // enemy's last known position is somewhere down the vector that the attack came from. if (pevInflictor) { if (m_hEnemy == NULL || pevInflictor == m_hEnemy->pev || !HasConditions(bits_COND_SEE_ENEMY)) { m_vecEnemyLKP = pevInflictor->origin; } } else { m_vecEnemyLKP = pev->origin + ( g_vecAttackDir * 64 ); } MakeIdealYaw( m_vecEnemyLKP ); // add pain to the conditions // !!!HACKHACK - fudged for now. Do we want to have a virtual function to determine what is light and // heavy damage per monster class? if ( flDamage > 0 ) { SetConditions(bits_COND_LIGHT_DAMAGE); } if ( flDamage >= 20 ) { SetConditions(bits_COND_HEAVY_DAMAGE); } } } return 1; }
//========================================================= // SonicAttack //========================================================= void CHoundeye :: SonicAttack ( void ) { float flAdjustedDamage; float flDist; switch ( RANDOM_LONG( 0, 2 ) ) { case 0: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "houndeye/he_blast1.wav", 1, ATTN_NORM); break; case 1: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "houndeye/he_blast2.wav", 1, ATTN_NORM); break; case 2: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "houndeye/he_blast3.wav", 1, ATTN_NORM); break; } // blast circles MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); WRITE_BYTE( TE_BEAMCYLINDER ); WRITE_COORD( pev->origin.x); WRITE_COORD( pev->origin.y); WRITE_COORD( pev->origin.z + 16); WRITE_COORD( pev->origin.x); WRITE_COORD( pev->origin.y); WRITE_COORD( pev->origin.z + 16 + HOUNDEYE_MAX_ATTACK_RADIUS / .2); // reach damage radius over .3 seconds WRITE_SHORT( m_iSpriteTexture ); WRITE_BYTE( 0 ); // startframe WRITE_BYTE( 0 ); // framerate WRITE_BYTE( 2 ); // life WRITE_BYTE( 16 ); // width WRITE_BYTE( 0 ); // noise WriteBeamColor(); WRITE_BYTE( 255 ); //brightness WRITE_BYTE( 0 ); // speed MESSAGE_END(); MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); WRITE_BYTE( TE_BEAMCYLINDER ); WRITE_COORD( pev->origin.x); WRITE_COORD( pev->origin.y); WRITE_COORD( pev->origin.z + 16); WRITE_COORD( pev->origin.x); WRITE_COORD( pev->origin.y); WRITE_COORD( pev->origin.z + 16 + ( HOUNDEYE_MAX_ATTACK_RADIUS / 2 ) / .2); // reach damage radius over .3 seconds WRITE_SHORT( m_iSpriteTexture ); WRITE_BYTE( 0 ); // startframe WRITE_BYTE( 0 ); // framerate WRITE_BYTE( 2 ); // life WRITE_BYTE( 16 ); // width WRITE_BYTE( 0 ); // noise WriteBeamColor(); WRITE_BYTE( 255 ); //brightness WRITE_BYTE( 0 ); // speed MESSAGE_END(); CBaseEntity *pEntity = NULL; // iterate on all entities in the vicinity. while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, HOUNDEYE_MAX_ATTACK_RADIUS )) != NULL) { if ( pEntity->pev->takedamage != DAMAGE_NO ) { if ( !FClassnameIs(pEntity->pev, "monster_houndeye") ) {// houndeyes don't hurt other houndeyes with their attack // houndeyes do FULL damage if the ent in question is visible. Half damage otherwise. // This means that you must get out of the houndeye's attack range entirely to avoid damage. // Calculate full damage first if ( SquadCount() > 1 ) { // squad gets attack bonus. flAdjustedDamage = gSkillData.houndeyeDmgBlast + gSkillData.houndeyeDmgBlast * ( HOUNDEYE_SQUAD_BONUS * ( SquadCount() - 1 ) ); } else { // solo flAdjustedDamage = gSkillData.houndeyeDmgBlast; } flDist = (pEntity->Center() - pev->origin).Length(); flAdjustedDamage -= ( flDist / HOUNDEYE_MAX_ATTACK_RADIUS ) * flAdjustedDamage; if ( !FVisible( pEntity ) ) { if ( pEntity->IsPlayer() ) { // if this entity is a client, and is not in full view, inflict half damage. We do this so that players still // take the residual damage if they don't totally leave the houndeye's effective radius. We restrict it to clients // so that monsters in other parts of the level don't take the damage and get pissed. flAdjustedDamage *= 0.5; } else if ( !FClassnameIs( pEntity->pev, "func_breakable" ) && !FClassnameIs( pEntity->pev, "func_pushable" ) ) { // do not hurt nonclients through walls, but allow damage to be done to breakables flAdjustedDamage = 0; } } //ALERT ( at_aiconsole, "Damage: %f\n", flAdjustedDamage ); if (flAdjustedDamage > 0 ) { pEntity->TakeDamage ( pev, pev, flAdjustedDamage, DMG_SONIC | DMG_ALWAYSGIB ); } } } } }
/* ========================================================= UpdateClientData resends any changed player HUD info to the client. Called every frame by PlayerPreThink Also called at start of demo recording and playback by ForceClientDllUpdate to ensure the demo gets messages reflecting all of the HUD state info. ========================================================= */ void CBasePlayer::UpdateClientData() { if( m_bNeedsNewConnectTime ) { m_bNeedsNewConnectTime = false; m_flConnectTime = gpGlobals->time; } if( !m_bWeaponValidationReceived && m_flConnectTime + WEAPON_VALIDATION_GRACE_TIME < gpGlobals->time ) { //If the client didn't send the message in time, drop the client. - Solokiller //Set it to true to avoid running this multiple times. - Solokiller m_bWeaponValidationReceived = true; UTIL_LogPrintf( "Player \"%s\" didn't send weapon validation in time, disconnecting\n", GetNetName() ); if( !IS_DEDICATED_SERVER() ) { //Listen server hosts usually don't have logging enabled, so echo to console unconditionally for them. - Solokiller UTIL_ServerPrintf( "Player \"%s\" didn't send weapon validation in time, disconnecting\n", GetNetName() ); } if( IS_DEDICATED_SERVER() || entindex() != 1 ) { SERVER_COMMAND( UTIL_VarArgs( "kick \"%s\" \"No weapon validation received\"\n", GetNetName() ) ); } else { //The local player can't be kicked, so terminate the session instead - Solokiller CLIENT_COMMAND( edict(), "disconnect\n" ); } } //The engine will not call ClientPutInServer after transitions, so we'll have to catch this event every map change. - Solokiller if( !m_bSentInitData ) { m_bSentInitData = true; //Update Hud colors. - Solokiller CMap::GetInstance()->SendHudColors( this, true ); } if( m_fInitHUD ) { m_fInitHUD = false; gInitHUD = false; MESSAGE_BEGIN( MSG_ONE, gmsgResetHUD, NULL, this ); WRITE_BYTE( 0 ); MESSAGE_END(); if( !m_fGameHUDInitialized ) { MESSAGE_BEGIN( MSG_ONE, gmsgInitHUD, NULL, this ); MESSAGE_END(); g_pGameRules->InitHUD( this ); m_fGameHUDInitialized = true; m_iObserverLastMode = OBS_ROAMING; if( g_pGameRules->IsMultiplayer() ) { FireTargets( "game_playerjoin", this, this, USE_TOGGLE, 0 ); } } FireTargets( "game_playerspawn", this, this, USE_TOGGLE, 0 ); InitStatusBar(); SendWeatherUpdate(); } if( m_iHideHUD != m_iClientHideHUD ) { MESSAGE_BEGIN( MSG_ONE, gmsgHideWeapon, NULL, this ); WRITE_BYTE( m_iHideHUD ); MESSAGE_END(); m_iClientHideHUD = m_iHideHUD; } if( m_iFOV != m_iClientFOV ) { MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, this ); WRITE_BYTE( m_iFOV ); MESSAGE_END(); // cache FOV change at end of function, so weapon updates can see that FOV has changed } // HACKHACK -- send the message to display the game title if( gDisplayTitle ) { MESSAGE_BEGIN( MSG_ONE, gmsgShowGameTitle, NULL, this ); WRITE_BYTE( 0 ); MESSAGE_END(); gDisplayTitle = false; } if( pev->health != m_iClientHealth ) { int iHealth = clamp( static_cast<int>( pev->health ), 0, 255 ); // make sure that no negative health values are sent if( pev->health > 0.0f && pev->health <= 1.0f ) iHealth = 1; // send "health" update message MESSAGE_BEGIN( MSG_ONE, gmsgHealth, NULL, this ); WRITE_BYTE( iHealth ); MESSAGE_END(); m_iClientHealth = pev->health; } if( pev->armorvalue != m_iClientBattery ) { m_iClientBattery = pev->armorvalue; ASSERT( gmsgBattery > 0 ); // send "health" update message MESSAGE_BEGIN( MSG_ONE, gmsgBattery, NULL, this ); WRITE_SHORT( ( int ) pev->armorvalue ); MESSAGE_END(); } if( pev->dmg_take || pev->dmg_save || m_bitsHUDDamage != m_bitsDamageType ) { // Comes from inside me if not set Vector damageOrigin = GetAbsOrigin(); // send "damage" message // causes screen to flash, and pain compass to show direction of damage edict_t *other = pev->dmg_inflictor; if( other ) { CBaseEntity *pEntity = CBaseEntity::Instance( other ); if( pEntity ) damageOrigin = pEntity->Center(); } // only send down damage type that have hud art int visibleDamageBits = m_bitsDamageType & DMG_SHOWNHUD; MESSAGE_BEGIN( MSG_ONE, gmsgDamage, NULL, this ); WRITE_BYTE( pev->dmg_save ); WRITE_BYTE( pev->dmg_take ); WRITE_LONG( visibleDamageBits ); WRITE_COORD( damageOrigin.x ); WRITE_COORD( damageOrigin.y ); WRITE_COORD( damageOrigin.z ); MESSAGE_END(); //TODO: both of these can probably be removed. - Solokiller pev->dmg_take = 0; pev->dmg_save = 0; m_bitsHUDDamage = m_bitsDamageType; // Clear off non-time-based damage indicators m_bitsDamageType &= DMG_TIMEBASED; } // Update Flashlight if( ( m_flFlashLightTime ) && ( m_flFlashLightTime <= gpGlobals->time ) ) { if( FlashlightIsOn() ) { if( m_iFlashBattery ) { m_flFlashLightTime = FLASH_DRAIN_TIME + gpGlobals->time; m_iFlashBattery--; if( !m_iFlashBattery ) FlashlightTurnOff(); } } else { if( m_iFlashBattery < 100 ) { m_flFlashLightTime = FLASH_CHARGE_TIME + gpGlobals->time; m_iFlashBattery++; } else m_flFlashLightTime = 0; } MESSAGE_BEGIN( MSG_ONE, gmsgFlashBattery, NULL, this ); WRITE_BYTE( m_iFlashBattery ); MESSAGE_END(); } if( m_iTrain & TRAIN_NEW ) { ASSERT( gmsgTrain > 0 ); // send "health" update message MESSAGE_BEGIN( MSG_ONE, gmsgTrain, NULL, this ); WRITE_BYTE( m_iTrain & 0xF ); MESSAGE_END(); m_iTrain &= ~TRAIN_NEW; } SendAmmoUpdate(); // Update all the items for( int i = 0; i < MAX_WEAPON_SLOTS; i++ ) { if( m_rgpPlayerItems[ i ] ) // each item updates it's successors m_rgpPlayerItems[ i ]->UpdateClientData( this ); } // Cache and client weapon change m_pClientActiveItem = m_pActiveItem; m_iClientFOV = m_iFOV; // Update Status Bar if( m_flNextSBarUpdateTime < gpGlobals->time ) { UpdateStatusBar(); m_flNextSBarUpdateTime = gpGlobals->time + 0.2; } }
// The damage is coming from inflictor, but get mad at attacker // This should be the only function that ever reduces health. // bitsDamageType indicates the type of damage sustained, ie: DMG_SHOCK // // Time-based damage: only occurs while the monster is within the trigger_hurt. // When a monster is poisoned via an arrow etc it takes all the poison damage at once. int CBaseMonster::__MAKE_VHOOK(TakeDamage)(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) { if (pev->takedamage == DAMAGE_NO) return 0; if (!IsAlive()) { return DeadTakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); } if (pev->deadflag == DEAD_NO) { // no pain sound during death animation. PainSound(); } // LATER: make armor consideration here! float flTake = flDamage; // set damage type sustained m_bitsDamageType |= bitsDamageType; // grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit). Vector vecDir(0, 0, 0); if (!FNullEnt(pevInflictor)) { CBaseEntity *pInflictor = CBaseEntity::Instance(pevInflictor); if (pInflictor) { #ifndef PLAY_GAMEDLL vecDir = (pInflictor->Center() - Vector(0, 0, 10) - Center()).Normalize(); #else // TODO: fix test demo vecDir = NormalizeSubtract< float_precision, float, float_precision, float_precision >(Center(), pInflictor->Center() - Vector(0, 0, 10)); #endif vecDir = g_vecAttackDir = vecDir.Normalize(); } } // add to the damage total for clients, which will be sent as a single // message at the end of the frame // TODO: remove after combining shotgun blasts? if (IsPlayer()) { if (pevInflictor) { pev->dmg_inflictor = ENT(pevInflictor); } pev->dmg_take += flTake; } pev->health -= flTake; if (m_MonsterState == MONSTERSTATE_SCRIPT) { SetConditions(bits_COND_LIGHT_DAMAGE); return 0; } if (pev->health <= 0.0f) { g_pevLastInflictor = pevInflictor; if (bitsDamageType & DMG_ALWAYSGIB) Killed(pevAttacker, GIB_ALWAYS); else if (bitsDamageType & DMG_NEVERGIB) Killed(pevAttacker, GIB_NEVER); else Killed(pevAttacker, GIB_NORMAL); g_pevLastInflictor = NULL; return 0; } if ((pev->flags & FL_MONSTER) && !FNullEnt(pevAttacker)) { if (pevAttacker->flags & (FL_MONSTER | FL_CLIENT)) { if (pevInflictor) { if (m_hEnemy == NULL || pevInflictor == m_hEnemy->pev || !HasConditions(bits_COND_SEE_ENEMY)) m_vecEnemyLKP = pevInflictor->origin; } else { m_vecEnemyLKP = pev->origin + (g_vecAttackDir * 64); } MakeIdealYaw(m_vecEnemyLKP); if (flDamage > 20.0f) { SetConditions(bits_COND_LIGHT_DAMAGE); } if (flDamage >= 20.0f) { SetConditions(bits_COND_HEAVY_DAMAGE); } } } return 1; }
void RadiusDamage(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, float flRadius, int iClassIgnore, int bitsDamageType) { CBaseEntity *pEntity = NULL; TraceResult tr; float flAdjustedDamage, falloff; Vector vecSpot; if (flRadius) falloff = flDamage / flRadius; else falloff = 1.0; int bInWater = (UTIL_PointContents(vecSrc) == CONTENTS_WATER); // in case grenade is lying on the ground vecSrc.z += 1; if (!pevAttacker) pevAttacker = pevInflictor; // iterate on all entities in the vicinity. while ((pEntity = UTIL_FindEntityInSphere(pEntity, vecSrc, flRadius)) != NULL) { if (pEntity->pev->takedamage != DAMAGE_NO) { // UNDONE: this should check a damage mask, not an ignore if (iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore) continue; // blast's don't tavel into or out of water if (bInWater && pEntity->pev->waterlevel == 0) continue; if (!bInWater && pEntity->pev->waterlevel == 3) continue; bool useLOS = false; float damageRatio = 1.0f; if ((bitsDamageType & DMG_EXPLOSION) && g_bIsCzeroGame) { useLOS = true; damageRatio = GetAmountOfPlayerVisible(vecSrc, pEntity); } damageRatio = GetAmountOfPlayerVisible(vecSrc, pEntity); float length; #ifdef REGAMEDLL_ADD // allow to damage breakable objects if (FClassnameIs(pEntity->pev, "func_breakable")) length = (vecSrc - pEntity->Center()).Length(); else #endif length = (vecSrc - pEntity->pev->origin).Length(); if (useLOS) { if (!flRadius) flRadius = flDamage; if (!flDamage) flRadius = 0; flAdjustedDamage = (flRadius - length) * (flRadius - length) * 1.25 / (flRadius * flRadius) * (damageRatio * flDamage) * 1.5; } else { flAdjustedDamage = flDamage - length * falloff; #ifdef REGAMEDLL_ADD // disable grenade damage through walls? if (hegrenade_penetration.string[0] == '1' && (bitsDamageType & DMG_EXPLOSION)) { UTIL_TraceLine(vecSrc, pEntity->pev->origin, ignore_monsters, NULL, &tr); if (tr.flFraction != 1.0f) flAdjustedDamage = 0.0f; } #endif } #ifdef REGAMEDLL_FIXES // not allow inflict to the player damage is less than 1.0f and to entities not less than 0.0f if ((pEntity->Classify() == CLASS_PLAYER && flAdjustedDamage < 1.0f) || flAdjustedDamage <= 0.0f) continue; #else if (flAdjustedDamage < 0) flAdjustedDamage = 0; #endif pEntity->TakeDamage(pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType); } } }
void CElite::SendShine( void ) { UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); Vector vecSrc = m_pPlayer->GetGunPosition( ); // + gpGlobals->v_up * -8 + gpGlobals->v_right * 8; Vector vecDir = gpGlobals->v_forward; Vector vecDest = vecSrc + gpGlobals->v_up * 200;//-100 edict_t *pentIgnore; TraceResult tr; pentIgnore = m_pPlayer->edict(); UTIL_TraceLine(vecSrc, vecDest, dont_ignore_monsters, pentIgnore, &tr); /* //UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,64), ignore_monsters, edict(), &tr ); Vector vecSpot; TraceResult tr; vecSpot = pev->origin + Vector ( 0 , 0 , 8 );//move up a bit, and trace down. UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, 4096 ), ignore_monsters, pentIgnore, & tr); */ if (tr.flFraction != 1.0) // != 1.0)// Hemos tocado algo { CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); float flDist = (pEntity->Center() - pev->origin).Length(); if ( pEntity->IsBSPModel() ) { // ALERT ( at_console, "I touch something! %f\n", tr.flFraction ); pev->skin = 0; } else { // ALERT ( at_console, "Is not a BSP model %f\n", tr.flFraction ); } } else { // ALERT ( at_console, "Im seeing the sky! %f\n", tr.flFraction ); pev->skin = 1; } /* extern short g_sModelIndexLaser; MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_BEAMPOINTS ); WRITE_COORD( vecSrc.x ); WRITE_COORD( vecSrc.y ); WRITE_COORD( vecSrc.z ); WRITE_COORD( vecDest.x ); WRITE_COORD( vecDest.y ); WRITE_COORD( vecDest.z ); WRITE_SHORT( g_sModelIndexLaser ); WRITE_BYTE( 0 ); // framerate WRITE_BYTE( 0 ); // framerate WRITE_BYTE( 1 ); // life WRITE_BYTE( 1 ); // width WRITE_BYTE( 0 ); // noise WRITE_BYTE( 255 ); // r, g, b WRITE_BYTE( 255 ); // r, g, b WRITE_BYTE( 255 ); // r, g, b WRITE_BYTE( 255 ); // brightness WRITE_BYTE( 111 ); // speed MESSAGE_END(); */ /* MESSAGE_BEGIN( MSG_ONE, gmsgSetSkin, NULL, m_pPlayer->pev ); WRITE_BYTE( pev->skin ); //weaponmodel skin. MESSAGE_END(); */ }
void AvHHealingSpray::FireProjectiles(void) { #ifdef AVH_SERVER // Look for entities in cone CBaseEntity* theCurrentEntity = NULL; vec3_t theOriginatingPosition = this->m_pPlayer->GetGunPosition(); while((theCurrentEntity = UTIL_FindEntityInSphere(theCurrentEntity, theOriginatingPosition, kHealingSprayRange)) != NULL) { bool isSelf=(theCurrentEntity == this->m_pPlayer); // Can't affect self // if(theCurrentEntity != this->m_pPlayer) // { // If entity is in view cone, and within range if(isSelf || this->m_pPlayer->FInViewCone(&theCurrentEntity->pev->origin) ) { // UTIL_FindEntityInSphere doesn't seem to take height into account. Make sure the entity is within range. float theMaxEntitySize = max(Length(theCurrentEntity->pev->mins), Length(theCurrentEntity->pev->maxs)); vec3_t theVectorDiff; VectorSubtract(theCurrentEntity->pev->origin, theOriginatingPosition, theVectorDiff); float theDiff = Length(theVectorDiff) - theMaxEntitySize; if(theDiff < kHealingSprayRange/2) { // Make sure entity is in line of fire TraceResult tr; UTIL_TraceLine(theOriginatingPosition, theCurrentEntity->Center(), dont_ignore_monsters, dont_ignore_glass, ENT(pev)/*pentIgnore*/, &tr); CBaseEntity* theBlockedByEntity = CBaseEntity::Instance(tr.pHit); if((tr.flFraction == 1.0) || (theBlockedByEntity == theCurrentEntity)) { // Heal friendly player or building in range float theFocusAmount = 1.0f; if(AvHSHUGetIsWeaponFocusable(AvHWeaponID(this->m_iId))) { theFocusAmount = AvHPlayerUpgrade::GetFocusDamageUpgrade(this->m_pPlayer->pev->iuser4); } float theDamage = this->mDamage*theFocusAmount; AvHPlayer* thePlayer = dynamic_cast<AvHPlayer*>(theCurrentEntity); if(theCurrentEntity->pev->team == this->m_pPlayer->pev->team) { // Players and buildables heal armor too AvHBaseBuildable* theBuildable = dynamic_cast<AvHBaseBuildable*>(theCurrentEntity); const int theBuildableHealingSprayScalar = BALANCE_VAR(kHealingSprayBuildableScalar); if(thePlayer) { // Players heal by base amount, plus percentage of health float thePercentage = BALANCE_VAR(kHealingSprayPlayerPercent)/100.0f; theDamage += thePercentage*theCurrentEntity->pev->max_health; if ( isSelf ) theDamage *= 0.5f; thePlayer->Heal(theDamage, true); } else if(theBuildable) { // Structures heal base amount times scalar float theAmount = theDamage*(float)theBuildableHealingSprayScalar; if(theBuildable->Regenerate(theAmount, true)) { // Award experience for healing the hive. Might award a little more if barely wounded, but that seems OK. if(GetGameRules()->GetIsCombatMode() && (theBuildable->pev->iuser3 == AVH_USER3_HIVE)) { AvHPlayer* theHealsprayingPlayer = dynamic_cast<AvHPlayer*>(this->m_pPlayer); if(theHealsprayingPlayer && (theHealsprayingPlayer->pev->team == theBuildable->pev->team)) { float theCombatHealExperienceScalar = BALANCE_VAR(kCombatHealExperienceScalar); theHealsprayingPlayer->AwardExperienceForObjective(theAmount*theCombatHealExperienceScalar, theBuildable->GetMessageID()); } } } } else { theCurrentEntity->TakeHealth(theDamage, this->GetDamageType()); } } else if(thePlayer) { thePlayer->TakeDamage(this->pev, this->m_pPlayer->pev, theDamage, this->GetDamageType()); } } } } // } } #endif }
void CGrappleHook::Move( void ) { // Fograin92: If owner (player) is dead if( !myowner->IsAlive() ) { Killed(pev, 0); // Remove tongue instantly return; } // Fograin92: Player isn't holding attack buttons if( !(myowner->pev->button & (IN_ATTACK|IN_ATTACK2)) ) { bPullBack = true; // Fograin92: We should pull the tongue back } // Fograin92: Animate pull-back tongue animation ONLY if we didn't hit a monster if(bPullBack) { UTIL_MakeVectors( myowner->pev->v_angle + myowner->pev->punchangle ); Vector GunPosition = myowner->GetGunPosition(); GunPosition = GunPosition + gpGlobals->v_up * -4 + gpGlobals->v_right * 3 + gpGlobals->v_forward * 6; pev->velocity = (GunPosition - pev->origin) * 10; // Pull back the tongue tip float fDistance = (GunPosition - pev->origin).Length2D(); // Calculate distance between tongue tip and player //ALERT( at_console, "^2HLU -> ^3weapon_grapple ^2-> %f\n", fDistance ); if (fDistance < 40) { Killed(pev, 0); return; } } else { // Fograin92: We did hit a monster if(m_iHitMonster > 0) { // Fograin92: Let's "stick" grapple tongue XYZ to target's center XYZ pev->origin = myHitMonster->Center(); // Fograin92: We did hit tiny monster, let's pull it if(m_iHitMonster == 2) { myHitMonster->pev->movetype = MOVETYPE_FLY; // Remove gravity effect on our pulled monster myHitMonster->pev->velocity = (myowner->pev->origin - myHitMonster->pev->origin) * 4; // Pull our monster } // Fograin92: Check distance (player <-> monster) float fDistance = (myowner->pev->origin - myHitMonster->pev->origin).Length2D(); // Fograin92: The monster is very close to player, let's OWN IT! if (fDistance < 40) { ALERT( at_console, "^2HLU -> ^3weapon_grapple ^2-> OWNED -> ^3%s\n", STRING(myHitMonster->pev->classname) ); // Fograin92: Did we pull the gib? if( myHitMonster->Classify() == CLASS_GIBS ) myHitMonster->SUB_Remove(); else myHitMonster->TakeDamage(myHitMonster->pev, myowner->pev, 10000, DMG_GENERIC); Killed(pev, 0); // Fograin92: Target died, kill tongue } } } // Fograin92: If tongue (beam) exists if( m_pTongue ) { UTIL_MakeVectors( myowner->pev->v_angle + myowner->pev->punchangle ); Vector GunPosition = myowner->GetGunPosition(); GunPosition = GunPosition + gpGlobals->v_up * -4 + gpGlobals->v_right * 3 + gpGlobals->v_forward * 6; m_pTongue->PointEntInit( GunPosition, this->entindex() ); } else { // Fograin92: Create tongue (beam) m_pTongue = CBeam::BeamCreate( "sprites/_tongue.spr", 8 ); m_pTongue->SetFlags( 0x20 ); // Solid beam m_pTongue->SetColor( 100, 100, 100 ); m_pTongue->SetScrollRate( 20 ); } pev->nextthink = gpGlobals->time + 0.01; }
//========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. // // Returns number of events handled, 0 if none. //========================================================= void CISlave :: HandleAnimEvent( MonsterEvent_t *pEvent ) { // ALERT( at_console, "event %d : %f\n", pEvent->event, pev->frame ); switch( pEvent->event ) { case ISLAVE_AE_CLAW: { // SOUND HERE! CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.slaveDmgClaw, DMG_SLASH ); if ( pHurt ) { if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) { pHurt->pev->punchangle.z = -18; pHurt->pev->punchangle.x = 5; } // Play a random attack hit sound EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); } else { // Play a random attack miss sound EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); } } break; case ISLAVE_AE_CLAWRAKE: { CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.slaveDmgClawrake, DMG_SLASH ); if ( pHurt ) { if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) { pHurt->pev->punchangle.z = -18; pHurt->pev->punchangle.x = 5; } EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); } else { EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); } } break; case ISLAVE_AE_ZAP_POWERUP: { // speed up attack when on hard if (g_iSkillLevel == SKILL_HARD) pev->framerate = 1.5; UTIL_MakeAimVectors( pev->angles ); if (m_iBeams == 0) { Vector vecSrc = pev->origin + gpGlobals->v_forward * 2; MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); WRITE_BYTE(TE_DLIGHT); WRITE_COORD(vecSrc.x); // X WRITE_COORD(vecSrc.y); // Y WRITE_COORD(vecSrc.z); // Z WRITE_BYTE( 12 ); // radius * 0.1 WRITE_BYTE( 255 ); // r WRITE_BYTE( 180 ); // g WRITE_BYTE( 96 ); // b WRITE_BYTE( 20 / pev->framerate ); // time * 10 WRITE_BYTE( 0 ); // decay * 0.1 MESSAGE_END( ); } if (m_hDead != NULL) { WackBeam( -1, m_hDead ); WackBeam( 1, m_hDead ); } else { ArmBeam( -1 ); ArmBeam( 1 ); BeamGlow( ); } EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0, 100 + m_iBeams * 10 ); pev->skin = m_iBeams / 2; } break; case ISLAVE_AE_ZAP_SHOOT: { ClearBeams( ); if (m_hDead != NULL) { Vector vecDest = m_hDead->pev->origin + Vector( 0, 0, 38 ); TraceResult trace; UTIL_TraceHull( vecDest, vecDest, dont_ignore_monsters, human_hull, m_hDead->edict(), &trace ); if ( !trace.fStartSolid ) { CBaseEntity *pNew = Create( "monster_alien_slave", m_hDead->pev->origin, m_hDead->pev->angles ); CBaseMonster *pNewMonster = pNew->MyMonsterPointer( ); pNew->pev->spawnflags |= 1; //sys test //pNew->pev->rendermode = kRenderTransTexture; pNew->pev->rendermode = kRenderNormal; pNew->pev->renderamt = 100; pNew->pev->renderfx = 19; //pev->rendercolor.x = r; //pev->rendercolor.y = g; //pev->rendercolor.z = b; pNew->pev->rendercolor.x = 50; pNew->pev->rendercolor.y = 255; pNew->pev->rendercolor.z = 50; pNew->pev->health = gSkillData.slaveHealth /2; WackBeam( -1, pNew ); WackBeam( 1, pNew ); UTIL_Remove( m_hDead ); // EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "hassault/hw_shoot1.wav", 1, ATTN_NORM, 0, RANDOM_LONG( 130, 160 ) ); EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0, 100 + m_iBeams * 10 ); // if ( mp_am_movecorpses.value != 0 ) //no es cero esta _Activado_ // { CBaseEntity *pEffect = Create( "test_effect", pNew->Center(), pev->angles ); pEffect->Use( this, this, USE_ON, 1 ); CBaseEntity *pEffect2 = Create( "env_teleport", pNew->Center(), pev->angles ); pEffect2->Use( this, this, USE_ON, 1 ); // } break; } } ClearMultiDamage(); UTIL_MakeAimVectors( pev->angles ); ZapBeam( -1 ); ZapBeam( 1 ); EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "hassault/hw_shoot1.wav", 1, ATTN_NORM, 0, RANDOM_LONG( 130, 160 ) ); // STOP_SOUND( ENT(pev), CHAN_WEAPON, "debris/zap4.wav" ); ApplyMultiDamage(pev, pev); m_flNextAttack = gpGlobals->time + RANDOM_FLOAT( 0.5, 4.0 ); } break; case ISLAVE_AE_ZAP_DONE: { ClearBeams( ); } break; default: CSquadMonster::HandleAnimEvent( pEvent ); break; } }