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)
{