diff --git a/Plugins/Public/base_plugin/ClientCommands.cpp b/Plugins/Public/base_plugin/ClientCommands.cpp index 1a22a2890..c7cb2b1cb 100644 --- a/Plugins/Public/base_plugin/ClientCommands.cpp +++ b/Plugins/Public/base_plugin/ClientCommands.cpp @@ -191,7 +191,13 @@ void SendBaseStatus(uint client, PlayerBase* base) { base_status += L"Hit Points: Indestructible"; } - base_status += L"Population: " + Int64ToPrettyStr((INT64)base->HasMarketItem(set_base_crew_type)) + L""; + uint population = 0; + for (uint hash : humanCargoList) + { + population += base->HasMarketItem(hash); + } + base_status += L"Crew: " + Int64ToPrettyStr((INT64)base->HasMarketItem(set_base_crew_type)) + L""; + base_status += L"Total population: " + Int64ToPrettyStr((INT64)population) + L""; if (single_vulnerability_window) { diff --git a/Plugins/Public/base_plugin/CoreModule.cpp b/Plugins/Public/base_plugin/CoreModule.cpp index 42d0978a2..142b58828 100644 --- a/Plugins/Public/base_plugin/CoreModule.cpp +++ b/Plugins/Public/base_plugin/CoreModule.cpp @@ -13,7 +13,7 @@ #include CoreModule::CoreModule(PlayerBase* the_base) : Module(TYPE_CORE), base(the_base), space_obj(0), dont_eat(false), -dont_rust(false) +dont_rust(false), wasDamagedSinceLastUpdate(false), undergoingDestruction(false) { } @@ -132,6 +132,9 @@ void CoreModule::Spawn() pub::SpaceObj::SetRelativeHealth(space_obj, base->base_health / base->max_base_health); + base->baseCSolar = (CSolar*)CObject::Find(space_obj, CObject::CSOLAR_OBJECT); + base->baseCSolar->Release(); + if (shield_reinforcement_threshold_map.count(base->base_level)) base->base_shield_reinforcement_threshold = shield_reinforcement_threshold_map[base->base_level]; else @@ -248,13 +251,6 @@ bool CoreModule::Timer(uint time) return false; } - // if health is 0 then the object will be destroyed but we won't - // receive a notification of this so emulate it. - if (base->base_health < 1) - { - return SpaceObjDestroyed(space_obj); - } - if ((base->logic == 0) && (base->invulnerable == 1)) { return false; @@ -269,7 +265,7 @@ bool CoreModule::Timer(uint time) float no_crew_penalty = isCrewSufficient ? 1.0f : no_crew_damage_multiplier; // Reduce hitpoints to reflect wear and tear. This will eventually // destroy the base unless it is able to repair itself. - float damage_taken = (set_damage_per_tick * base->base_level) * no_crew_penalty; + float damage_taken = set_damage_per_tick * no_crew_penalty; base->base_health -= damage_taken; } @@ -287,6 +283,7 @@ bool CoreModule::Timer(uint time) else if (base->base_health <= 0) { base->base_health = 0; + return SpaceObjDestroyed(space_obj); } pub::SpaceObj::SetRelativeHealth(space_obj, base->base_health / base->max_base_health); @@ -351,7 +348,12 @@ bool CoreModule::Timer(uint time) float CoreModule::SpaceObjDamaged(uint space_obj, uint attacking_space_obj, float curr_hitpoints, float new_hitpoints) { - base->SpaceObjDamaged(space_obj, attacking_space_obj, curr_hitpoints, new_hitpoints); + base->shield_timeout = time(nullptr) + 60; + if (!base->isShieldOn) + { + base->isShieldOn = true; + EnableShieldFuse(true); + } if (!base->vulnerableWindowStatus || base->invulnerable == 1 || base->shield_strength_multiplier >= 1.0f) { @@ -386,14 +388,25 @@ float CoreModule::SpaceObjDamaged(uint space_obj, uint attacking_space_obj, floa base->shield_strength_multiplier += shield_reinforcement_increment; } - base->base_health -= damageTaken; - return curr_hitpoints - damageTaken; + if (!wasDamagedSinceLastUpdate) + { + base->baseCSolar->set_hit_pts(base->base_health); + wasDamagedSinceLastUpdate = true; + } + + float newHealth = max(0, curr_hitpoints - damageTaken); + + base->SpaceObjDamaged(space_obj, attacking_space_obj, curr_hitpoints, newHealth); + + base->base_health = newHealth; + return newHealth; } bool CoreModule::SpaceObjDestroyed(uint space_obj, bool moveFile, bool broadcastDeath) { - if (this->space_obj == space_obj) + if (this->space_obj == space_obj && !undergoingDestruction) { + undergoingDestruction = true; if (set_plugin_debug > 1) ConPrint(L"CoreModule::destroyed space_obj=%u\n", space_obj); pub::SpaceObj::LightFuse(space_obj, "player_base_explode_fuse", 0); @@ -434,14 +447,7 @@ bool CoreModule::SpaceObjDestroyed(uint space_obj, bool moveFile, bool broadcast } Log::LogBaseAction(wstos(base->basename), msg.c_str()); - if (!base->last_attacker.empty()) - { - ConPrint(L"BASE: Base %s destroyed. Last attacker: %s\n", base->basename.c_str(), base->last_attacker.c_str()); - } - else - { - ConPrint(L"BASE: Base %s destroyed\n", base->basename.c_str()); - } + ConPrint(L"BASE: Base %s destroyed\n", base->basename.c_str()); // Unspawn, delete base and save file. DeleteBase(base, moveFile); diff --git a/Plugins/Public/base_plugin/Jumper.cpp b/Plugins/Public/base_plugin/Jumper.cpp index 7d365d278..e27f340eb 100644 --- a/Plugins/Public/base_plugin/Jumper.cpp +++ b/Plugins/Public/base_plugin/Jumper.cpp @@ -169,6 +169,7 @@ void HyperJump::LoadHyperspaceHubConfig(const string& configPath) static map> mapSystemJumps; uint lastJumpholeRandomization = 0; uint randomizationCooldown = 3600 * 23; + uint randomizationCooldownOffset = 3600 * 9; INI_Reader ini; if (ini.open(cfg_filehyperspaceHubTimer.c_str(), false)) @@ -186,6 +187,10 @@ void HyperJump::LoadHyperspaceHubConfig(const string& configPath) { randomizationCooldown = ini.get_value_int(0); } + if (ini.is_value("randomizationCooldownOffset")) + { + randomizationCooldownOffset = ini.get_value_int(0); + } if (ini.is_value("systemToExclude")) { unchartedSystemToExclude = CreateID(ini.get_value_string(0)); @@ -390,5 +395,5 @@ void HyperJump::LoadHyperspaceHubConfig(const string& configPath) } } - WritePrivateProfileString("Timer", "lastRandomization", itos((int)currTime).c_str(), cfg_filehyperspaceHubTimer.c_str()); + WritePrivateProfileString("Timer", "lastRandomization", itos((int)(currTime - (currTime % randomizationCooldown) + randomizationCooldownOffset)).c_str(), cfg_filehyperspaceHubTimer.c_str()); } \ No newline at end of file diff --git a/Plugins/Public/base_plugin/Main.cpp b/Plugins/Public/base_plugin/Main.cpp index 561cf0782..5b19e1fdd 100644 --- a/Plugins/Public/base_plugin/Main.cpp +++ b/Plugins/Public/base_plugin/Main.cpp @@ -100,7 +100,7 @@ string set_status_path_html; string set_status_path_json; /// Damage to the base every tick -uint set_damage_per_tick = 600; +float set_damage_per_tick = 600; /// Additional damage penalty for stations without proper crew float no_crew_damage_multiplier = 1; @@ -524,7 +524,7 @@ void LoadSettingsActual() } else if (ini.is_value("damage_per_tick")) { - set_damage_per_tick = ini.get_value_int(0); + set_damage_per_tick = ini.get_value_float(0); } else if (ini.is_value("no_crew_damage_multiplier")) { @@ -1142,9 +1142,17 @@ bool __stdcall HkCb_Land(IObjInspectImpl *obj, uint base_dock_id, uint base) if (clients[client].player_base) return true; + CUSTOM_MOBILE_DOCK_CHECK_STRUCT info; + info.iClientID = client; + info.isMobileDocked = false; + Plugin_Communication(CUSTOM_MOBILE_DOCK_CHECK, &info); + if (!info.isMobileDocked) + { + clients[client].last_player_base = 0; + } + // If we're not docking at a player base then clear // the last base flag - clients[client].last_player_base = 0; clients[client].player_base = 0; if (base == 0) @@ -1532,9 +1540,9 @@ static bool IsDockingAllowed(PlayerBase *base, uint client) } //Hostile listed can't dock even if they are friendly faction listed - for (list::iterator i = base->perma_hostile_tags.begin(); i != base->perma_hostile_tags.end(); ++i) + for (auto& i : base->perma_hostile_tags) { - if (charname.find(*i) == 0) + if (charname.find(i) == 0) { return false; } @@ -2370,6 +2378,10 @@ void __stdcall HkCb_AddDmgEntry(DamageList *dmg, unsigned short sID, float& newH returncode = SKIPPLUGINS_NOFUNCTIONCALL; return; } + if (newHealth == 0.0f) + { + damagedModule->SpaceObjDestroyed(iDmgToSpaceID); + } returncode = SKIPPLUGINS; @@ -2566,7 +2578,6 @@ bool ExecuteCommandString_Callback(CCmds* cmd, const wstring &args) } } - if (!base) { cmd->Print(L"ERR Base doesn't exist"); @@ -2624,39 +2635,6 @@ bool ExecuteCommandString_Callback(CCmds* cmd, const wstring &args) } - return true; - } - else if (args.find(L"basedespawn") == 0) - { - returncode = SKIPPLUGINS_NOFUNCTIONCALL; - - RIGHT_CHECK(RIGHT_BASES) - - uint client = HkGetClientIdFromCharname(cmd->GetAdminName()); - - PlayerBase* base; - for (auto& i : player_bases) - { - if (i.second->basename == cmd->ArgStrToEnd(1)) - { - base = i.second; - break; - } - } - - if (!base) - { - cmd->Print(L"ERR Base doesn't exist\n"); - return true; - } - - base->base_health = 0; - if (base->base_health < 1) - { - cmd->Print(L"Base despawned\n"); - CoreModule(base).SpaceObjDestroyed(CoreModule(base).space_obj, false, false); - } - return true; } else if (args.find(L"baserespawn") == 0) diff --git a/Plugins/Public/base_plugin/Main.h b/Plugins/Public/base_plugin/Main.h index 9e8cfef79..dd57df65e 100644 --- a/Plugins/Public/base_plugin/Main.h +++ b/Plugins/Public/base_plugin/Main.h @@ -145,8 +145,8 @@ class CoreModule : public Module // If true, do not take damage bool dont_rust; - // The list of goods and usage of goods per minute for the autosys effect - map mapAutosysGood; + bool wasDamagedSinceLastUpdate; + bool undergoingDestruction; // The list of goods and usage of goods per minute for the autosys effect map mapHumansysGood; @@ -309,7 +309,6 @@ class PlayerBase float GetAttitudeTowardsClient(uint client, bool emulated_siege_mode = false); void SyncReputationForBase(); - void SiegeModChainReaction(uint client); void SyncReputationForBaseObject(uint space_obj); void SpaceObjDamaged(uint space_obj, uint attacking_space_obj, float curr_hitpoints, float new_hitpoints); @@ -320,6 +319,9 @@ class PlayerBase // The base nickname string nickname; + // Reference to the base's CSolar object + CSolar* baseCSolar; + // The base affiliation uint affiliation; @@ -401,11 +403,10 @@ class PlayerBase unordered_set hostile_factions; // List of ships that are hostile to this base - unordered_map hostile_tags; - unordered_map hostile_tags_damage; + unordered_set hostile_tags; // List of ships that are permanently hostile to this base - list perma_hostile_tags; + unordered_set perma_hostile_tags; // Modules for base vector modules; @@ -434,9 +435,6 @@ class PlayerBase int logic; int invulnerable; - //last player attacker - wstring last_attacker; - uint lastVulnerabilityWindowChange = 0; BASE_VULNERABILITY_WINDOW vulnerabilityWindow1 = { -1, -1 }; @@ -679,7 +677,7 @@ extern int construction_credit_cost; extern uint set_damage_per_10sec; /// Damage to the base every tick -extern uint set_damage_per_tick; +extern float set_damage_per_tick; /// Additional damage penalty for stations without proper crew extern float no_crew_damage_multiplier; diff --git a/Plugins/Public/base_plugin/PlayerBase.cpp b/Plugins/Public/base_plugin/PlayerBase.cpp index 4894faebc..1bcae3911 100644 --- a/Plugins/Public/base_plugin/PlayerBase.cpp +++ b/Plugins/Public/base_plugin/PlayerBase.cpp @@ -388,7 +388,7 @@ void PlayerBase::Load() { wstring tag; ini_get_wstring(ini, tag); - perma_hostile_tags.emplace_back(tag); + perma_hostile_tags.insert(tag); } else if (ini.is_value("faction_ally_tag")) { @@ -555,11 +555,7 @@ void PlayerBase::Save() { fprintf(file, "faction_hostile_tag = %d\n", i); } - for (auto& i : hostile_tags) - { - ini_write_wstring(file, "hostile_tag", const_cast(i.first)); - } - for(auto& i : perma_hostile_tags) + for(auto i : perma_hostile_tags) { ini_write_wstring(file, "perma_hostile_tag", i); } @@ -816,30 +812,6 @@ void ReportAttack(wstring basename, wstring charname, uint system, wstring alert return; } -// For all players in the base's system, resync their reps towards all objects -// of this base. -void PlayerBase::SiegeModChainReaction(uint client) -{ - for (auto& it : player_bases) - { - if (it.second->system != this->system || it.second->siege_mode || - HkDistance3D(it.second->position, this->position) >= siege_mode_chain_reaction_trigger_distance) - { - continue; - } - float attitude = it.second->GetAttitudeTowardsClient(client, true); - if (attitude < -0.55f) - { - it.second->siege_mode = true; - - const wstring& charname = (const wchar_t*)Players.GetActiveCharacterName(client); - ReportAttack(it.second->basename, charname, it.second->system, L"has detected hostile activity at a nearby base by"); - - it.second->SyncReputationForBase(); - } - } -} - // Return true if void PlayerBase::SpaceObjDamaged(uint space_obj, uint attacking_space_obj, float curr_hitpoints, float new_hitpoints) { @@ -847,7 +819,6 @@ void PlayerBase::SpaceObjDamaged(uint space_obj, uint attacking_space_obj, float { return; } - float incoming_damage = curr_hitpoints - new_hitpoints; // Make sure that the attacking player is hostile. uint client = HkGetClientIDByShip(attacking_space_obj); @@ -856,68 +827,10 @@ void PlayerBase::SpaceObjDamaged(uint space_obj, uint attacking_space_obj, float return; } const wstring& charname = (const wchar_t*)Players.GetActiveCharacterName(client); - last_attacker = charname; - - if (hostile_tags_damage.find(charname) == hostile_tags_damage.end()) - hostile_tags_damage[charname] = 0; - - hostile_tags_damage[charname] += incoming_damage; - - // Allies are allowed to shoot at the base without the base becoming hostile. We do the ally search - // after checking to see if this player is on the hostile list because allies don't normally - // shoot at bases and so this is more efficient than searching the ally list first. - if (hostile_tags.find(charname) == hostile_tags.end()) - { - bool is_ally = false; - for (list::iterator i = ally_tags.begin(); i != ally_tags.end(); ++i) - { - if (charname.find(*i) == 0) - { - is_ally = true; - break; - } - } - - if (!is_ally && (hostile_tags_damage[charname]) > damage_threshold) - { - hostile_tags[charname] = charname; - - const wstring& charname = (const wchar_t*)Players.GetActiveCharacterName(client); - ReportAttack(this->basename, charname, this->system, L"has activated self-defense against"); - - SyncReputationForBase(); - - if (siege_mode) - SiegeModChainReaction(client); - } - } - - if (!siege_mode && (hostile_tags_damage[charname]) > siege_mode_damage_trigger_level) - { - const wstring& charname = (const wchar_t*)Players.GetActiveCharacterName(client); - ReportAttack(this->basename, charname, this->system, L"siege mode triggered by"); - - siege_mode = true; - SiegeModChainReaction(client); - } - // If the shield is not active but could be set a time - // to request that it is activated. - if (!this->shield_timeout && this->isShieldOn == false - && this->vulnerableWindowStatus) + if (!hostile_tags.count(charname)) { - const wstring& charname = (const wchar_t*)Players.GetActiveCharacterName(client); + hostile_tags.insert(charname); ReportAttack(this->basename, charname, this->system); - if (set_plugin_debug > 1) - { - ConPrint(L"PlayerBase::damaged shield active=%u\n", this->shield_timeout); - } - } - - this->shield_timeout = time(nullptr) + 60; - if (!this->isShieldOn) - { - this->isShieldOn = true; - ((CoreModule*)this->modules[0])->EnableShieldFuse(true); } } \ No newline at end of file diff --git a/Plugins/Public/base_plugin/PlayerCommands.cpp b/Plugins/Public/base_plugin/PlayerCommands.cpp index 4a0771543..f83f4a6c9 100644 --- a/Plugins/Public/base_plugin/PlayerCommands.cpp +++ b/Plugins/Public/base_plugin/PlayerCommands.cpp @@ -877,7 +877,7 @@ namespace PlayerCommands } - base->perma_hostile_tags.emplace_back(tag); + base->perma_hostile_tags.insert(tag); // Logging wstring thecharname = (const wchar_t*)Players.GetActiveCharacterName(client); @@ -909,13 +909,13 @@ namespace PlayerCommands PrintUserCmdText(client, L"ERR No tag"); } - if (find(base->perma_hostile_tags.begin(), base->perma_hostile_tags.end(), tag) == base->perma_hostile_tags.end()) + if (!base->perma_hostile_tags.count(tag)) { PrintUserCmdText(client, L"ERR Tag does not exist"); return; } - base->perma_hostile_tags.remove(tag); + base->perma_hostile_tags.erase(tag); // Logging wstring thecharname = (const wchar_t*)Players.GetActiveCharacterName(client); @@ -941,8 +941,8 @@ namespace PlayerCommands return; } - foreach(base->perma_hostile_tags, wstring, i) - PrintUserCmdText(client, L"%s", i->c_str()); + for(auto& hostileTag : base->perma_hostile_tags) + PrintUserCmdText(client, L"%s", hostileTag.c_str()); PrintUserCmdText(client, L"OK"); } @@ -1871,7 +1871,7 @@ namespace PlayerCommands wstring charname = (const wchar_t*)Players.GetActiveCharacterName(client); const GoodInfo* gi = GoodList::find_by_id(i.first); - BaseLogging("Base %s: player %s changed price of %s to %f", wstos(base->basename).c_str(), wstos(charname).c_str(), wstos(HkGetWStringFromIDS(gi->iIDSName)).c_str(), money); + BaseLogging("Base %s: player %s changed price of %s to %d", wstos(base->basename).c_str(), wstos(charname).c_str(), wstos(HkGetWStringFromIDS(gi->iIDSName)).c_str(), money); return; } } @@ -1996,6 +1996,13 @@ namespace PlayerCommands } PrintUserCmdText(client, L"Crew: %u onboard", crewItemCount); + uint populationCount = 0; + for (uint hash : humanCargoList) + { + populationCount += base->HasMarketItem(hash); + } + PrintUserCmdText(client, L"Total population: %u onboard", populationCount); + PrintUserCmdText(client, L"Crew supplies:"); for (uint item : set_base_crew_consumption_items) {