mirror of
https://github.com/Melledy/Nebula.git
synced 2025-12-12 20:34:36 +01:00
Implement some star tower npc events
This commit is contained in:
@@ -55,6 +55,9 @@ public class GameConstants {
|
||||
public static final int[] TOWER_COMMON_SUB_NOTE_SKILLS = new int[] {
|
||||
90011, 90012, 90013, 90014, 90015, 90016, 90017
|
||||
};
|
||||
public static final int[] TOWER_EVENTS_IDS = new int[] {
|
||||
101, 102, 104, 105, 106, 107, 108, 114, 115, 116, 126, 127, 128
|
||||
};
|
||||
|
||||
public static int[][] VAMPIRE_SURVIVOR_BONUS_POWER = new int[][] {
|
||||
new int[] {100, 120},
|
||||
|
||||
@@ -116,6 +116,7 @@ public class GameData {
|
||||
@Getter private static DataTable<StarTowerGrowthNodeDef> StarTowerGrowthNodeDataTable = new DataTable<>();
|
||||
@Getter private static DataTable<StarTowerFloorExpDef> StarTowerFloorExpDataTable = new DataTable<>();
|
||||
@Getter private static DataTable<StarTowerTeamExpDef> StarTowerTeamExpDataTable = new DataTable<>();
|
||||
@Getter private static DataTable<StarTowerEventDef> StarTowerEventDataTable = new DataTable<>();
|
||||
@Getter private static DataTable<SubNoteSkillPromoteGroupDef> SubNoteSkillPromoteGroupDataTable = new DataTable<>();
|
||||
|
||||
@Getter private static DataTable<PotentialDef> PotentialDataTable = new DataTable<>();
|
||||
|
||||
34
src/main/java/emu/nebula/data/resources/EventOptionsDef.java
Normal file
34
src/main/java/emu/nebula/data/resources/EventOptionsDef.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package emu.nebula.data.resources;
|
||||
|
||||
import emu.nebula.data.BaseDef;
|
||||
import emu.nebula.data.GameData;
|
||||
import emu.nebula.data.ResourceType;
|
||||
import emu.nebula.data.ResourceType.LoadPriority;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* We don't need a DataTable for this, since we are only using this class to verify event options for the client
|
||||
*/
|
||||
@Getter
|
||||
@ResourceType(name = "EventOptions.json", loadPriority = LoadPriority.LOW)
|
||||
public class EventOptionsDef extends BaseDef {
|
||||
private int Id;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return Id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
// Get event
|
||||
var event = GameData.getStarTowerEventDataTable().get(this.Id / 100);
|
||||
if (event == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add to avaliable options
|
||||
event.getOptionIds().add(this.getId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package emu.nebula.data.resources;
|
||||
|
||||
import emu.nebula.data.BaseDef;
|
||||
import emu.nebula.data.ResourceType;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@ResourceType(name = "StarTowerEvent.json")
|
||||
public class StarTowerEventDef extends BaseDef {
|
||||
private int Id;
|
||||
private int[] RelatedNPCs;
|
||||
|
||||
private transient IntList optionIds;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return Id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a deep copy of our option ids
|
||||
*/
|
||||
public IntList getClonedOptionIds() {
|
||||
var list = new IntArrayList();
|
||||
list.addAll(this.getOptionIds());
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
this.optionIds = new IntArrayList();
|
||||
}
|
||||
}
|
||||
@@ -395,6 +395,11 @@ public class StarTowerGame {
|
||||
change.add(info);
|
||||
}
|
||||
case SubNoteSkill -> {
|
||||
// Sanity check to make sure we dont remove more than what we have
|
||||
if (count < 0) {
|
||||
count = Math.max(count, -this.getItems().get(id));
|
||||
}
|
||||
|
||||
// Add to items
|
||||
this.getItems().add(id, count);
|
||||
|
||||
@@ -409,6 +414,11 @@ public class StarTowerGame {
|
||||
this.getNewInfos().add(id, count);
|
||||
}
|
||||
case Res -> {
|
||||
// Sanity check to make sure we dont remove more than what we have
|
||||
if (count < 0) {
|
||||
count = Math.max(count, -this.getRes().get(id));
|
||||
}
|
||||
|
||||
// Add to res
|
||||
this.getRes().add(id, count);
|
||||
|
||||
@@ -484,10 +494,14 @@ public class StarTowerGame {
|
||||
return this.createPotentialSelector(0);
|
||||
}
|
||||
|
||||
public StarTowerBaseCase createPotentialSelector(int charId) {
|
||||
return this.createPotentialSelector(charId, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a potential selector for the specified character
|
||||
*/
|
||||
public StarTowerBaseCase createPotentialSelector(int charId) {
|
||||
public StarTowerBaseCase createPotentialSelector(int charId, boolean rareOnly) {
|
||||
// Check character id
|
||||
if (charId <= 0) {
|
||||
charId = this.getRandomCharId();
|
||||
@@ -507,13 +521,21 @@ public class StarTowerGame {
|
||||
|
||||
if (isMainCharacter) {
|
||||
list.addElements(0, data.getMasterSpecificPotentialIds());
|
||||
list.addElements(0, data.getMasterNormalPotentialIds());
|
||||
|
||||
if (!rareOnly) {
|
||||
list.addElements(0, data.getMasterNormalPotentialIds());
|
||||
}
|
||||
} else {
|
||||
list.addElements(0, data.getAssistSpecificPotentialIds());
|
||||
list.addElements(0, data.getAssistNormalPotentialIds());
|
||||
|
||||
if (!rareOnly) {
|
||||
list.addElements(0, data.getAssistNormalPotentialIds());
|
||||
}
|
||||
}
|
||||
|
||||
list.addElements(0, data.getCommonPotentialIds());
|
||||
if (!rareOnly) {
|
||||
list.addElements(0, data.getCommonPotentialIds());
|
||||
}
|
||||
|
||||
// Remove potentials we already have maxed out
|
||||
var potentials = new IntArrayList();
|
||||
@@ -613,9 +635,13 @@ public class StarTowerGame {
|
||||
this.pendingSubNotes = amount;
|
||||
}
|
||||
|
||||
public int getRandomSubNoteId() {
|
||||
return Utils.randomElement(this.getSubNoteDropList());
|
||||
}
|
||||
|
||||
private PlayerChangeInfo addRandomSubNoteSkills(PlayerChangeInfo change) {
|
||||
int id = this.getRandomSubNoteId();
|
||||
int count = Utils.randomRange(1, 3);
|
||||
int id = Utils.randomElement(this.getSubNoteDropList());
|
||||
|
||||
this.addItem(id, count, change);
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ public class StarTowerHawkerCase extends StarTowerBaseCase {
|
||||
this.addGoods(goods);
|
||||
}
|
||||
|
||||
// Apply discounts based on star tower talents
|
||||
// Apply discounts based on star tower growth nodes
|
||||
if (getModifiers().isShopDiscountTier1()) {
|
||||
this.applyDiscount(1.0, 2, 0.8);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
package emu.nebula.game.tower.cases;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import emu.nebula.GameConstants;
|
||||
import emu.nebula.data.resources.StarTowerEventDef;
|
||||
import emu.nebula.game.player.PlayerChangeInfo;
|
||||
import emu.nebula.proto.PublicStarTower.NPCAffinityInfo;
|
||||
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
|
||||
import emu.nebula.proto.StarTowerInteract.StarTowerInteractReq;
|
||||
import emu.nebula.proto.StarTowerInteract.StarTowerInteractResp;
|
||||
import emu.nebula.util.Utils;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import lombok.Getter;
|
||||
@@ -12,11 +19,32 @@ public class StarTowerNpcEventCase extends StarTowerBaseCase {
|
||||
private int npcId;
|
||||
private int eventId;
|
||||
private IntList options;
|
||||
private boolean completed;
|
||||
|
||||
public StarTowerNpcEventCase(int npcId, int eventId) {
|
||||
public StarTowerNpcEventCase(int npcId, StarTowerEventDef event) {
|
||||
this.npcId = npcId;
|
||||
this.eventId = eventId;
|
||||
this.eventId = event.getId();
|
||||
this.options = new IntArrayList();
|
||||
|
||||
// Add up to 4 random options
|
||||
var randomOptions = event.getClonedOptionIds();
|
||||
int maxOptions = Math.min(randomOptions.size(), 4);
|
||||
|
||||
for (int i = 0; i < maxOptions; i++) {
|
||||
int optionId = Utils.randomElement(randomOptions, true);
|
||||
this.options.add(optionId);
|
||||
}
|
||||
|
||||
// Fix for question type events to always include the answer
|
||||
if (this.eventId >= 114 && this.eventId <= 116) {
|
||||
int answerId = (this.eventId * 100) + 3;
|
||||
if (!this.getOptions().contains(answerId)) {
|
||||
this.getOptions().set(0, answerId);
|
||||
}
|
||||
}
|
||||
|
||||
// Shuffle
|
||||
Collections.shuffle(this.getOptions());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -24,18 +52,267 @@ public class StarTowerNpcEventCase extends StarTowerBaseCase {
|
||||
return CaseType.NpcEvent;
|
||||
}
|
||||
|
||||
public int getOption(int index) {
|
||||
if (index < 0 || index >= this.getOptions().size()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return this.getOptions().getInt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StarTowerInteractResp interact(StarTowerInteractReq req, StarTowerInteractResp rsp) {
|
||||
// Sanity check to make sure we cant do the event multiple times
|
||||
if (this.isCompleted()) {
|
||||
return rsp;
|
||||
}
|
||||
|
||||
// Get option from selection index
|
||||
int option = this.getOption(req.getSelectReq().getIndex());
|
||||
|
||||
// Get select response proto
|
||||
var selectRsp = rsp.getMutableSelectResp();
|
||||
var success = selectRsp.getMutableResp();
|
||||
var change = new PlayerChangeInfo();
|
||||
|
||||
// Completed event flag
|
||||
boolean completed = true;
|
||||
|
||||
// Handle option id
|
||||
switch (option) {
|
||||
case 10101 -> {
|
||||
if (this.spendCoin(100, change)) {
|
||||
this.addPotentialSelector(rsp);
|
||||
} else {
|
||||
completed = false;
|
||||
}
|
||||
}
|
||||
case 10102 -> {
|
||||
if (this.spendCoin(120, change)) {
|
||||
this.addPotentialSelector(rsp);
|
||||
} else {
|
||||
completed = false;
|
||||
}
|
||||
}
|
||||
case 10103 -> {
|
||||
this.addCoin(30, change);
|
||||
}
|
||||
case 10201 -> {
|
||||
if (this.spendCoin(120, change)) {
|
||||
this.addPotentialSelector(rsp, this.getRandomSupportCharId());
|
||||
} else {
|
||||
completed = false;
|
||||
}
|
||||
}
|
||||
case 10202 -> {
|
||||
if (this.spendCoin(160, change)) {
|
||||
this.addPotentialSelector(rsp, this.getMainCharId());
|
||||
} else {
|
||||
completed = false;
|
||||
}
|
||||
}
|
||||
case 10203 -> {
|
||||
if (this.spendCoin(200, change)) {
|
||||
this.addRarePotentialSelector(rsp);
|
||||
} else {
|
||||
completed = false;
|
||||
}
|
||||
}
|
||||
case 10204 -> {
|
||||
this.addCoin(30, change);
|
||||
}
|
||||
case 10302 -> {
|
||||
// TODO
|
||||
if (this.spendSubNotes(5, change)) {
|
||||
this.addCoin(150, change);
|
||||
} else {
|
||||
completed = false;
|
||||
}
|
||||
}
|
||||
case 10303 -> {
|
||||
this.addCoin(30, change);
|
||||
}
|
||||
case 10401 -> {
|
||||
// TODO
|
||||
completed = false;
|
||||
}
|
||||
case 10402 -> {
|
||||
if (this.spendCoin(200, change)) {
|
||||
this.addRarePotentialSelector(rsp);
|
||||
} else {
|
||||
completed = false;
|
||||
}
|
||||
}
|
||||
case 10403 -> {
|
||||
this.addCoin(30, change);
|
||||
}
|
||||
case 10501 -> {
|
||||
if (Utils.randomChance(.5)) {
|
||||
this.addCoin(200, change);
|
||||
} else {
|
||||
this.addCoin(-100, change);
|
||||
}
|
||||
}
|
||||
case 10502 -> {
|
||||
if (Utils.randomChance(.3)) {
|
||||
this.addCoin(650, change);
|
||||
} else {
|
||||
this.addCoin(-200, change);
|
||||
}
|
||||
}
|
||||
case 10503 -> {
|
||||
this.addCoin(30, change);
|
||||
}
|
||||
case 10601 -> {
|
||||
if (Utils.randomChance(.5)) {
|
||||
this.addRarePotentialSelector(rsp);
|
||||
}
|
||||
}
|
||||
case 10602 -> {
|
||||
this.addPotentialSelector(rsp);
|
||||
}
|
||||
case 10603 -> {
|
||||
this.addCoin(30, change);
|
||||
}
|
||||
case 10701, 10702, 10703, 10704, 10705, 10706, 10707 -> {
|
||||
int subNoteId = (option % 100) + 90010;
|
||||
this.getGame().addItem(subNoteId, 5, change);
|
||||
}
|
||||
case 10708 -> {
|
||||
int subNoteId = this.getGame().getRandomSubNoteId();
|
||||
this.getGame().addItem(subNoteId, 5, change);
|
||||
}
|
||||
case 10801, 10802, 10803, 10804, 10805, 10806, 10807 -> {
|
||||
if (this.spendCoin(140, change)) {
|
||||
int subNoteId = (option % 100) + 90010;
|
||||
this.getGame().addItem(subNoteId, 10, change);
|
||||
} else {
|
||||
completed = false;
|
||||
}
|
||||
}
|
||||
case 10808 -> {
|
||||
if (this.spendCoin(90, change)) {
|
||||
int subNoteId = this.getGame().getRandomSubNoteId();
|
||||
this.getGame().addItem(subNoteId, 10, change);
|
||||
} else {
|
||||
completed = false;
|
||||
}
|
||||
}
|
||||
case 10809 -> {
|
||||
this.addCoin(30, change);
|
||||
}
|
||||
case 11401, 11402, 11403, 11404, 11405 -> {
|
||||
if (option == 11403) {
|
||||
int subNoteId = this.getGame().getRandomSubNoteId();
|
||||
this.getGame().addItem(subNoteId, 10, change);
|
||||
}
|
||||
}
|
||||
case 11501, 11502, 11503, 11504, 11505 -> {
|
||||
if (option == 11503) {
|
||||
this.addPotentialSelector(rsp);
|
||||
}
|
||||
}
|
||||
case 11601, 11602, 11603, 11604, 11605 -> {
|
||||
if (option == 11603) {
|
||||
this.addRarePotentialSelector(rsp);
|
||||
}
|
||||
}
|
||||
case 12601 -> {
|
||||
this.addPotentialSelector(rsp, this.getRandomSupportCharId());
|
||||
}
|
||||
case 12602 -> {
|
||||
// Recover 20% hp
|
||||
}
|
||||
case 12701 -> {
|
||||
this.addPotentialSelector(rsp, this.getRandomSupportCharId());
|
||||
}
|
||||
case 12702 -> {
|
||||
int subNoteId = this.getGame().getRandomSubNoteId();
|
||||
this.getGame().addItem(subNoteId, 5, change);
|
||||
}
|
||||
case 12801 -> {
|
||||
this.addRarePotentialSelector(rsp, this.getRandomSupportCharId());
|
||||
}
|
||||
case 12802 -> {
|
||||
this.addCoin(30, change);
|
||||
}
|
||||
default -> {
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
|
||||
// Set change info
|
||||
rsp.setChange(change.toProto());
|
||||
|
||||
// Set success result
|
||||
success.setOptionsResult(completed);
|
||||
this.completed = completed;
|
||||
|
||||
// Complete
|
||||
return rsp;
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
|
||||
private boolean spendCoin(int amount, PlayerChangeInfo change) {
|
||||
int coin = this.getGame().getResCount(GameConstants.TOWER_COIN_ITEM_ID);
|
||||
|
||||
if (coin < amount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.addCoin(-amount, change);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private PlayerChangeInfo addCoin(int amount, PlayerChangeInfo change) {
|
||||
return this.getGame().addItem(GameConstants.TOWER_COIN_ITEM_ID, amount, change);
|
||||
}
|
||||
|
||||
private boolean spendSubNotes(int amount, PlayerChangeInfo change) {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
private void addPotentialSelector(StarTowerInteractResp rsp) {
|
||||
this.addPotentialSelector(rsp, 0);
|
||||
}
|
||||
|
||||
private void addPotentialSelector(StarTowerInteractResp rsp, int charId) {
|
||||
var selectorCase = this.getGame().createPotentialSelector(charId);
|
||||
this.getRoom().addCase(rsp.getMutableCases(), selectorCase);
|
||||
}
|
||||
|
||||
private void addRarePotentialSelector(StarTowerInteractResp rsp) {
|
||||
this.addRarePotentialSelector(rsp, 0);
|
||||
}
|
||||
|
||||
private void addRarePotentialSelector(StarTowerInteractResp rsp, int charId) {
|
||||
var selectorCase = this.getGame().createPotentialSelector(charId, true);
|
||||
this.getRoom().addCase(rsp.getMutableCases(), selectorCase);
|
||||
}
|
||||
|
||||
private int getMainCharId() {
|
||||
return this.getGame().getCharIds()[0];
|
||||
}
|
||||
|
||||
private int getRandomSupportCharId() {
|
||||
return this.getGame().getCharIds()[Utils.randomRange(1, 2)];
|
||||
}
|
||||
|
||||
// Proto
|
||||
|
||||
@Override
|
||||
public void encodeProto(StarTowerRoomCase proto) {
|
||||
var info = NPCAffinityInfo.newInstance()
|
||||
.setNPCId(this.getNpcId())
|
||||
.setAffinity(0);
|
||||
|
||||
proto.getMutableSelectOptionsEventCase()
|
||||
.setEvtId(this.getEventId())
|
||||
.setNPCId(this.getNpcId())
|
||||
.addInfos(info)
|
||||
.addAllOptions(this.getOptions().toIntArray());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,6 +90,11 @@ public class StarTowerBaseRoom {
|
||||
}
|
||||
|
||||
public StarTowerBaseCase addCase(RepeatedMessage<StarTowerRoomCase> cases, StarTowerBaseCase towerCase) {
|
||||
// Sanity check
|
||||
if (towerCase == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Set game for tower case
|
||||
towerCase.register(this);
|
||||
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
package emu.nebula.game.tower.room;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import emu.nebula.GameConstants;
|
||||
import emu.nebula.data.GameData;
|
||||
import emu.nebula.data.resources.StarTowerEventDef;
|
||||
import emu.nebula.data.resources.StarTowerStageDef;
|
||||
import emu.nebula.game.tower.StarTowerGame;
|
||||
import emu.nebula.game.tower.cases.StarTowerBaseCase;
|
||||
import emu.nebula.game.tower.cases.StarTowerNpcEventCase;
|
||||
import emu.nebula.game.tower.cases.StarTowerSyncHPCase;
|
||||
import emu.nebula.util.Utils;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@@ -12,9 +21,47 @@ public class StarTowerEventRoom extends StarTowerBaseRoom {
|
||||
public StarTowerEventRoom(StarTowerGame game, StarTowerStageDef stage) {
|
||||
super(game, stage);
|
||||
}
|
||||
|
||||
private StarTowerEventDef getRandomEvent() {
|
||||
/*
|
||||
var list = GameData.getStarTowerEventDataTable()
|
||||
.values()
|
||||
.stream()
|
||||
.toList();
|
||||
*/
|
||||
|
||||
var list = Arrays.stream(GameConstants.TOWER_EVENTS_IDS)
|
||||
.mapToObj(GameData.getStarTowerEventDataTable()::get)
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
|
||||
if (list.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Utils.randomElement(list);
|
||||
}
|
||||
|
||||
public StarTowerBaseCase createNpcEvent() {
|
||||
// Get random event
|
||||
var event = this.getRandomEvent();
|
||||
|
||||
if (event == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get random npc
|
||||
int npcId = Utils.randomElement(event.getRelatedNPCs());
|
||||
|
||||
// Create case with event
|
||||
return new StarTowerNpcEventCase(npcId, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnter() {
|
||||
// Create npc
|
||||
this.addCase(this.createNpcEvent());
|
||||
|
||||
// Create sync hp case
|
||||
this.addCase(new StarTowerSyncHPCase());
|
||||
|
||||
|
||||
@@ -173,6 +173,10 @@ public class Utils {
|
||||
public static int randomRange(int min, int max) {
|
||||
return ThreadLocalRandom.current().nextInt(min, max + 1);
|
||||
}
|
||||
|
||||
public static boolean randomChance(double chance) {
|
||||
return ThreadLocalRandom.current().nextDouble() < chance;
|
||||
}
|
||||
|
||||
public static int randomElement(int[] array) {
|
||||
return array[ThreadLocalRandom.current().nextInt(0, array.length)];
|
||||
|
||||
Reference in New Issue
Block a user