#include "MW4Headers.hpp" #include "MWDamageObject.hpp" #include "Subsystem.hpp" #include "MWObject.hpp" #include "Weapon.hpp" #include "MWApplication.hpp" #include "DamageDispatch.hpp" #include "bucket.hpp" #include "MWMission.hpp" #include "windows.h" #include "recscore.h" // jcem //############################################################################# //########################### MWInternalDamageObject ##################### //############################################################################# extern int g_nMR; MWInternalDamageObject::ClassData* MWInternalDamageObject::DefaultData = NULL; void MechWarrior4::MW4DamageSecurityCheckStart() { _asm { nop } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MWInternalDamageObject::InitializeClass() { Verify(!DefaultData); DefaultData = new ClassData( MWInternalDamageObjectClassID, "MechWarrior4::MWInternalDamageObject", InternalDamageObject::DefaultData, 0, NULL ); Register_Object(DefaultData); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MWInternalDamageObject::TerminateClass() { Unregister_Object(DefaultData); delete DefaultData; DefaultData = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MWInternalDamageObject::MWInternalDamageObject( ClassData *class_data, MemoryStream *stream ): InternalDamageObject(class_data, stream), // MSL 5.02 headshot destroyedSubsystemChain(NULL), subsystemChain(NULL) { Check_Pointer(this); Check_Object(stream); *stream >> m_maxMissileSlots; *stream >> m_maxProjectileSlots; *stream >> m_maxBeamSlots; *stream >> m_maxOmniSlots; m_missileSlotsAvailable = m_maxMissileSlots; m_projectileSlotsAvailable = m_maxProjectileSlots; m_beamSlotsAvailable = m_maxBeamSlots; m_omniSlotsAvailable = m_maxOmniSlots; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MWInternalDamageObject::ConstructMWInternalDamageObjectStream( MemoryStream *stream, Page *instance_page ) { Check_Object(instance_page); InternalDamageObject::ConstructInternalDamageObjectStream( stream, instance_page, DefaultData->GetClassID() ); int slots = 0; instance_page->GetEntry("MissileSlots", &slots); *stream << slots; slots = 0; instance_page->GetEntry("ProjectileSlots", &slots); *stream << slots; slots = 0; instance_page->GetEntry("BeamSlots", &slots); *stream << slots; slots = 0; instance_page->GetEntry("OmniSlots", &slots); *stream << slots; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void* MWInternalDamageObject::operator new(size_t size) { /* gos_PushCurrentHeap(Adept::g_DamageObjectHeap); void *temp = ::new(size_t); gos_PopCurrentHeap(); return temp; */ return gos_Malloc(size,Adept::g_DamageObjectHeap); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MWInternalDamageObject::Save(MemoryStream *stream) { Check_Object(this); InternalDamageObject::Save(stream, DefaultData->GetClassID()); *stream << m_maxMissileSlots; *stream << m_maxProjectileSlots; *stream << m_maxBeamSlots; *stream << m_maxOmniSlots; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MWInternalDamageObject::~MWInternalDamageObject() { } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int MWInternalDamageObject::AddSubsystem(Subsystem *subsystem) { Check_Object(this); Check_Object(subsystem); int result = VerifySubsystem(subsystem); if(result) subsystemChain.Add(subsystem); return result; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Subsystem* MWInternalDamageObject::GetSubsystem(int type) { Check_Object(this); ChainIteratorOf iterator(&subsystemChain); Subsystem *subsystem; while((subsystem = iterator.ReadAndNext()) != NULL) { Check_Object(subsystem); const Subsystem::GameModel *model = subsystem->GetGameModel(); Check_Object(model); if(model->itemID == type) return subsystem; } return NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int MWInternalDamageObject::VerifySubsystem(Subsystem *subsystem) { Check_Object(this); Check_Object(subsystem); const Subsystem::GameModel *model = subsystem->GetGameModel(); subsystem->containedInSlotType = DoesHaveAvailableSlots(model->slotType, model->totalSlotsTaken); return subsystem->containedInSlotType >= -1; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int MWInternalDamageObject::DoesHaveAvailableSlots(int slot_type, int slots_needed, bool check_omni, bool subtract_slot) { Check_Object(this); switch(slot_type) { case -1: return -1; break; case MissileSlotType: if((m_missileSlotsAvailable - slots_needed) >= 0) { if(subtract_slot) m_missileSlotsAvailable -= slots_needed; return MissileSlotType; } break; case ProjectileSlotType: if((m_projectileSlotsAvailable - slots_needed) >= 0) { if(subtract_slot) m_projectileSlotsAvailable -= slots_needed; return ProjectileSlotType; } break; case BeamSlotType: if((m_beamSlotsAvailable - slots_needed) >= 0) { if(subtract_slot) m_beamSlotsAvailable -= slots_needed; return BeamSlotType; } break; case OmniSlotType: if((m_omniSlotsAvailable - slots_needed) >= 0) { if(subtract_slot) m_omniSlotsAvailable -= slots_needed; return OmniSlotType; } break; } if(check_omni) { if((m_omniSlotsAvailable - slots_needed) >= 0) { if(subtract_slot) m_omniSlotsAvailable -= slots_needed; return OmniSlotType; } } return -2; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MWInternalDamageObject::FreeAvailableSlots(int slot_type, int num) { Check_Object(this); switch(slot_type) { case MissileSlotType: m_missileSlotsAvailable += num; break; case ProjectileSlotType: m_projectileSlotsAvailable += num; break; case BeamSlotType: m_beamSlotsAvailable += num; break; case OmniSlotType: m_omniSlotsAvailable += num; break; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int MWInternalDamageObject::RollCriticalHit() { Check_Object(this); int roll = Stuff::Random::GetLessThan(100); if(roll <= 70) return 0; else if(roll >= 97) return 3; else if(roll >= 90) return 2; else return 1; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MWInternalDamageObject::InflictCriticalHit() { Check_Object(this); DamageDispatch *dispatch = DamageDispatch::GetInstance(); Check_Pointer(dispatch); dispatch->InflictCriticalHit(*this); } void MWInternalDamageObject::_InflictCriticalHit() { Check_Object(this); // //--------------------------------- //Get Number of Critical Hits taken //--------------------------------- // int num_crit_hits = RollCriticalHit(); ChainIteratorOf iterator(&subsystemChain); for(int i=0; i 0) { int roll = Stuff::Random::GetLessThan(iterator.GetSize()); Subsystem *subsystem = iterator.GetNth(roll); Check_Object(subsystem); bool does_destroy = subsystem->TakeCriticalHit(); if(does_destroy) { g_RSF.RecScore(CBucketManager::COMPONENT_DEATHS, ReplicatorID::Null, ReplicatorID::Null, 0, 0, (DWORD)subsystem); // jcem // MSL 5.02 headshot destroyedSubsystemChain.Add(subsystem); // So we can later completely remove the subsystem subsystemChain.Remove(subsystem); } } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Scalar MWInternalDamageObject::TakeDamage(Scalar damage_taken, Entity__TakeDamageMessage *message) { Check_Object(this); DamageDispatch *dispatch = DamageDispatch::GetInstance(); Check_Pointer(dispatch); return (dispatch->TakeDamage(*this,damage_taken,message)); } Scalar MWInternalDamageObject::_TakeDamage(Scalar damage_taken, Entity__TakeDamageMessage *message) { Check_Object(this); if (g_nMR == 2) { return InternalDamageObject::TakeDamage(damage_taken, message); } int prev_num_subsystems = subsystemChain.GetSize(); Scalar rv = InternalDamageObject::TakeDamage(damage_taken, message); if (Network::GetInstance()->AmIServer()) { if(currentInternalDamage <= 0.0f) { KillAllContainedSubsystems(); } } const int num_subsystems = subsystemChain.GetSize(); if (num_subsystems < prev_num_subsystems) { MWApplication* mwapplication = Cast_Object(MWApplication*,MWApplication::GetInstance()); if (mwapplication->networkingFlag == false) { if (!mwapplication->IsCampCOOP()) return (rv); } MWMission *mission = Cast_Object(MWMission*,MWMission::GetInstance()); if ((mission == 0) || (mission->m_BucketManager == 0)) { return (rv); } Adept::ReplicatorID me = parentEntity->GetReplicatorID(); const Adept::ReplicatorID& attacker = message->inflictingEntityID; int num_subsystems_destroyed = prev_num_subsystems - num_subsystems; if (num_subsystems_destroyed > 0) { MWMover *mover = Cast_Object(MWMover*, parentEntity); Check_Object(mover); if (mover->GetParentVehicle() && mover->GetParentVehicle()->IsDerivedFrom(Mech::DefaultData)) { Mech *mech = Cast_Object(Mech *,mover->GetParentVehicle()); if (mech->IsDestroyed() == true) { return (rv); } me = mech->GetReplicatorID(); } if(mover->GetParentVehicle() && mover->GetParentVehicle()->GetClassID() == MechClassID) { mission->m_BucketManager->NotifyAction(CBucketManager::COMPONENT_KILLS,attacker,num_subsystems_destroyed); g_RSF.RecScore(CBucketManager::COMPONENT_KILLS, attacker, me, 0, 0, num_subsystems_destroyed); // jcem mission->m_BucketManager->NotifyAction(CBucketManager::COMPONENT_DEATHS,me,num_subsystems_destroyed); if (mwapplication->TeamsAreFriendly(me,attacker) == true) { mission->m_BucketManager->NotifyAction(CBucketManager::FRIENDLY_COMPONENT_KILLS,attacker,num_subsystems_destroyed,me); mission->m_BucketManager->NotifyAction(CBucketManager::FRIENDLY_COMPONENT_DEATHS,me,num_subsystems_destroyed); } else { mission->m_BucketManager->NotifyAction(CBucketManager::ENEMY_COMPONENT_KILLS,attacker,num_subsystems_destroyed,me); mission->m_BucketManager->NotifyAction(CBucketManager::ENEMY_COMPONENT_DEATHS,me,num_subsystems_destroyed); } } #if !defined(NO_LOG) // ngLog addition int self = parentEntity->GetReplicatorID().connectionID; int inflictor = message->inflictingEntityID.connectionID; if(self >= 0 && inflictor >= 0) { MWMover *mobj = Cast_Object(MWMover *, parentEntity); Check_Object(mobj); if(mobj && mobj->GetParentVehicle() && mobj->GetParentVehicle()->IsDerivedFrom(Mech::DefaultData)) { Mech *mech = Cast_Object(Mech *, mobj->GetParentVehicle()); if(mech && mech->IsLanceMate()) { self = mech->lancemateIndex + Maximum_Players; } } // Check for local bots, weeding out stuff like buildings, tanks, etc. Replicator *r = NULL; Connection *conn = NULL; // Check if inflictor is a bot if(inflictor == Connection::Server->GetID()) { conn = Network::GetInstance()->GetConnection(message->inflictingEntityID.connectionID); if(conn) { r = conn->FindReplicator(message->inflictingEntityID); if(r && r->GetClassID() == MechClassID) { Mech *inflict = Cast_Object(Mech *, r); if(inflict && inflict->IsLanceMate()) { inflictor = inflict->lancemateIndex + Maximum_Players; } } } } MWApplication *app = MWApplication::GetInstance(); if(self >= Maximum_Players) { app->lancemateConnectionData[self-Maximum_Players].comp_rcv[inflictor] += num_subsystems_destroyed; app->lancemateConnectionData[self-Maximum_Players].stats_update = 1; } else { app->servedConnectionData[self].comp_rcv[inflictor] += num_subsystems_destroyed; app->servedConnectionData[self].stats_update = 1; } if(inflictor >= Maximum_Players) { app->lancemateConnectionData[inflictor-Maximum_Players].comp_inf[self] += num_subsystems_destroyed; app->lancemateConnectionData[inflictor-Maximum_Players].stats_update = 1; } else { app->servedConnectionData[inflictor].comp_inf[self] += num_subsystems_destroyed; app->servedConnectionData[inflictor].stats_update = 1; } } #endif // !defined(NO_LOG) } } return (rv); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MWInternalDamageObject::KillAllContainedSubsystems() { Check_Object(this); DamageDispatch *dispatch = DamageDispatch::GetInstance(); Check_Pointer(dispatch); dispatch->KillAllContainedSubsystems(*this); } void MWInternalDamageObject::_KillAllContainedSubsystems() { ChainIteratorOf iterator(&subsystemChain); Subsystem *subsystem; while((subsystem = iterator.ReadAndNext()) != NULL) { Check_Object(subsystem); bool does_destroy = subsystem->TakeCriticalHit(); if(does_destroy) { g_RSF.RecScore(CBucketManager::COMPONENT_DEATHS, ReplicatorID::Null, ReplicatorID::Null, 0, 0, (DWORD)subsystem); // MSL 5.02 headshot destroyedSubsystemChain.Add(subsystem); // So we can later completely remove the subsystem subsystemChain.Remove(subsystem); } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MWInternalDamageObject::TestInstance() const { Verify(IsDerivedFrom(DefaultData)); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // const char* MWInternalDamageObject::SlotTypeAsciiToText(int slot_type) { switch(slot_type) { case MissileSlotType: return "MissileSlot"; case ProjectileSlotType: return "ProjectileSlot"; case BeamSlotType: return "BeamSlot"; case OmniSlotType: return "OmniSlot"; } PAUSE(("That is a bad slot value")); return "Bad"; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int MWInternalDamageObject::SlotTypeTextToAscii(const char *slot_type_string) { if(!_stricmp(slot_type_string, "MissileSlot")) return MissileSlotType; if(!_stricmp(slot_type_string, "ProjectileSlot")) return ProjectileSlotType; if(!_stricmp(slot_type_string, "BeamSlot")) return BeamSlotType; if(!_stricmp(slot_type_string, "OmniSlot")) return OmniSlotType; PAUSE(("That is a bad Slot Type String: %s", slot_type_string)); return -1; } void MechWarrior4::MW4DamageSecurityCheckStop() { _asm { nop } }