Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SW tag that grants 1-time-use super weapons #1199

Open
wants to merge 16 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ This page lists all the individual contributions to the project by their author.
- Customizable FLH when infantry is prone or deployed
- Initial strength for cloned infantry
- Map Events 604 & 605 for checking if a specific Techno enters in a cell
- Grant new superweapons in superweapons
- **Starkku**:
- Misc. minor bugfixes & improvements
- AI script actions:
Expand Down
2 changes: 1 addition & 1 deletion YRpp
Submodule YRpp updated 1 files
+6 −0 Unsorted.h
25 changes: 25 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -869,6 +869,31 @@ Detonate.Damage= ; integer
Detonate.AtFirer=false ; boolean
```

### Grant new superweapons in superweapons

- Superweapons can add 1-time superweapons to the firer like the nuke crate. Granted types can be additionally randomized using the same rules as with LimboDelivery (see above).
- `SW.GrantOneTime.InitialReady` specifies if all new granted superweapons will be ready for launch. If not set this behaviour will be managed by `SW.InitialReady` of the granted superweapon.
- `SW.GrantOneTime.ReadyIfExists` specifies if superweapons should be ready for launch if already exists. If not set this behaviour will be managed by `SW.GrantOneTime.InitialReady` or `SW.InitialReady` of the granted superweapon.
- `SW.GrantOneTime.ResetIfExists` specifies if superweapons timers should be reset if already exists. Takes precedence over `SW.GrantOneTime.ReadyIfExists`, `SW.GrantOneTime.InitialReady` and `SW.InitialReady`.
- `Message.GrantOneTimeLaunched` will be displayed to the firer when the main superweapon is launched.
- `EVA.GrantOneTimeLaunched` will be played to the firer when the main superweapon is launched.
- These superweapons can be made random with these optional tags. The game will randomly choose only a single superweapon from the list for each roll chance provided.
- `SW.GrantOneTime.RollChances` lists chances of each "dice roll" happening. Valid values range from 0% (never happens) to 100% (always happens). Defaults to a single sure roll.
- `SW.GrantOneTime.RandomWeightsN` lists the weights for each "dice roll" that increase the probability of picking a specific superweapon. Valid values are 0 (don't pick) and above (the higher value, the bigger the likelyhood). `RandomWeights` are a valid alias for `RandomWeights0`. If a roll attempt doesn't have weights specified, the last weights will be used.

In `rulesmd.ini`:
```ini
[SOMESW] ; Super Weapon
SW.GrantOneTime= ; List of super weapons
SW.GrantOneTime.RollChances= ; List of percentages.
SW.GrantOneTime.RandomWeightsN= ; List of integers.
SW.GrantOneTime.InitialReady= ; boolean
SW.GrantOneTime.ReadyIfExists= ; boolean
SW.GrantOneTime.ResetIfExists=false ; boolean
Message.GrantOneTimeLaunched= ; CSF entry key
EVA.GrantOneTimeLaunched= ; EVA entry
```

## Technos

### Aircraft spawner customizations
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ New:
- Allow setting default singleplayer map loading screen and briefing offsets (by Starkku)
- Allow toggling whether or not fire particle systems adjust target coordinates when firer rotates (by Starkku)
- `AmbientDamage` warhead & main target ignore customization (by Starkku)
- Grant new superweapons in superweapons (by FS-21).
- Flashing Technos on selecting (by Fryone)
- Customizable DropPod properties on a per-InfantryType basis (by Trsdy)
- Projectile return weapon (by Starkku)
Expand Down
38 changes: 38 additions & 0 deletions src/Ext/SWType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ void SWTypeExt::ExtData::Serialize(T& Stm)
.Process(this->UseWeeds_Amount)
.Process(this->UseWeeds_StorageTimer)
.Process(this->UseWeeds_ReadinessAnimationPercentage)
.Process(this->SW_GrantOneTime)
.Process(this->SW_GrantOneTime_InitialReady)
.Process(this->SW_GrantOneTime_ReadyIfExists)
.Process(this->SW_GrantOneTime_ResetIfExists)
.Process(this->SW_GrantOneTime_RandomWeightsData)
.Process(this->SW_GrantOneTime_RollChances)
.Process(this->Message_GrantOneTimeLaunched)
.Process(this->EVA_GrantOneTimeLaunched)
;
}

Expand Down Expand Up @@ -149,6 +157,36 @@ void SWTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->SW_Next_RandomWeightsData.push_back(std::move(weights2));
}

this->SW_GrantOneTime.Read(exINI, pSection, "SW.GrantOneTime");
this->SW_GrantOneTime_InitialReady.Read(exINI, pSection, "SW.GrantOneTime.InitialReady");
this->SW_GrantOneTime_ReadyIfExists.Read(exINI, pSection, "SW.GrantOneTime.ReadyIfExists");
this->SW_GrantOneTime_ResetIfExists.Read(exINI, pSection, "SW.GrantOneTime.ResetIfExists");
this->Message_GrantOneTimeLaunched.Read(exINI, pSection, "Message.GrantOneTimeLaunched");
this->EVA_GrantOneTimeLaunched.Read(exINI, pSection, "EVA.GrantOneTimeLaunched");
this->SW_GrantOneTime_RollChances.Read(exINI, pSection, "SW.GrantOneTime.RollChances");

// SW.GrantOneTime.RandomWeights
for (size_t i = 0; ; ++i)
{
ValueableVector<int> weights3;
_snprintf_s(tempBuffer, sizeof(tempBuffer), "SW.GrantOneTime.RandomWeights%d", i);
weights3.Read(exINI, pSection, tempBuffer);

if (!weights3.size())
break;

this->SW_GrantOneTime_RandomWeightsData.push_back(std::move(weights3));
}
ValueableVector<int> weights3;
weights3.Read(exINI, pSection, "SW.GrantOneTime.RandomWeights");
if (weights3.size())
{
if (this->SW_GrantOneTime_RandomWeightsData.size())
this->SW_GrantOneTime_RandomWeightsData[0] = std::move(weights3);
else
this->SW_GrantOneTime_RandomWeightsData.push_back(std::move(weights3));
}

this->Detonate_Warhead.Read<true>(exINI, pSection, "Detonate.Warhead");
this->Detonate_Weapon.Read<true>(exINI, pSection, "Detonate.Weapon");
this->Detonate_Damage.Read(exINI, pSection, "Detonate.Damage");
Expand Down
19 changes: 19 additions & 0 deletions src/Ext/SWType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class SWTypeExt

std::vector<ValueableVector<int>> LimboDelivery_RandomWeightsData;
std::vector<ValueableVector<int>> SW_Next_RandomWeightsData;
std::vector<ValueableVector<int>> SW_GrantOneTime_RandomWeightsData;

std::vector<TypeConvertGroup> Convert_Pairs;

Expand All @@ -70,6 +71,14 @@ class SWTypeExt
Valueable<bool> UseWeeds_StorageTimer;
Valueable<double> UseWeeds_ReadinessAnimationPercentage;

ValueableIdxVector<SuperWeaponTypeClass> SW_GrantOneTime;
Nullable<bool> SW_GrantOneTime_InitialReady;
Nullable<bool> SW_GrantOneTime_ReadyIfExists;
Valueable<bool> SW_GrantOneTime_ResetIfExists;
ValueableVector<float> SW_GrantOneTime_RollChances;
Valueable<CSFText> Message_GrantOneTimeLaunched;
NullableIdx<VoxClass> EVA_GrantOneTimeLaunched;

ExtData(SuperWeaponTypeClass* OwnerObject) : Extension<SuperWeaponTypeClass>(OwnerObject)
, Money_Amount { 0 }
, SW_Inhibitors {}
Expand Down Expand Up @@ -111,6 +120,14 @@ class SWTypeExt
, UseWeeds_Amount { RulesClass::Instance->WeedCapacity }
, UseWeeds_StorageTimer { false }
, UseWeeds_ReadinessAnimationPercentage { 0.9 }
, SW_GrantOneTime {}
, SW_GrantOneTime_InitialReady {}
, SW_GrantOneTime_ReadyIfExists {}
, SW_GrantOneTime_ResetIfExists { false }
, SW_GrantOneTime_RollChances {}
, SW_GrantOneTime_RandomWeightsData {}
, Message_GrantOneTimeLaunched {}
, EVA_GrantOneTimeLaunched {}
{ }

// Ares 0.A functions
Expand All @@ -131,6 +148,8 @@ class SWTypeExt
void ApplySWNext(SuperClass* pSW, const CellStruct& cell);
void ApplyTypeConversion(SuperClass* pSW);

void GrantOneTimeFromList(SuperClass* pSW);

virtual void LoadFromINIFile(CCINIClass* pINI) override;
virtual ~ExtData() = default;

Expand Down
71 changes: 71 additions & 0 deletions src/Ext/SWType/FireSuperWeapon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <Utilities/GeneralUtils.h>

#include "Ext/House/Body.h"
#include <MessageListClass.h>
#include "Ext/WarheadType/Body.h"
#include "Ext/WeaponType/Body.h"
#include <Ext/Scenario/Body.h>
Expand All @@ -33,6 +34,9 @@ void SWTypeExt::FireSuperWeaponExt(SuperClass* pSW, const CellStruct& cell)

if (pTypeExt->Convert_Pairs.size() > 0)
pTypeExt->ApplyTypeConversion(pSW);

if (pTypeExt->SW_GrantOneTime.size() > 0)
pTypeExt->GrantOneTimeFromList(pSW);
}
}

Expand Down Expand Up @@ -280,3 +284,70 @@ void SWTypeExt::ExtData::ApplyTypeConversion(SuperClass* pSW)
for (const auto pTargetFoot : *FootClass::Array)
TypeConvertGroup::Convert(pTargetFoot, this->Convert_Pairs, pSW->Owner);
}

void SWTypeExt::ExtData::GrantOneTimeFromList(SuperClass* pSW)
{
// SW.GrantOneTime proper SW granting mechanic
HouseClass* pHouse = pSW->Owner;
bool notObserver = !pHouse->IsObserver() || !pHouse->IsCurrentPlayerObserver();

auto grantTheSW = [=](const int swIdxToAdd) -> bool
{
if (const auto pSuper = pHouse->Supers.GetItem(swIdxToAdd))
{
bool forceReadyness = pSuper->IsPresent && this->SW_GrantOneTime_ReadyIfExists.isset() && this->SW_GrantOneTime_ReadyIfExists.Get();
bool forceReset = pSuper->IsPresent && this->SW_GrantOneTime_ResetIfExists.Get();
bool granted = pSuper->Grant(true, false, false);

if (granted || forceReadyness || forceReset)
{
auto const pTypeExt = SWTypeExt::ExtMap.Find(pSuper->Type);
bool isReady = this->SW_GrantOneTime_InitialReady.isset() && this->SW_GrantOneTime_InitialReady.Get() ? true : false;
isReady = !this->SW_GrantOneTime_InitialReady.isset() && pTypeExt->SW_InitialReady ? true : isReady;
isReady = forceReadyness ? true : isReady;

if (isReady && !forceReset)
{
pSuper->RechargeTimer.TimeLeft = 0;
pSuper->SetReadiness(true);
}
else
{
pSuper->Reset();
}

if (notObserver && pHouse->IsCurrentPlayer())
{
if (MouseClass::Instance->AddCameo(AbstractType::Special, swIdxToAdd))
MouseClass::Instance->RepaintSidebar(1);
}
}

return granted;
}

return false;
};

// random mode
if (this->SW_GrantOneTime_RandomWeightsData.size())
{
auto results = this->WeightedRollsHandler(&this->SW_GrantOneTime_RollChances, &this->SW_GrantOneTime_RandomWeightsData, this->SW_GrantOneTime.size());
for (int result : results)
grantTheSW(this->SW_GrantOneTime[result]);
}
// no randomness mode
else
{
for (const auto swType : this->SW_GrantOneTime)
grantTheSW(swType);
}

if (notObserver && pHouse->IsCurrentPlayer())
{
if (this->EVA_GrantOneTimeLaunched.isset())
VoxClass::PlayIndex(this->EVA_GrantOneTimeLaunched.Get(), -1, -1);

MessageListClass::Instance->PrintMessage(this->Message_GrantOneTimeLaunched.Get(), RulesClass::Instance->MessageDelay, HouseClass::CurrentPlayer->ColorSchemeIndex, true);
}
}
Loading