10 Commits

Author SHA1 Message Date
Melledy
be84e0f406 Remove max level potentials from potential selectors 2025-12-04 00:01:48 -08:00
Melledy
e5cb842fdd Implement monolith shop discounts and improvements 2025-12-03 23:53:18 -08:00
Melledy
15618414a6 Implement monolith shop discounts 2025-12-03 23:15:25 -08:00
Melledy
71de6184b9 Optimize star tower case handling 2025-12-03 22:52:49 -08:00
Melledy
e887d5eb4c Update data versions 2025-12-03 22:45:42 -08:00
Melledy
211e012c42 Update patchlist handler 2025-12-03 22:44:12 -08:00
Melledy
9c87d74ad7 Add /client-code endpoint 2025-12-03 22:34:29 -08:00
Melledy
357d12779b Implement monolith shop refresh 2025-12-03 22:23:41 -08:00
Melledy
c8a7db75aa Implement bonus max potential level 2025-12-03 21:28:47 -08:00
Melledy
ef8846445c Implement monolith enhancement machines 2025-12-03 19:36:47 -08:00
20 changed files with 670 additions and 119 deletions

View File

@@ -12,16 +12,16 @@ public class GameConstants {
// Set data versions for each region
static {
RegionConfig.getRegion("global")
.setDataVersion(60);
RegionConfig.getRegion("kr")
.setDataVersion(67);
RegionConfig.getRegion("jp")
.setDataVersion(63);
RegionConfig.getRegion("kr")
.setDataVersion(70);
RegionConfig.getRegion("jp")
.setDataVersion(66);
RegionConfig.getRegion("tw")
.setDataVersion(61);
.setDataVersion(64);
}
public static final ZoneId UTC_ZONE = ZoneId.of("UTC");
@@ -34,7 +34,7 @@ public class GameConstants {
public static final int GEM_ITEM_ID = 2;
public static final int PREM_GEM_ITEM_ID = 3;
public static final int ENERGY_BUY_ITEM_ID = GEM_ITEM_ID;
public static final int STAR_TOWER_GOLD_ITEM_ID = 11;
public static final int STAR_TOWER_COIN_ITEM_ID = 11;
public static final int EXP_ITEM_ID = 21;
public static final int MAX_ENERGY = 240;

View File

@@ -2,6 +2,7 @@ package emu.nebula.data.resources;
import emu.nebula.data.BaseDef;
import emu.nebula.data.ResourceType;
import emu.nebula.game.tower.StarTowerGame;
import lombok.Getter;
@Getter
@@ -10,6 +11,7 @@ public class PotentialDef extends BaseDef {
private int Id;
private int CharId;
private int Build;
private int BranchType;
private int MaxLevel;
private int[] BuildScore;
@@ -19,4 +21,24 @@ public class PotentialDef extends BaseDef {
public int getId() {
return Id;
}
public int getMaxLevel(StarTowerGame game) {
// Check if regular potential
if (this.BranchType == 3) {
return this.MaxLevel + game.getModifiers().getBonusMaxPotentialLevel();
}
// Special potential should always have a max level of 1
return this.MaxLevel;
}
public int getBuildScore(int level) {
int index = level - 1;
if (index >= this.BuildScore.length) {
index = this.BuildScore.length - 1;
}
return this.BuildScore[index];
}
}

View File

@@ -140,8 +140,7 @@ public class StarTowerBuild implements GameDatabaseObject {
var data = GameData.getPotentialDataTable().get(potential.getIntKey());
if (data == null) continue;
int index = potential.getIntValue() - 1;
this.score += data.getBuildScore()[index];
this.score += data.getBuildScore(potential.getIntValue());
}
// Sub note skills

View File

@@ -19,6 +19,7 @@ import emu.nebula.game.tower.cases.StarTowerDoorCase;
import emu.nebula.game.tower.cases.StarTowerHawkerCase;
import emu.nebula.game.tower.cases.StarTowerNpcRecoveryHPCase;
import emu.nebula.game.tower.cases.StarTowerPotentialCase;
import emu.nebula.game.tower.cases.StarTowerStrengthenMachineCase;
import emu.nebula.game.tower.room.RoomType;
import emu.nebula.game.tower.room.StarTowerBaseRoom;
import emu.nebula.game.tower.room.StarTowerBattleRoom;
@@ -78,6 +79,9 @@ public class StarTowerGame {
// Sub note skill drop list
private IntList subNoteDropList;
// Modifiers
private StarTowerModifiers modifiers;
// Cached build
private transient StarTowerBuild build;
private transient ItemParamMap newInfos;
@@ -122,6 +126,9 @@ public class StarTowerGame {
// Melody skill drop list
this.subNoteDropList = new IntArrayList();
// Init modifiers
this.modifiers = new StarTowerModifiers(this);
// Init formation
for (int i = 0; i < 3; i++) {
int id = formation.getCharIdAt(i);
@@ -167,10 +174,10 @@ public class StarTowerGame {
this.subNoteDropList.add(id);
}
// Starting gold
int money = this.getStartingGold();
if (money > 0) {
this.getRes().add(GameConstants.STAR_TOWER_GOLD_ITEM_ID, money);
// Add starting coin directly
int coin = this.getModifiers().getStartingCoin();
if (coin > 0) {
this.getRes().add(GameConstants.STAR_TOWER_COIN_ITEM_ID, coin);
}
}
@@ -186,6 +193,10 @@ public class StarTowerGame {
return this.build;
}
public int getDifficulty() {
return this.getData().getDifficulty();
}
public int getRandomCharId() {
return Utils.randomElement(this.getCharIds());
}
@@ -250,20 +261,6 @@ public class StarTowerGame {
this.room.onEnter();
}
public int getStartingGold() {
int gold = 0;
if (this.getManager().hasGrowthNode(10103)) {
gold += 50;
} if (this.getManager().hasGrowthNode(10403)) {
gold += 100;
} if (this.getManager().hasGrowthNode(10702)) {
gold += 200;
}
return gold;
}
public void addExp(int amount) {
this.teamExp += amount;
}
@@ -322,12 +319,25 @@ public class StarTowerGame {
return this.getItems().get(id);
}
public int getResCount(int id) {
return this.getRes().get(id);
}
public PlayerChangeInfo addItem(int id, int count) {
return this.addItem(id, count, null);
}
public PlayerChangeInfo addItem(int id, int count, PlayerChangeInfo change) {
// Create changes if null
if (change == null) {
change = new PlayerChangeInfo();
}
// Sanity check
if (count == 0) {
return change;
}
// Get item data
var itemData = GameData.getItemDataTable().get(id);
if (itemData == null) {
@@ -343,7 +353,7 @@ public class StarTowerGame {
// Clamp level
int curLevel = getPotentials().get(id);
int nextLevel = Math.min(curLevel + count, potentialData.getMaxLevel());
int nextLevel = Math.min(curLevel + count, potentialData.getMaxLevel(this));
// Sanity
count = nextLevel - curLevel;
@@ -430,7 +440,11 @@ public class StarTowerGame {
// Create shop npc if this is the last room
if (this.isOnFinalFloor()) {
// Create hawker case (shop)
cases.add(new StarTowerHawkerCase(this));
cases.add(new StarTowerHawkerCase());
// Create strengthen machine
if (this.getModifiers().isEnableEndStrengthen()) {
cases.add(new StarTowerStrengthenMachineCase());
}
} else if (this.getRoom() instanceof StarTowerBattleRoom) {
// Create recovery npc
cases.add(new StarTowerNpcRecoveryHPCase());
@@ -444,14 +458,18 @@ public class StarTowerGame {
* Creates a potential selector for a random character
*/
public StarTowerBaseCase createPotentialSelector() {
int charId = this.getRandomCharId();
return this.createPotentialSelector(charId);
return this.createPotentialSelector(0);
}
/**
* Creates a potential selector for the specified character
*/
public StarTowerBaseCase createPotentialSelector(int charId) {
// Check character id
if (charId <= 0) {
charId = this.getRandomCharId();
}
// Get character potentials
var data = GameData.getCharPotentialDataTable().get(charId);
if (data == null) {
@@ -459,20 +477,85 @@ public class StarTowerGame {
}
// Random potentials list
var potentials = new IntArrayList();
var list = new IntArrayList();
// Add potentials based on character role
boolean isMainCharacter = this.getCharIds().getInt(0) == charId;
if (isMainCharacter) {
potentials.addElements(0, data.getMasterSpecificPotentialIds());
potentials.addElements(0, data.getMasterNormalPotentialIds());
list.addElements(0, data.getMasterSpecificPotentialIds());
list.addElements(0, data.getMasterNormalPotentialIds());
} else {
potentials.addElements(0, data.getAssistSpecificPotentialIds());
potentials.addElements(0, data.getAssistNormalPotentialIds());
list.addElements(0, data.getAssistSpecificPotentialIds());
list.addElements(0, data.getAssistNormalPotentialIds());
}
potentials.addElements(0, data.getCommonPotentialIds());
list.addElements(0, data.getCommonPotentialIds());
// Remove potentials we already have maxed out
var potentials = new IntArrayList();
for (int id : list) {
// Get potential data
var potential = GameData.getPotentialDataTable().get(id);
if (potential == null) continue;
// Filter out max level ones
int curLevel = this.getPotentials().get(id);
int maxLevel = potential.getMaxLevel(this);
if (curLevel >= maxLevel) {
continue;
}
// Add
potentials.add(id);
}
// Get up to 3 random potentials
IntList selector = new IntArrayList();
for (int i = 0; i < 3; i++) {
// Sanity check
if (potentials.isEmpty()) {
break;
}
// Get random potential id
int potentialId = Utils.randomElement(potentials, true);
// Add to selector
selector.add(potentialId);
}
// Sanity check
if (selector.isEmpty()) {
return null;
}
// Creator potential selector case
return new StarTowerPotentialCase(this.getTeamLevel(), selector);
}
public StarTowerBaseCase createStrengthenSelector() {
// Random potentials list
var potentials = new IntArrayList();
// Get upgradable potentials
for (var item : this.getPotentials()) {
// Get potential data
var potential = GameData.getPotentialDataTable().get(item.getIntKey());
if (potential == null) continue;
// Check max level
int level = item.getIntValue();
if (level >= potential.getMaxLevel(this)) {
continue;
}
// Add
potentials.add(potential.getId());
}
// Get up to 3 random potentials
IntList selector = new IntArrayList();

View File

@@ -0,0 +1,107 @@
package emu.nebula.game.tower;
import lombok.Getter;
/**
* Data class to hold various modifiers for star tower.
*/
@Getter
public class StarTowerModifiers {
private StarTowerGame game;
// Strengthen machines
private boolean enableEndStrengthen;
private boolean enableShopStrengthen;
private boolean freeStrengthen;
private int strengthenDiscount;
// Bonus max potential level
private int bonusMaxPotentialLevel;
// Shop
private int shopGoodsCount;
private int shopRerollCount;
private int shopRerollPrice;
private boolean shopDiscountTier1;
private boolean shopDiscountTier2;
private boolean shopDiscountTier3;
public StarTowerModifiers(StarTowerGame game) {
this.game = game;
// Strengthen machines
this.enableEndStrengthen = this.hasGrowthNode(10601) && game.getDifficulty() >= 2;
this.enableShopStrengthen = this.hasGrowthNode(20301) && game.getDifficulty() >= 4;
this.freeStrengthen = this.hasGrowthNode(10801);
if (this.hasGrowthNode(30402)) {
this.strengthenDiscount += 60;
}
if (this.hasGrowthNode(30102)) {
this.strengthenDiscount += 30;
}
// Bonus max level
if (this.hasGrowthNode(30301)) {
this.bonusMaxPotentialLevel = 6;
} else if (this.hasGrowthNode(20601)) {
this.bonusMaxPotentialLevel = 4;
}
// Shop
if (this.hasGrowthNode(20702)) {
this.shopGoodsCount = 8;
} else if (this.hasGrowthNode(20402)) {
this.shopGoodsCount = 6;
} else if (this.hasGrowthNode(10402)) {
this.shopGoodsCount = 4;
} else {
this.shopGoodsCount = 2;
}
if (this.hasGrowthNode(20902)) {
this.shopRerollCount++;
}
if (this.hasGrowthNode(30601)) {
this.shopRerollCount++;
}
if (this.shopRerollCount > 0) {
this.shopRerollPrice = 100;
}
this.shopDiscountTier1 = this.hasGrowthNode(20202) && game.getDifficulty() >= 3;
this.shopDiscountTier2 = this.hasGrowthNode(20502) && game.getDifficulty() >= 4;
this.shopDiscountTier3 = this.hasGrowthNode(20802) && game.getDifficulty() >= 5;
}
public boolean hasGrowthNode(int nodeId) {
return this.getGame().getManager().hasGrowthNode(nodeId);
}
public int getStartingCoin() {
int gold = 0;
if (this.hasGrowthNode(10103)) {
gold += 50;
} if (this.hasGrowthNode(10403)) {
gold += 100;
} if (this.hasGrowthNode(10702)) {
gold += 200;
}
return gold;
}
public void setFreeStrengthen(boolean b) {
this.freeStrengthen = b;
}
public void consumeShopReroll() {
this.shopRerollCount = Math.max(this.shopRerollCount - 1, 0);
}
}

View File

@@ -9,16 +9,52 @@ public class StarTowerShopGoods {
private int type;
private int goodsId;
private int price;
private int discount;
private int count;
private int charPos;
private boolean sold;
public StarTowerShopGoods(int type, int goodsId, int price) {
this.type = type;
this.goodsId = goodsId;
this.price = price;
this.count = 1;
}
public void markAsSold() {
this.sold = true;
}
public void setCount(int count) {
this.count = count;
}
public void setCharPos(int charPos) {
this.charPos = charPos;
}
public boolean hasDiscount() {
return this.getDiscount() > 0;
}
public void applyDiscount(double percentage) {
this.discount = (int) Math.ceil(this.price * (1.0 - percentage));
}
public int getPrice() {
return this.price - this.discount;
}
public int getDisplayPrice() {
return this.price;
}
public int getCharId(StarTowerGame game) {
if (this.getCharPos() == 0) {
return 0;
}
int index = this.getCharPos() - 1;
return game.getCharIds().getInt(index);
}
}

View File

@@ -1,6 +1,7 @@
package emu.nebula.game.tower.cases;
import emu.nebula.game.tower.StarTowerGame;
import emu.nebula.game.tower.StarTowerModifiers;
import emu.nebula.game.tower.room.StarTowerBaseRoom;
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
import emu.nebula.proto.StarTowerInteract.StarTowerInteractReq;
@@ -22,13 +23,22 @@ public abstract class StarTowerBaseCase {
public StarTowerBaseRoom getRoom() {
return this.getGame().getRoom();
}
public StarTowerModifiers getModifiers() {
return this.getGame().getModifiers();
}
public abstract CaseType getType();
public void register(StarTowerBaseRoom room) {
this.game = room.getGame();
this.id = room.getNextCaseId();
this.onRegister();
}
public abstract CaseType getType();
public void onRegister() {
}
public abstract StarTowerInteractResp interact(StarTowerInteractReq req, StarTowerInteractResp rsp);

View File

@@ -6,6 +6,7 @@ import emu.nebula.game.player.PlayerChangeInfo;
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
import emu.nebula.proto.StarTowerInteract.StarTowerInteractReq;
import emu.nebula.proto.StarTowerInteract.StarTowerInteractResp;
import lombok.Getter;
@Getter
@@ -78,10 +79,10 @@ public class StarTowerBattleCase extends StarTowerBaseCase {
.setLv(this.getGame().getTeamLevel())
.setBattleTime(this.getGame().getBattleTime());
// Add money
int money = this.getRoom().getStage().getInteriorCurrencyQuantity();
// Add coin
int coin = this.getRoom().getStage().getInteriorCurrencyQuantity();
this.getGame().addItem(GameConstants.STAR_TOWER_GOLD_ITEM_ID, money, change);
this.getGame().addItem(GameConstants.STAR_TOWER_COIN_ITEM_ID, coin, change);
// Handle pending potential selectors
var nextCases = this.getGame().handlePendingPotentialSelectors();

View File

@@ -2,14 +2,18 @@ package emu.nebula.game.tower.cases;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import emu.nebula.GameConstants;
import emu.nebula.game.tower.StarTowerGame;
import emu.nebula.game.player.PlayerChangeInfo;
import emu.nebula.game.tower.StarTowerShopGoods;
import emu.nebula.proto.PublicStarTower.HawkerCaseData;
import emu.nebula.proto.PublicStarTower.HawkerGoods;
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
import emu.nebula.proto.StarTowerInteract.StarTowerInteractReq;
import emu.nebula.proto.StarTowerInteract.StarTowerInteractResp;
import emu.nebula.util.Utils;
import lombok.Getter;
@Getter
@@ -19,76 +23,225 @@ public class StarTowerHawkerCase extends StarTowerBaseCase {
public StarTowerHawkerCase() {
this.goods = new HashMap<>();
}
public StarTowerHawkerCase(StarTowerGame game) {
this();
// Create shop goods
for (int i = 0; i < 6; i++) {
this.addGoods(new StarTowerShopGoods(1, 1, 200));
}
// TODO apply discounts based on star tower talents
}
@Override
public CaseType getType() {
return CaseType.Hawker;
}
@Override
public void onRegister() {
this.initGoods();
}
public void initGoods() {
// Clear goods
this.getGoods().clear();
// Caclulate amount of potentials/sub notes to sell
int total = getModifiers().getShopGoodsCount();
int minPotentials = Math.max(total / 2, 2);
int maxPotentials = Math.max(total - 1, minPotentials);
int potentials = Utils.randomRange(minPotentials, maxPotentials);
int subNotes = total - potentials;
// Add goods
for (int i = 0; i < potentials; i++) {
// Create potential selector shop item
var goods = new StarTowerShopGoods(1, 102, 200);
// Add character specific potentials
if (Utils.generateRandomDouble() < .2) {
goods.setCharPos(1);
}
// Add to goods map
this.addGoods(goods);
}
for (int i = 0; i < subNotes; i++) {
// Randomize sub note
int id = Utils.randomElement(this.getGame().getSubNoteDropList());
int count = Utils.randomRange(3, 10);
// Create sub note shop item
var goods = new StarTowerShopGoods(2, id, 15 * count);
goods.setCount(count);
// Add to goods map
this.addGoods(goods);
}
// Apply discounts based on star tower talents
if (getModifiers().isShopDiscountTier1()) {
this.applyDiscount(1.0, 2, 0.8);
}
if (getModifiers().isShopDiscountTier2()) {
this.applyDiscount(0.3, 1, 0.5);
}
if (getModifiers().isShopDiscountTier3()) {
this.applyDiscount(1.0, 1, 0.5);
}
}
private void applyDiscount(double chance, int times, double percentage) {
// Check chance
double random = Utils.generateRandomDouble();
if (random > chance) {
return;
}
// Create goods list
var list = this.getGoods().values().stream()
.filter(g -> !g.hasDiscount())
.collect(Collectors.toList());
// Apply discounts
for (int i = 0; i < times; i++) {
// Sanity check
if (list.isEmpty()) {
break;
}
// Get goods and apply discount
var goods = Utils.randomElement(list, true);
goods.applyDiscount(percentage);
}
}
public void addGoods(StarTowerShopGoods goods) {
this.getGoods().put(getGoods().size() + 1, goods);
}
@Override
public StarTowerInteractResp interact(StarTowerInteractReq req, StarTowerInteractResp rsp) {
// Set nil resp
// Set nil resp
rsp.getMutableNilResp();
// Get goods
var goods = this.getGoods().get(req.getHawkerReq().getSid());
// Get hawker req
var hawker = req.getHawkerReq();
// Make sure we have enough currency
int gold = this.getGame().getRes().get(GameConstants.STAR_TOWER_GOLD_ITEM_ID);
if (gold < goods.getPrice() || goods.isSold()) {
return rsp;
if (hawker.hasReRoll()) {
// Refresh shop items
this.refresh(rsp);
} else if (hawker.hasSid()) {
// Buy shop items
this.buy(hawker.getSid(), rsp);
}
// Mark goods as sold
goods.markAsSold();
// Add case
this.getGame().addCase(rsp.getMutableCases(), this.getGame().createPotentialSelector());
// Remove items
var change = this.getGame().addItem(GameConstants.STAR_TOWER_GOLD_ITEM_ID, -goods.getPrice(), null);
// Set change info
rsp.setChange(change.toProto());
// Success
return rsp;
}
private void refresh(StarTowerInteractResp rsp) {
// Check if we can refresh
if (this.getModifiers().getShopRerollCount() <= 0) {
return;
}
// Make sure we have enough currency
int coin = this.getGame().getResCount(GameConstants.STAR_TOWER_COIN_ITEM_ID);
int price = this.getModifiers().getShopRerollPrice();
if (coin < price) {
return;
}
// Create new goods
this.initGoods();
// Consume reroll count
this.getGame().getModifiers().consumeShopReroll();
// Set in proto
rsp.getMutableSelectResp()
.setHawkerCase(this.toHawkerCaseProto());
// Remove coins
var change = this.getGame().addItem(GameConstants.STAR_TOWER_COIN_ITEM_ID, -price);
// Set change info
rsp.setChange(change.toProto());
}
private void buy(int sid, StarTowerInteractResp rsp) {
// Get goods
var goods = this.getGoods().get(sid);
if (goods == null) {
return;
}
// Make sure we have enough currency
int coin = this.getGame().getResCount(GameConstants.STAR_TOWER_COIN_ITEM_ID);
int price = goods.getPrice();
if (coin < price || goods.isSold()) {
return;
}
// Mark goods as sold
goods.markAsSold();
// Create change info
var change = new PlayerChangeInfo();
// Add goods
if (goods.getType() == 1) {
// Potential selector
int charId = goods.getCharId(this.getGame());
this.getGame().addCase(rsp.getMutableCases(), this.getGame().createPotentialSelector(charId));
} else {
// Sub notes
this.getGame().addItem(goods.getGoodsId(), goods.getCount(), change);
}
// Remove coins
this.getGame().addItem(GameConstants.STAR_TOWER_COIN_ITEM_ID, -price, change);
// Set change info
rsp.setChange(change.toProto());
}
// Proto
@Override
public void encodeProto(StarTowerRoomCase proto) {
var hawker = proto.getMutableHawkerCase();
private HawkerCaseData toHawkerCaseProto() {
var hawker = HawkerCaseData.newInstance();
if (this.getModifiers().getShopRerollCount() > 0) {
hawker.setCanReRoll(true);
hawker.setReRollTimes(this.getModifiers().getShopRerollCount());
hawker.setReRollPrice(this.getModifiers().getShopRerollPrice());
}
for (var entry : this.getGoods().entrySet()) {
var sid = entry.getKey();
var goods = entry.getValue();
var info = HawkerGoods.newInstance()
.setIdx(goods.getGoodsId())
.setIdx(1)
.setSid(sid)
.setType(goods.getType())
.setGoodsId(102) // ?
.setPrice(goods.getPrice())
.setGoodsId(goods.getGoodsId())
.setPrice(goods.getDisplayPrice())
.setTag(1);
if (goods.hasDiscount()) {
info.setDiscount(goods.getPrice());
}
if (goods.getCharPos() > 0) {
info.setCharPos(goods.getCharPos());
}
hawker.addList(info);
}
return hawker;
}
@Override
public void encodeProto(StarTowerRoomCase proto) {
proto.setHawkerCase(this.toHawkerCaseProto());
}
}

View File

@@ -44,7 +44,7 @@ public class StarTowerPotentialCase extends StarTowerBaseCase {
}
// Add item
var change = this.getGame().addItem(id, 1, null);
var change = this.getGame().addItem(id, 1);
// Set change
rsp.setChange(change.toProto());

View File

@@ -0,0 +1,92 @@
package emu.nebula.game.tower.cases;
import emu.nebula.GameConstants;
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
import emu.nebula.proto.StarTowerInteract.StarTowerInteractReq;
import emu.nebula.proto.StarTowerInteract.StarTowerInteractResp;
import lombok.Getter;
@Getter
public class StarTowerStrengthenMachineCase extends StarTowerBaseCase {
private boolean free;
private int discount;
private int times;
@Override
public void onRegister() {
// Set strengthen price
this.free = this.getModifiers().isFreeStrengthen();
this.discount = this.getModifiers().getStrengthenDiscount();
}
public int getPrice() {
if (this.free) {
return 0;
}
int price = 120 + (this.times * 60) - this.discount;
return Math.max(price, 0);
}
public void increasePrice() {
if (this.free) {
this.free = false;
this.getModifiers().setFreeStrengthen(false);
} else {
this.times++;
}
}
@Override
public CaseType getType() {
return CaseType.StrengthenMachine;
}
@Override
public StarTowerInteractResp interact(StarTowerInteractReq req, StarTowerInteractResp rsp) {
// Init case
StarTowerBaseCase towerCase = null;
// Check coin
int coin = getGame().getResCount(GameConstants.STAR_TOWER_COIN_ITEM_ID);
int price = this.getPrice();
if (coin >= price) {
towerCase = getGame().createStrengthenSelector();
}
if (towerCase != null) {
// Add enhancement selector case
this.getRoom().addCase(rsp.getMutableCases(), towerCase);
// Remove coins
var change = this.getGame().addItem(GameConstants.STAR_TOWER_COIN_ITEM_ID, -price);
// Set change info
rsp.setChange(change.toProto());
// Increment price
this.increasePrice();
}
// Set success result
rsp.getMutableStrengthenMachineResp()
.setBuySucceed(towerCase != null);
// Complete
return rsp;
}
// Proto
@Override
public void encodeProto(StarTowerRoomCase proto) {
// Set field in the proto
proto.getMutableStrengthenMachineCase()
.setFirstFree(this.isFree())
.setDiscount(this.getDiscount())
.setTimes(this.getTimes());
}
}

View File

@@ -1,10 +1,8 @@
package emu.nebula.game.tower.room;
import java.util.ArrayList;
import java.util.List;
import emu.nebula.data.resources.StarTowerStageDef;
import emu.nebula.game.tower.StarTowerGame;
import emu.nebula.game.tower.StarTowerModifiers;
import emu.nebula.game.tower.cases.CaseType;
import emu.nebula.game.tower.cases.StarTowerBaseCase;
import emu.nebula.game.tower.cases.StarTowerSyncHPCase;
@@ -12,7 +10,12 @@ import emu.nebula.proto.PublicStarTower.InteractEnterReq;
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
import emu.nebula.proto.PublicStarTower.StarTowerRoomData;
import emu.nebula.proto.StarTowerApply.StarTowerApplyReq;
import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import lombok.Getter;
import us.hebi.quickbuf.RepeatedMessage;
@Getter
@@ -29,7 +32,7 @@ public class StarTowerBaseRoom {
// Cases
private int lastCaseId = 0;
private List<StarTowerBaseCase> cases;
private Int2ObjectMap<StarTowerBaseCase> cases;
// Misc
private boolean hasDoor;
@@ -37,7 +40,7 @@ public class StarTowerBaseRoom {
public StarTowerBaseRoom(StarTowerGame game, StarTowerStageDef stage) {
this.game = game;
this.stage = stage;
this.cases = new ArrayList<>();
this.cases = new Int2ObjectLinkedOpenHashMap<>();
}
public int getType() {
@@ -48,6 +51,14 @@ public class StarTowerBaseRoom {
return this.hasDoor;
}
public StarTowerModifiers getModifiers() {
return this.getGame().getModifiers();
}
public StarTowerBaseCase createExit() {
return this.getGame().createExit();
}
// Map info
public void setMapInfo(StarTowerApplyReq req) {
@@ -71,10 +82,7 @@ public class StarTowerBaseRoom {
}
public StarTowerBaseCase getCase(int id) {
return this.getCases().stream()
.filter(c -> c.getId() == id)
.findFirst()
.orElse(null);
return this.getCases().get(id);
}
public StarTowerBaseCase addCase(StarTowerBaseCase towerCase) {
@@ -82,12 +90,12 @@ public class StarTowerBaseRoom {
}
public StarTowerBaseCase addCase(RepeatedMessage<StarTowerRoomCase> cases, StarTowerBaseCase towerCase) {
// Add to cases list
this.getCases().add(towerCase);
// Set game for tower case
towerCase.register(this);
// Add to cases list
this.getCases().put(towerCase.getId(), towerCase);
// Add case to proto
if (cases != null) {
cases.add(towerCase.toProto());
@@ -105,11 +113,11 @@ public class StarTowerBaseRoom {
// Events
public void onEnter() {
// Create door case
this.getGame().createExit();
// Create sync hp case
this.getGame().addCase(new StarTowerSyncHPCase());
this.addCase(new StarTowerSyncHPCase());
// Create door case
this.createExit();
}
// Proto
@@ -118,7 +126,7 @@ public class StarTowerBaseRoom {
var proto = emu.nebula.proto.PublicStarTower.StarTowerRoom.newInstance()
.setData(this.getDataProto());
for (var towerCase : this.getCases()) {
for (var towerCase : this.getCases().values()) {
proto.addCases(towerCase.toProto());
}

View File

@@ -18,9 +18,9 @@ public class StarTowerBattleRoom extends StarTowerBaseRoom {
public void onEnter() {
// Create battle case
this.getGame().setPendingSubNotes(Utils.randomRange(1, 3));
this.getGame().addCase(new StarTowerBattleCase(this.getGame().getPendingSubNotes()));
this.addCase(new StarTowerBattleCase(this.getGame().getPendingSubNotes()));
// Create sync hp case
this.getGame().addCase(new StarTowerSyncHPCase());
this.addCase(new StarTowerSyncHPCase());
}
}

View File

@@ -15,10 +15,10 @@ public class StarTowerEventRoom extends StarTowerBaseRoom {
@Override
public void onEnter() {
// Create door case
this.getGame().createExit();
// Create sync hp case
this.getGame().addCase(new StarTowerSyncHPCase());
this.addCase(new StarTowerSyncHPCase());
// Create door case
this.createExit();
}
}

View File

@@ -3,6 +3,7 @@ package emu.nebula.game.tower.room;
import emu.nebula.data.resources.StarTowerStageDef;
import emu.nebula.game.tower.StarTowerGame;
import emu.nebula.game.tower.cases.StarTowerHawkerCase;
import emu.nebula.game.tower.cases.StarTowerStrengthenMachineCase;
import emu.nebula.game.tower.cases.StarTowerSyncHPCase;
import lombok.Getter;
@@ -16,12 +17,17 @@ public class StarTowerHawkerRoom extends StarTowerBaseRoom {
@Override
public void onEnter() {
// Create hawker case (shop)
this.getGame().addCase(new StarTowerHawkerCase(this.getGame()));
this.addCase(new StarTowerHawkerCase());
// Create door case
this.getGame().createExit();
// Create strengthen machine
if (this.getModifiers().isEnableShopStrengthen()) {
this.addCase(new StarTowerStrengthenMachineCase());
}
// Create sync hp case
this.getGame().addCase(new StarTowerSyncHPCase());
this.addCase(new StarTowerSyncHPCase());
// Create door case
this.createExit();
}
}

View File

@@ -141,6 +141,9 @@ public class HttpServer {
if (this.getType().runGame()) {
this.addGameServerRoutes();
}
// Custom api route(s)
getApp().post("/api/command", new RemoteHandler());
// Exception handler
getApp().exception(Exception.class, (e, c) -> {
@@ -154,8 +157,8 @@ public class HttpServer {
private void addLoginServerRoutes() {
// https://en-sdk-api.yostarplat.com/
getApp().post("/common/config", new CommonConfigHandler(this));
getApp().post("/common/version", new HttpJsonResponse(
"{\"Code\":200,\"Data\":{\"Agreement\":[{\"Version\":\"0.1\",\"Type\":\"user_agreement\",\"Title\":\"用户协议\",\"Content\":\"\",\"Lang\":\"en\"},{\"Version\":\"0.1\",\"Type\":\"privacy_agreement\",\"Title\":\"隐私政策\",\"Content\":\"\",\"Lang\":\"en\"}],\"ErrorCode\":\"4.4\"},\"Msg\":\"OK\"}"));
getApp().post("/common/client-code", new CommonClientCodeHandler());
getApp().post("/common/version", new HttpJsonResponse("{\"Code\":200,\"Data\":{\"Agreement\":[{\"Version\":\"0.1\",\"Type\":\"user_agreement\",\"Title\":\"用户协议\",\"Content\":\"\",\"Lang\":\"en\"},{\"Version\":\"0.1\",\"Type\":\"privacy_agreement\",\"Title\":\"隐私政策\",\"Content\":\"\",\"Lang\":\"en\"}],\"ErrorCode\":\"4.4\"},\"Msg\":\"OK\"}"));
getApp().post("/user/detail", new UserLoginHandler());
getApp().post("/user/set", new UserSetDataHandler());
@@ -163,16 +166,11 @@ public class HttpServer {
getApp().post("/user/quick-login", new UserLoginHandler());
getApp().post("/yostar/get-auth", new GetAuthHandler());
getApp().post("/yostar/send-code", new HttpJsonResponse("{\"Code\":200,\"Data\":{},\"Msg\":\"OK\"}")); // Dummy
// handler
getApp().post("/yostar/send-code", new HttpJsonResponse("{\"Code\":200,\"Data\":{},\"Msg\":\"OK\"}")); // Dummy handler
// https://nova-static.stellasora.global/
getApp().get("/meta/serverlist.html", new MetaServerlistHandler(this));
getApp().get("/meta/win.html", new MetaWinHandler(this));
getApp().post("/api/command", new RemoteHandler());
getApp().get("/meta/*.html", new MetaPatchListHandler(this));
}
private void addGameServerRoutes() {

View File

@@ -5,6 +5,7 @@ import emu.nebula.net.NetMsgId;
import emu.nebula.proto.StarTowerApply.StarTowerApplyReq;
import emu.nebula.proto.StarTowerApply.StarTowerApplyResp;
import emu.nebula.net.HandlerId;
import emu.nebula.GameConstants;
import emu.nebula.game.tower.StarTowerGame;
import emu.nebula.net.GameSession;
@@ -29,6 +30,7 @@ public class HandlerStarTowerApplyReq extends NetHandler {
// Create response
var rsp = StarTowerApplyResp.newInstance()
.setLastId(req.getId())
.setCoinQty(game.getResCount(GameConstants.STAR_TOWER_COIN_ITEM_ID))
.setInfo(game.toProto())
.setChange(change.toProto());

File diff suppressed because one or more lines are too long

View File

@@ -12,10 +12,10 @@ import lombok.AccessLevel;
import lombok.Getter;
@Getter(AccessLevel.PRIVATE)
public class MetaWinHandler implements Handler {
public class MetaPatchListHandler implements Handler {
private HttpServer server;
public MetaWinHandler(HttpServer server) {
public MetaPatchListHandler(HttpServer server) {
this.server = server;
}

View File

@@ -179,12 +179,34 @@ public class Utils {
}
public static <T> T randomElement(List<T> list) {
return list.get(ThreadLocalRandom.current().nextInt(0, list.size()));
return randomElement(list, false);
}
public static <T> T randomElement(List<T> list, boolean remove) {
int index = ThreadLocalRandom.current().nextInt(0, list.size());
var object = list.get(index);
if (remove) {
list.remove(index);
}
return object;
}
public static int randomElement(IntList list) {
return list.getInt(ThreadLocalRandom.current().nextInt(0, list.size()));
}
public static int randomElement(IntList list, boolean remove) {
int index = ThreadLocalRandom.current().nextInt(0, list.size());
int object = list.getInt(index);
if (remove) {
list.removeInt(index);
}
return object;
}
/**
* Checks if an integer array contains a value