Make clashing wave resolution randomized.

This commit changes two things; it allows multiple single waves to have
the same wave number, and it makes the wave selection procedure pick
randomly between multiple valid matches.

Effectively, this means that MobArena now picks randomly when clashing
recurrent waves _also_ clash on priority (rather than deferring the
decision to the arbitrary but deterministic nature of sorted sets), and
it also picks randomly between multiple single waves with the same wave
number (which was not possible before).

This should allow server owners to add variety into their wave setups
while maintaining a great deal of control over the randomness involved.
For instance, it's now possible to have wave 10 be a boss wave, but the
_actual_ boss wave is randomly picked between three different waves all
with wave number 10. Upgrade waves could be randomized as well. As for
randomized recurrent waves, perhaps instead of having potentially four
different mobs in the same wave, a setup could instead have two _pairs_
of mobs that are randomly selected for a different kind of randomness.

Closes #795
This commit is contained in:
Andreas Troelsen
2024-07-23 02:24:29 +02:00
parent 70a46862b0
commit 3badf4c934
3 changed files with 77 additions and 35 deletions
+4
View File
@@ -11,6 +11,10 @@ These changes will (most likely) be included in the next version.
## [Unreleased] ## [Unreleased]
### Changed
- Recurrent waves can now be randomized. If two or more recurrent waves clash on wave number, frequency, _and_ priority, MobArena will now randomly pick between them. This should make it easier to create more varied and interesting wave setups without having to resort to only massively randomized default waves.
- Single waves can now be randomized. If two or more single waves clash on wave number, MobArena will now randomly pick between them. This means it is now possible to make randomly selected bosses for boss waves, for instance.
### Fixed ### Fixed
- MobArena no longer throws errors when handling block explosions on Minecraft 1.21. - MobArena no longer throws errors when handling block explosions on Minecraft 1.21.
@@ -4,7 +4,9 @@ import com.garbagemule.MobArena.framework.Arena;
import com.garbagemule.MobArena.waves.enums.WaveBranch; import com.garbagemule.MobArena.waves.enums.WaveBranch;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import java.util.SortedSet; import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.TreeSet; import java.util.TreeSet;
public class WaveManager public class WaveManager
@@ -12,10 +14,11 @@ public class WaveManager
private Arena arena; private Arena arena;
private ConfigurationSection section; private ConfigurationSection section;
private Wave defaultWave, currentWave; private Wave defaultWave, currentWave, nextWave;
private TreeSet<Wave> recurrentWaves, singleWaves, singleWavesInstance; private TreeSet<Wave> recurrentWaves, singleWaves;
private int wave, finalWave; private int wave, finalWave;
private Random random = new Random();
public WaveManager(Arena arena, ConfigurationSection section) { public WaveManager(Arena arena, ConfigurationSection section) {
this.arena = arena; this.arena = arena;
@@ -26,14 +29,10 @@ public class WaveManager
reloadWaves(); reloadWaves();
} }
public TreeSet<Wave> getRecurrentWaves() {
return recurrentWaves;
}
public void reset() { public void reset() {
reloadWaves(); reloadWaves();
wave = 0; wave = 0;
singleWavesInstance = new TreeSet<>(singleWaves); determineNextWave();
} }
public void reloadWaves() { public void reloadWaves() {
@@ -61,21 +60,77 @@ public class WaveManager
} }
} }
private void determineNextWave() {
// Single waves take precedence over recurrent waves
List<Wave> singles = findSingleWaveCandidates(wave + 1);
if (!singles.isEmpty()) {
nextWave = pickRandomWave(singles);
return;
}
List<Wave> recurrents = findRecurrentWaveCandidates(wave + 1);
if (!recurrents.isEmpty()) {
nextWave = pickRandomWave(recurrents);
} else {
nextWave = defaultWave.copy();
}
}
private List<Wave> findSingleWaveCandidates(int wave) {
List<Wave> candidates = new ArrayList<>(singleWaves.size());
for (Wave w : singleWaves) {
if (w.matches(wave)) {
candidates.add(w);
}
}
return candidates;
}
private List<Wave> findRecurrentWaveCandidates(int wave) {
List<Wave> matches = new ArrayList<>(recurrentWaves.size());
for (Wave w : recurrentWaves) {
if (w.matches(wave)) {
matches.add(w);
}
}
int priority = 0;
for (Wave w : matches) {
if (w.getPriority() > priority) {
priority = w.getPriority();
}
}
List<Wave> candidates = new ArrayList<>(matches.size());
for (Wave w : matches) {
if (w.getPriority() == priority) {
candidates.add(w);
}
}
return candidates;
}
private Wave pickRandomWave(List<Wave> candidates) {
if (candidates.size() == 1) {
return candidates.get(0).copy();
}
int index = random.nextInt(candidates.size());
return candidates.get(index).copy();
}
/** /**
* Increment the wave number and get the next Wave to be spawned. * Increment the wave number and get the next Wave to be spawned.
* Note that this method is a mutator. * Note that this method is a mutator.
* @return the next Wave * @return the next Wave
*/ */
public Wave next() { public Wave next() {
wave++; currentWave = nextWave;
if (!singleWavesInstance.isEmpty() && singleWavesInstance.first().matches(wave)) { wave++;
currentWave = singleWavesInstance.pollFirst().copy(); determineNextWave();
}
else {
SortedSet<Wave> matches = getMatchingRecurrentWaves(wave);
currentWave = (matches.isEmpty() ? defaultWave : matches.last()).copy();
}
return currentWave; return currentWave;
} }
@@ -87,14 +142,7 @@ public class WaveManager
* @return the next Wave * @return the next Wave
*/ */
public Wave getNext() { public Wave getNext() {
int next = wave + 1; return nextWave;
if (!singleWavesInstance.isEmpty() && singleWavesInstance.first().matches(next)) {
return singleWavesInstance.first();
}
SortedSet<Wave> matches = getMatchingRecurrentWaves(wave);
return (matches.isEmpty() ? defaultWave : matches.last());
} }
/** /**
@@ -121,14 +169,4 @@ public class WaveManager
public int getFinalWave() { public int getFinalWave() {
return finalWave; return finalWave;
} }
private SortedSet<Wave> getMatchingRecurrentWaves(int wave) {
TreeSet<Wave> result = new TreeSet<>(WaveUtils.getRecurrentComparator());
for (Wave w : recurrentWaves) {
if (w.matches(wave)) {
result.add(w);
}
}
return result;
}
} }
@@ -114,7 +114,7 @@ public class WaveUtils
return -1; return -1;
else if (w1.getFirstWave() > w2.getFirstWave()) else if (w1.getFirstWave() > w2.getFirstWave())
return 1; return 1;
else return 0; else return w1.getName().compareTo(w2.getName());
} }
}; };
} }