Implement new event

This commit is contained in:
Melledy
2025-12-08 22:28:47 -08:00
parent 80a181680b
commit c5f339c8be
20 changed files with 1020 additions and 8 deletions
@@ -109,9 +109,13 @@ public class ActivityManager extends PlayerManager implements GameDatabaseObject
return null;
}
// TODO improve activity creation
GameActivity activity = switch (data.getType()) {
case Trial -> new TrialActivity(this, data);
case TowerDefense -> new TowerDefenseActivity(this, data);
case Trial -> new TrialActivity(this, data);
case Levels -> new LevelsActivity(this, data);
case Task -> new TaskActivity(this, data);
case Shop -> new ShopActivity(this, data);
default -> null;
};
@@ -15,12 +15,20 @@ public class ActivityModule extends GameContextModule {
this.activities = new IntArrayList();
// Hardcode these activities for now
this.activities.add(700102);
this.activities.add(700103);
// TODO make an activity json file to read activity ids from
// Trial activities
this.activities.add(700104);
this.activities.add(700107);
this.activities.add(700108);
this.activities.add(102001); // Tower defense activity
// Tower defense activity
this.activities.add(102001);
//
this.activities.add(1010201);
this.activities.add(1010203);
this.activities.add(1010204);
//this.activities.add(101002);
//this.activities.add(101003);
@@ -0,0 +1,93 @@
package emu.nebula.game.activity;
import dev.morphia.annotations.Entity;
import emu.nebula.data.resources.ActivityTaskDef;
import emu.nebula.proto.Public.Quest;
import emu.nebula.proto.Public.QuestProgress;
import lombok.Getter;
import lombok.Setter;
@Getter
@Entity(useDiscriminator = false)
public class ActivityTaskQuest {
private int id;
private int cond;
private int curProgress;
private int maxProgress;
@Setter
private boolean claimed;
@Deprecated
public ActivityTaskQuest() {
}
public ActivityTaskQuest(ActivityTaskDef data) {
this.id = data.getId();
this.cond = data.getCompleteCond();
this.maxProgress = data.getAimNumShow();
}
public void resetProgress() {
this.curProgress = 0;
this.claimed = false;
}
public boolean isComplete() {
return this.curProgress >= this.maxProgress;
}
private int getStatus() {
if (this.isClaimed()) {
return 2;
} else if (this.isComplete()) {
return 1;
}
return 0;
}
public boolean trigger(int condition, int progress, int param1, int param2) {
// Sanity check
if (this.isComplete()) {
return false;
}
// Skip if not the correct condition
if (this.cond != condition) {
return false;
}
// Check quest param TODO
// Get new progress
int newProgress = Math.min(this.curProgress + progress, this.maxProgress);
// Set
if (this.curProgress != newProgress) {
this.curProgress = newProgress;
return true;
}
return false;
}
// Proto
public Quest toProto() {
var progress = QuestProgress.newInstance()
.setCur(this.getCurProgress())
.setMax(this.getMaxProgress());
var proto = Quest.newInstance()
.setId(this.getId())
.setStatus(this.getStatus())
.addProgress(progress);
return proto;
}
}
@@ -0,0 +1,209 @@
package emu.nebula.game.activity.type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import dev.morphia.annotations.Entity;
import emu.nebula.GameConstants;
import emu.nebula.data.GameData;
import emu.nebula.data.resources.ActivityDef;
import emu.nebula.data.resources.ActivityLevelsLevelDef;
import emu.nebula.game.activity.ActivityManager;
import emu.nebula.game.activity.GameActivity;
import emu.nebula.game.instance.InstanceSettleData;
import emu.nebula.game.inventory.ItemParamMap;
import emu.nebula.game.player.PlayerChangeInfo;
import emu.nebula.game.quest.QuestCondition;
import emu.nebula.proto.ActivityDetail.ActivityMsg;
import emu.nebula.proto.Public.ActivityLevel;
import lombok.Getter;
import lombok.Setter;
@Getter
@Entity
public class LevelsActivity extends GameActivity {
private Map<Integer, ActivityLevelInfo> levels;
// Apply level data
private transient ActivityLevelsLevelDef level;
private transient long buildId;
@Deprecated // Morphia only
public LevelsActivity() {
}
public LevelsActivity(ActivityManager manager, ActivityDef data) {
super(manager, data);
this.levels = new HashMap<>();
}
public boolean apply(int levelId, long buildId) {
// Verify level
var level = GameData.getActivityLevelsLevelDataTable().get(levelId);
if (level == null || level.getActivityId() != this.getId()) {
return false;
}
// Verify build
var build = this.getPlayer().getStarTowerManager().getBuildById(buildId);
if (build == null) {
return false;
}
// Set
this.level = level;
this.buildId = buildId;
// Success
return true;
}
public PlayerChangeInfo settle(int star) {
// Check energy
if (!this.getLevel().hasEnergy(this.getPlayer(), 1)) {
return null;
}
// Calculate settle data
var settleData = new InstanceSettleData();
settleData.setWin(star > 0);
settleData.setFirst(settleData.isWin() && !this.getLevels().containsKey(this.getLevel().getId()));
// Init player change info
var change = new PlayerChangeInfo();
// Handle win
if (settleData.isWin()) {
// Calculate energy and exp
settleData.setExp(this.getLevel().getEnergyConsume());
getPlayer().consumeEnergy(settleData.getExp(), change);
// Calculate rewards
settleData.generateRewards(this.getLevel());
// Add to inventory
getPlayer().getInventory().addItem(GameConstants.EXP_ITEM_ID, settleData.getExp(), change);
getPlayer().getInventory().addItems(settleData.getRewards(), change);
getPlayer().getInventory().addItems(settleData.getFirstRewards(), change);
// Log
var level = getLevels().computeIfAbsent(this.getLevel().getId(), i -> new ActivityLevelInfo());
level.setStar(star);
level.setBuildId(this.getBuildId());
// Save to database
this.save();
// Quest triggers
this.getPlayer().trigger(QuestCondition.BattleTotal, 1);
}
// Set extra data
change.setExtraData(settleData);
// Success
return change;
}
public PlayerChangeInfo sweep(ActivityLevelsLevelDef data, int count) {
// Sanity check count
if (count <= 0) {
return null;
}
// Check if we have 3 starred this instance
var level = this.getLevels().get(data.getId());
if (level == null || level.getStar() != 3) {
return null;
}
// Check energy cost
int energyCost = data.getEnergyConsume() * count;
if (this.getPlayer().getEnergy() < energyCost) {
return null;
}
// Init variables
var change = new PlayerChangeInfo();
var list = new ArrayList<ItemParamMap>();
// Consume exp
getPlayer().consumeEnergy(energyCost, change);
getPlayer().getInventory().addItem(GameConstants.EXP_ITEM_ID, energyCost, change);
// Calculate total rewards
var totalRewards = new ItemParamMap();
for (int i = 0; i < count; i++) {
// Generate rewards for each settle count
var rewards = data.getRewards().generate();
// Add to reward list
list.add(rewards);
// Add to total rewards
totalRewards.add(rewards);
}
// Add total rewards to inventory
getPlayer().getInventory().addItems(totalRewards, change);
// Set reward list in change info so we can serialize it in the response proto later
change.setExtraData(list);
// Quest triggers
this.getPlayer().trigger(QuestCondition.BattleTotal, count);
// Success
return change.setSuccess(true);
}
// Proto
@Override
public void encodeActivityMsg(ActivityMsg msg) {
var proto = msg.getMutableLevels();
for (var entry : this.getLevels().entrySet()) {
int id = entry.getKey();
var level = entry.getValue();
var info = level.toProto()
.setId(id);
proto.addLevels(info);
}
}
@Setter
@Getter
@Entity(useDiscriminator = false)
public static class ActivityLevelInfo {
private int star;
private long buildId;
public ActivityLevelInfo() {
}
// Proto
public ActivityLevel toProto() {
var proto = ActivityLevel.newInstance()
.setStar(this.getStar())
.setBuildId(this.getBuildId());
return proto;
}
}
}
@@ -0,0 +1,152 @@
package emu.nebula.game.activity.type;
import java.util.HashMap;
import java.util.Map;
import dev.morphia.annotations.Entity;
import emu.nebula.data.GameData;
import emu.nebula.data.resources.ActivityDef;
import emu.nebula.data.resources.ActivityShopControlDef;
import emu.nebula.data.resources.ActivityShopDef;
import emu.nebula.game.activity.ActivityManager;
import emu.nebula.game.activity.GameActivity;
import emu.nebula.game.inventory.ItemParamMap;
import emu.nebula.game.player.PlayerChangeInfo;
import emu.nebula.proto.ActivityDetail.ActivityMsg;
import emu.nebula.proto.Public.BoughtGoods;
import emu.nebula.proto.Public.ResidentShop;
import lombok.Getter;
@Getter
@Entity
public class ShopActivity extends GameActivity {
private Map<Integer, ActivityShopInfo> shops;
@Deprecated // Morphia only
public ShopActivity() {
}
public ShopActivity(ActivityManager manager, ActivityDef data) {
super(manager, data);
this.shops = new HashMap<>();
// Load shops
var control = GameData.getActivityShopControlDataTable().get(data.getId());
if (control != null) {
this.initShops(control);
}
}
private void initShops(ActivityShopControlDef control) {
for (int id : control.getShopIds()) {
var data = GameData.getActivityShopDataTable().get(id);
if (data == null) {
continue;
}
// Create resident shop
var shop = new ActivityShopInfo(data);
// Add
this.getShops().put(data.getId(), shop);
}
}
public PlayerChangeInfo buy(int shopId, int goodsId, int count) {
// Get shop
var shop = this.getShops().get(shopId);
if (shop == null) return null;
// Get shop data
var data = GameData.getActivityShopDataTable().get(shopId);
if (data == null) return null;
// Get goods
var goods = data.getGoods().get(goodsId);
if (goods == null) return null;
// Check limit
if (goods.getMaximumLimit() > 0) {
var limit = goods.getMaximumLimit() - shop.getBoughtCount(goodsId);
if (count > limit) {
return null;
}
}
// Purchase
var change = getPlayer().getInventory().buyItem(data.getCurrencyItemId(), goods.getPrice(), goods.getItems(), count);
// Purchase failed
if (change == null) {
return null;
}
// Set log
shop.getBoughtGoods().add(goodsId, count);
// Save
this.save();
// Set extra data
change.setExtraData(shop);
// Success
return change;
}
// Proto
@Override
public void encodeActivityMsg(ActivityMsg msg) {
var proto = msg.getMutableShop();
for (var entry : this.getShops().entrySet()) {
var id = entry.getKey();
var shop = entry.getValue();
var info = shop.toProto()
.setId(id);
proto.addShops(info);
}
}
@Getter
@Entity(useDiscriminator = false)
public static class ActivityShopInfo {
private ItemParamMap boughtGoods;
@Deprecated // Morphia only
public ActivityShopInfo() {
}
public ActivityShopInfo(ActivityShopDef data) {
this.boughtGoods = new ItemParamMap();
}
public int getBoughtCount(int goodsId) {
return this.getBoughtGoods().get(goodsId);
}
// Proto
public ResidentShop toProto() {
var proto = ResidentShop.newInstance();
for (var item : this.getBoughtGoods().int2IntEntrySet()) {
var info = BoughtGoods.newInstance()
.setId(item.getIntKey())
.setNumber(item.getIntValue());
proto.addInfos(info);
}
return proto;
}
}
}
@@ -0,0 +1,72 @@
package emu.nebula.game.activity.type;
import java.util.HashMap;
import java.util.Map;
import dev.morphia.annotations.Entity;
import emu.nebula.data.GameData;
import emu.nebula.data.resources.ActivityDef;
import emu.nebula.game.activity.ActivityManager;
import emu.nebula.game.activity.ActivityTaskQuest;
import emu.nebula.game.activity.GameActivity;
import emu.nebula.proto.ActivityDetail.ActivityMsg;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import lombok.Getter;
@Getter
@Entity
public class TaskActivity extends GameActivity {
private Map<Integer, ActivityTaskQuest> quests;
private IntSet completedGroups;
@Deprecated // Morphia only
public TaskActivity() {
}
public TaskActivity(ActivityManager manager, ActivityDef data) {
super(manager, data);
this.quests = new HashMap<>();
this.completedGroups = new IntOpenHashSet();
var groupSet = new IntOpenHashSet();
for (var group : GameData.getActivityTaskGroupDataTable()) {
if (group.getActivityId() != this.getId()) {
continue;
}
groupSet.add(group.getId());
}
for (var task : GameData.getActivityTaskDataTable()) {
if (!groupSet.contains(task.getActivityTaskGroupId())) {
continue;
}
var quest = new ActivityTaskQuest(task);
this.getQuests().put(quest.getId(), quest);
}
}
// Proto
@Override
public void encodeActivityMsg(ActivityMsg msg) {
var proto = msg.getMutableTask();
for (int id : this.getCompletedGroups()) {
proto.addGroupIds(id);
}
var tasks = proto.getMutableActivityTasks();
for (var quest : this.getQuests().values()) {
tasks.addList(quest.toProto());
}
}
}