Skip to content

Commit

Permalink
Improved upgrade generation algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
ToxicFrog committed Jul 8, 2022
1 parent e9d9219 commit d5aa75e
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 46 deletions.
3 changes: 3 additions & 0 deletions laevis/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
- Change: Explosive Death's range now increases more slowly with levels, and is
based on the radius of the exploding monster; bigger enemies produce bigger booms.
- Change: split the menu code into a separate library, libtooltipmenu.pk3
- Change: you can now pick between 4 upgrades when you gain a level
- Fix: upgrade generation can no longer take unbounded time if you're unlucky
- Fix: upgrade generation can no longer freeze the game if the pool of upgrade candidates is very small
- Fix: Added some missing sprites to the repo (they were still in the pk3 but not versioned)

# 0.6.4
Expand Down
14 changes: 3 additions & 11 deletions laevis/ca.ancilla.laevis/PlayerUpgradeGiver.zs
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,17 @@
class ::PlayerUpgradeGiver : ::UpgradeGiver {
::PerPlayerStats stats;

// TODO: we might want to force the first upgrade to always be a damage bonus
// or some other simple, generally useful upgrade.
override void CreateUpgradeCandidates() {
while (candidates.size() < 3) {
let upgrade = ::Upgrade::Registry.GenerateUpgradeForPlayer(stats);
if (!AlreadyHasUpgrade(upgrade)) {
candidates.push(upgrade);
} else {
upgrade.Destroy();
}
}
candidates.clear();
::Upgrade::Registry.GenerateUpgradesForPlayer(stats, candidates);
}

void InstallUpgrade(int index) {
if (index < 0) {
console.printf("Level-up rejected!");
} else {
console.printf("You gained a level of %s!", candidates[index].GetName());
stats.upgrades.AddUpgrade(candidates[index]);
stats.upgrades.Add(candidates[index].GetClassName());
}
Destroy();
}
Expand Down
14 changes: 3 additions & 11 deletions laevis/ca.ancilla.laevis/WeaponUpgradeGiver.zs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,8 @@ class ::WeaponUpgradeGiver : ::UpgradeGiver {
TFLV_WeaponInfo wielded;

override void CreateUpgradeCandidates() {
// TODO: properly handle the case where the number of valid upgrades is
// less than the number we want to display.
while (candidates.size() < 3) {
let upgrade = ::Upgrade::Registry.GenerateUpgradeForWeapon(wielded);
if (!AlreadyHasUpgrade(upgrade)) {
candidates.push(upgrade);
} else {
upgrade.Destroy();
}
}
candidates.clear();
::Upgrade::Registry.GenerateUpgradesForWeapon(wielded, candidates);
}

void InstallUpgrade(int index) {
Expand All @@ -24,7 +16,7 @@ class ::WeaponUpgradeGiver : ::UpgradeGiver {
} else {
console.printf("Your %s gained a level of %s!",
wielded.weapon.GetTag(), candidates[index].GetName());
wielded.upgrades.AddUpgrade(candidates[index]);
wielded.upgrades.Add(candidates[index].GetClassName());
}
Destroy();
}
Expand Down
57 changes: 33 additions & 24 deletions laevis/ca.ancilla.laevis/upgrades/Registry.zs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
#namespace TFLV::Upgrade;
#debug off

const UPGRADES_PER_LEVEL = 4;

class ::Registry : Object play {
array<string> upgrades;
array<string> upgrade_names;
array<::BaseUpgrade> upgrades;

static ::Registry GetRegistry() {
let reg = TFLV::EventHandler(StaticEventHandler.Find("TFLV::EventHandler"));
Expand All @@ -13,13 +16,14 @@ class ::Registry : Object play {

static void Register(string upgrade) {
DEBUG("Register: %s", upgrade);
if (GetRegistry().upgrades.find(upgrade) != GetRegistry().upgrades.size()) {
if (GetRegistry().upgrade_names.find(upgrade) != GetRegistry().upgrade_names.size()) {
// Assume that this is because a mod has tried to double-register an upgrade,
// and permit it as a no-op.
//ThrowAbortException("Duplicate upgrades named %s", upgrade);
return;
}
GetRegistry().upgrades.push(upgrade);
GetRegistry().upgrade_names.push(upgrade);
GetRegistry().upgrades.push(::BaseUpgrade(new(upgrade)));
}

// Can't be static because we need to call it during eventmanager initialization,
Expand Down Expand Up @@ -63,35 +67,40 @@ class ::Registry : Object play {
"::Embrittlement"
};
for (uint i = 0; i < UpgradeNames.size(); ++i) {
upgrades.push(UpgradeNames[i]);
upgrade_names.push(UpgradeNames[i]);
upgrades.push(::BaseUpgrade(new(UpgradeNames[i])));
}
}

static ::BaseUpgrade GenerateUpgrade() {
let cls = GetRegistry().upgrades[random(0, GetRegistry().upgrades.size()-1)];
DEBUG("GenerateUpgrade(%s)", cls);
return ::BaseUpgrade(new(cls));
static void PickN(Array<::BaseUpgrade> dst, Array<::BaseUpgrade> src, uint n) {
uint max = src.size();
while (max > 0 && dst.size() < n) {
uint i = random(0, max-1);
dst.push(src[i]);
src[i] = src[--max];
}
}

static ::BaseUpgrade GenerateUpgradeForPlayer(TFLV::PerPlayerStats stats) {
::BaseUpgrade upgrade = null;
while (upgrade == null) {
upgrade = ::Registry.GenerateUpgrade();
if (upgrade.IsSuitableForPlayer(stats)) return upgrade;
upgrade.Destroy();
upgrade = null;
static void GenerateUpgradesForPlayer(
TFLV::PerPlayerStats stats, Array<::BaseUpgrade> generated) {
Array<::BaseUpgrade> candidates;
// Array<::BaseUpgrade> all_upgrades = GetRegistry().upgrades;
for (uint i = 0; i < GetRegistry().upgrades.size(); ++i) {
if (GetRegistry().upgrades[i].IsSuitableForPlayer(stats))
candidates.push(GetRegistry().upgrades[i]);
}
return null; // unreachable

PickN(generated, candidates, UPGRADES_PER_LEVEL);
}

static ::BaseUpgrade GenerateUpgradeForWeapon(TFLV::WeaponInfo info) {
::BaseUpgrade upgrade = null;
while (upgrade == null) {
upgrade = ::Registry.GenerateUpgrade();
if (upgrade.IsSuitableForWeapon(info)) return upgrade;
upgrade.Destroy();
upgrade = null;
static void GenerateUpgradesForWeapon(
TFLV::WeaponInfo info, Array<::BaseUpgrade> generated) {
array<::BaseUpgrade> candidates;
for (uint i = 0; i < GetRegistry().upgrades.size(); ++i) {
if (GetRegistry().upgrades[i].IsSuitableForWeapon(info))
candidates.push(GetRegistry().upgrades[i]);
}
return null; // unreachable

PickN(generated, candidates, UPGRADES_PER_LEVEL);
}
}

0 comments on commit d5aa75e

Please sign in to comment.