mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-12-16 08:56:04 +01:00
Merge remote-tracking branch 'origin/development' into development
This commit is contained in:
@@ -92,15 +92,16 @@ public class HealAbilityManager {
|
||||
public HealAbilityManager (Player player) {
|
||||
this.player = player;
|
||||
healDataAvatarList = new ArrayList();
|
||||
healDataAvatarList.add(new HealDataAvatar(10000054, "Kokomi", 0).addHealData("E", "ElementalArt_Heal_MaxHP_Base_Percentage", "ElementalArt_Heal_Base_Amount", false));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000054, "Kokomi", 0).addHealData("E", "ElementalArt_Heal_MaxHP_Base_Percentage", "ElementalArt_Heal_Base_Amount", false).addHealData("Q", "Avatar_Kokomi_ElementalBurst_Heal", 0.0172f, 212f, false));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000003, "Qin", 1).addHealData("Q", "Heal", "BurstHealConst", true));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000034, "Noel", 2).addHealData("E", "OnAttack_HealthRate", 0.452f, 282f, true));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000032, "Bennett", 0).addHealData("Q", "HealMaxHpRatio", "HealConst", false));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000039, "Diona", 0).addHealData("Q", "HealHPRatio", "HealHP_Const", false));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000053, "Sayu", 1).addHealData("Q", "Constellation_6_Damage", "Heal_BaseAmount", true).addHealData("Q", "Heal_AttackRatio", "Constellation_6_Heal", true));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000014, "Barbara", 0).addHealData("E", "HealHPOnAdded", "HealHPOnAdded_Const", true).addHealData("E", "HealHP_OnHittingOthers", "HealHP_Const_OnHittingOthers", true));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000014, "Barbara", 0).addHealData("E", "HealHPOnAdded", "HealHPOnAdded_Const", true).addHealData("E", "HealHP_OnHittingOthers", "HealHP_Const_OnHittingOthers", true).addHealData("Q", "Avatar_Barbara_IdolHeal", 0.374f, 4660f, true));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000065, "Shinobu", 0).addHealData("E", "ElementalArt_Heal_MaxHP_Percentage", 0.064f, 795f, false));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000035, "Qiqi", 1).addHealData("E", "HealHP_OnHittingOthers", "HealHP_Const_OnHittingOthers", true).addHealData("E", "ElementalArt_HealHp_Ratio", "ElementalArt_HealHp_Const", true));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000035, "Qiqi", 1).addHealData("E", "HealHP_OnHittingOthers", "HealHP_Const_OnHittingOthers", true).addHealData("E", "ElementalArt_HealHp_Ratio", "ElementalArt_HealHp_Const", true).addHealData("Q", "Avatar_Qiqi_ElementalBurst_ApplyModifier", 0.0191f, 1588f, false));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000046, "Hutao", 0).addHealData("Q", "Avatar_Hutao_VermilionBite_BakeMesh", 0.1166f, 0f, false));
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
@@ -128,7 +129,7 @@ public class HealAbilityManager {
|
||||
int fightPropertyType = 0;
|
||||
float healAmount = 0;
|
||||
float ratio = 0, base = 0;
|
||||
float maxHP, curAttack, curDefense;
|
||||
float maxHP, curHP, curAttack, curDefense;
|
||||
Map<String, Float> map = sourceEntity.getMetaOverrideMap();
|
||||
|
||||
for(int i = 0 ; i < healDataAvatarList.size() ; i ++) {
|
||||
@@ -139,7 +140,7 @@ public class HealAbilityManager {
|
||||
|
||||
for(int j = 0 ; j < healDataList.size(); j++) {
|
||||
HealData healData = healDataList.get(j);
|
||||
if(map.containsKey(healData.sRatio)) {
|
||||
if(map.containsKey(healData.sRatio) || modifierString.equals(healData.sRatio)) {
|
||||
if(healData.isString) {
|
||||
ratio = map.get(healData.sRatio);
|
||||
base = map.get(healData.sBase);
|
||||
@@ -173,8 +174,15 @@ public class HealAbilityManager {
|
||||
|
||||
if(healActionAvatar != null) {
|
||||
maxHP = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||
curHP = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
||||
curAttack = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_ATTACK);
|
||||
curDefense = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_DEFENSE);
|
||||
|
||||
//Special case for Hu Tao:
|
||||
if(healDataAvatar.avatarName.equals("Hutao") && curHP <= maxHP * 0.5 && ratio != 0) {
|
||||
ratio = 0.1555f;
|
||||
}
|
||||
|
||||
switch(fightPropertyType) {
|
||||
case 0:
|
||||
healAmount = ratio * maxHP + base;
|
||||
|
||||
@@ -242,6 +242,23 @@ public class Avatar {
|
||||
this.promoteLevel = promoteLevel;
|
||||
}
|
||||
|
||||
static public int getMinPromoteLevel(int level) {
|
||||
if (level > 80) {
|
||||
return 6;
|
||||
} else if (level > 70) {
|
||||
return 5;
|
||||
} else if (level > 60) {
|
||||
return 4;
|
||||
} else if (level > 50) {
|
||||
return 3;
|
||||
} else if (level > 40) {
|
||||
return 2;
|
||||
} else if (level > 20) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Int2ObjectMap<GameItem> getEquips() {
|
||||
return equips;
|
||||
}
|
||||
|
||||
@@ -1,23 +1,53 @@
|
||||
package emu.grasscutter.game.battlepass;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import dev.morphia.annotations.Id;
|
||||
import dev.morphia.annotations.Indexed;
|
||||
import dev.morphia.annotations.Transient;
|
||||
import emu.grasscutter.GameConstants;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
import emu.grasscutter.data.excels.BattlePassRewardData;
|
||||
import emu.grasscutter.data.excels.RewardData;
|
||||
import emu.grasscutter.database.DatabaseHelper;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.game.props.BattlePassMissionRefreshType;
|
||||
import emu.grasscutter.game.props.BattlePassMissionStatus;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.net.proto.BattlePassCycleOuterClass.BattlePassCycle;
|
||||
import emu.grasscutter.net.proto.BattlePassProductOuterClass.BattlePassProduct;
|
||||
import emu.grasscutter.net.proto.BattlePassRewardTagOuterClass.BattlePassRewardTag;
|
||||
import emu.grasscutter.net.proto.BattlePassUnlockStatusOuterClass.BattlePassUnlockStatus;
|
||||
import emu.grasscutter.net.proto.BattlePassRewardTakeOptionOuterClass.BattlePassRewardTakeOption;
|
||||
import emu.grasscutter.net.proto.BattlePassScheduleOuterClass.BattlePassSchedule;
|
||||
import emu.grasscutter.server.packet.send.PacketBattlePassCurScheduleUpdateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketBattlePassMissionUpdateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketTakeBattlePassRewardRsp;
|
||||
import lombok.Getter;
|
||||
|
||||
@Entity(value = "battlepass", useDiscriminator = false)
|
||||
public class BattlePassManager {
|
||||
@Id private ObjectId id;
|
||||
@Transient private Player player;
|
||||
@Id @Getter private ObjectId id;
|
||||
@Transient @Getter private Player player;
|
||||
|
||||
@Indexed private int ownerUid;
|
||||
private int point;
|
||||
private int awardTakenLevel;
|
||||
@Getter private int point;
|
||||
@Getter private int cyclePoints; // Weekly maximum cap
|
||||
@Getter private int level;
|
||||
|
||||
@Getter private boolean viewed;
|
||||
@Getter private boolean paid;
|
||||
|
||||
private Map<Integer, BattlePassMission> missions;
|
||||
private Map<Integer, BattlePassReward> takenRewards;
|
||||
|
||||
@Deprecated // Morphia only
|
||||
public BattlePassManager() {}
|
||||
@@ -26,39 +56,226 @@ public class BattlePassManager {
|
||||
this.setPlayer(player);
|
||||
}
|
||||
|
||||
public ObjectId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
public void setPlayer(Player player) {
|
||||
this.player = player;
|
||||
this.ownerUid = player.getUid();
|
||||
}
|
||||
|
||||
public int getPoint() {
|
||||
return point;
|
||||
public void updateViewed() {
|
||||
this.viewed = true;
|
||||
}
|
||||
|
||||
public int getAwardTakenLevel() {
|
||||
return awardTakenLevel;
|
||||
}
|
||||
public boolean setLevel(int level) {
|
||||
if (level >= 0 && level <= GameConstants.BATTLE_PASS_MAX_LEVEL) {
|
||||
this.level = level;
|
||||
this.point = 0;
|
||||
this.player.sendPacket(new PacketBattlePassCurScheduleUpdateNotify(this.player));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addPoint(int point){
|
||||
this.point += point;
|
||||
player.getSession().send(new PacketBattlePassCurScheduleUpdateNotify(player.getSession().getPlayer()));
|
||||
public void addPoints(int points){
|
||||
this.addPointsDirectly(points, false);
|
||||
|
||||
this.player.sendPacket(new PacketBattlePassCurScheduleUpdateNotify(player));
|
||||
this.save();
|
||||
}
|
||||
|
||||
public void updateAwardTakenLevel(int level){
|
||||
this.awardTakenLevel = level;
|
||||
player.getSession().send(new PacketBattlePassCurScheduleUpdateNotify(player.getSession().getPlayer()));
|
||||
this.save();
|
||||
public void addPointsDirectly(int points, boolean isWeekly) {
|
||||
int amount = points;
|
||||
|
||||
if (isWeekly) {
|
||||
amount = Math.min(amount, GameConstants.BATTLE_PASS_POINT_PER_WEEK - this.cyclePoints);
|
||||
}
|
||||
|
||||
if (amount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.point += amount;
|
||||
this.cyclePoints += amount;
|
||||
|
||||
if (this.point >= GameConstants.BATTLE_PASS_POINT_PER_LEVEL && this.getLevel() < GameConstants.BATTLE_PASS_MAX_LEVEL) {
|
||||
int levelups = Math.floorDiv(this.point, GameConstants.BATTLE_PASS_POINT_PER_LEVEL);
|
||||
|
||||
// Make sure player cant go above max BP level
|
||||
levelups = Math.min(levelups, GameConstants.BATTLE_PASS_MAX_LEVEL - levelups);
|
||||
|
||||
// Set new points after level up
|
||||
this.point = this.point - (levelups * GameConstants.BATTLE_PASS_POINT_PER_LEVEL);
|
||||
this.level += levelups;
|
||||
}
|
||||
}
|
||||
|
||||
public Map<Integer, BattlePassMission> getMissions() {
|
||||
if (this.missions == null) this.missions = new HashMap<>();
|
||||
return this.missions;
|
||||
}
|
||||
|
||||
// Will return a new empty mission if the mission id is not found
|
||||
public BattlePassMission loadMissionById(int id) {
|
||||
return getMissions().computeIfAbsent(id, i -> new BattlePassMission(i));
|
||||
}
|
||||
|
||||
public boolean hasMission(int id) {
|
||||
return getMissions().containsKey(id);
|
||||
}
|
||||
|
||||
public Map<Integer, BattlePassReward> getTakenRewards() {
|
||||
if (this.takenRewards == null) this.takenRewards = new HashMap<>();
|
||||
return this.takenRewards;
|
||||
}
|
||||
|
||||
// Mission triggers
|
||||
public void triggerMission(WatcherTriggerType triggerType) {
|
||||
getPlayer().getServer().getBattlePassMissionManager().triggerMission(getPlayer(), triggerType);
|
||||
}
|
||||
|
||||
public void triggerMission(WatcherTriggerType triggerType, int param, int progress) {
|
||||
getPlayer().getServer().getBattlePassMissionManager().triggerMission(getPlayer(), triggerType, param, progress);
|
||||
}
|
||||
|
||||
// Handlers
|
||||
public void takeMissionPoint(List<Integer> missionIdList) {
|
||||
// Obvious exploit check
|
||||
if (missionIdList.size() > GameData.getBattlePassMissionDataMap().size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<BattlePassMission> updatedMissions = new ArrayList<>(missionIdList.size());
|
||||
|
||||
for (int id : missionIdList) {
|
||||
// Skip if we dont have this mission
|
||||
if (!this.hasMission(id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BattlePassMission mission = this.loadMissionById(id);
|
||||
|
||||
if (mission.getData() == null) {
|
||||
this.getMissions().remove(mission.getId());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Take reward
|
||||
if (mission.getStatus() == BattlePassMissionStatus.MISSION_STATUS_FINISHED) {
|
||||
this.addPointsDirectly(mission.getData().getAddPoint(), mission.getData().isCycleRefresh());
|
||||
mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_POINT_TAKEN);
|
||||
|
||||
updatedMissions.add(mission);
|
||||
}
|
||||
}
|
||||
|
||||
if (updatedMissions.size() > 0) {
|
||||
// Save to db
|
||||
this.save();
|
||||
|
||||
// Packet
|
||||
getPlayer().sendPacket(new PacketBattlePassMissionUpdateNotify(updatedMissions));
|
||||
getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer()));
|
||||
}
|
||||
}
|
||||
|
||||
public void takeReward(List<BattlePassRewardTakeOption> takeOptionList) {
|
||||
List<BattlePassRewardTag> rewardList = new ArrayList<>();
|
||||
|
||||
for (BattlePassRewardTakeOption option : takeOptionList) {
|
||||
// Duplicate check
|
||||
if (option.getTag().getRewardId() == 0 || getTakenRewards().containsKey(option.getTag().getRewardId())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Level check
|
||||
if (option.getTag().getLevel() > this.getLevel()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BattlePassRewardData rewardData = GameData.getBattlePassRewardDataMap().get(option.getTag().getLevel());
|
||||
|
||||
// Sanity check with excel data
|
||||
if (rewardData.getFreeRewardIdList().contains(option.getTag().getRewardId())) {
|
||||
rewardList.add(option.getTag());
|
||||
} else if (this.isPaid() && rewardData.getPaidRewardIdList().contains(option.getTag().getRewardId())) {
|
||||
rewardList.add(option.getTag());
|
||||
}
|
||||
}
|
||||
|
||||
// Get rewards
|
||||
List<ItemParamData> rewardItems = null;
|
||||
|
||||
if (rewardList.size() > 0) {
|
||||
rewardItems = new ArrayList<>();
|
||||
|
||||
for (BattlePassRewardTag tag : rewardList) {
|
||||
RewardData reward = GameData.getRewardDataMap().get(tag.getRewardId());
|
||||
|
||||
if (reward == null) continue;
|
||||
|
||||
BattlePassReward bpReward = new BattlePassReward(tag.getLevel(), tag.getRewardId(), tag.getUnlockStatus() == BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_PAID);
|
||||
this.getTakenRewards().put(bpReward.getRewardId(), bpReward);
|
||||
|
||||
rewardItems.addAll(reward.getRewardItemList());
|
||||
}
|
||||
|
||||
// Save to db
|
||||
this.save();
|
||||
|
||||
// Add items and send battle pass schedule packet
|
||||
getPlayer().getInventory().addItemParamDatas(rewardItems);
|
||||
getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer()));
|
||||
}
|
||||
|
||||
getPlayer().sendPacket(new PacketTakeBattlePassRewardRsp(takeOptionList, rewardItems));
|
||||
}
|
||||
|
||||
public int buyLevels(int buyLevel) {
|
||||
int boughtLevels = Math.min(buyLevel, GameConstants.BATTLE_PASS_MAX_LEVEL - buyLevel);
|
||||
|
||||
if (boughtLevels > 0) {
|
||||
int price = GameConstants.BATTLE_PASS_LEVEL_PRICE * boughtLevels;
|
||||
|
||||
if (getPlayer().getPrimogems() < price) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
this.level += boughtLevels;
|
||||
this.save();
|
||||
|
||||
getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer()));
|
||||
}
|
||||
|
||||
return boughtLevels;
|
||||
}
|
||||
|
||||
public void resetDailyMissions() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public void resetWeeklyMissions() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
//
|
||||
public BattlePassSchedule getScheduleProto() {
|
||||
BattlePassSchedule.Builder schedule = BattlePassSchedule.newBuilder()
|
||||
.setScheduleId(2700)
|
||||
.setLevel(this.getLevel())
|
||||
.setPoint(this.getPoint())
|
||||
.setBeginTime(0)
|
||||
.setEndTime(2059483200)
|
||||
.setIsViewed(this.isViewed())
|
||||
.setUnlockStatus(this.isPaid() ? BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_PAID : BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE)
|
||||
.setCurCyclePoints(this.getCyclePoints())
|
||||
.setCurCycle(BattlePassCycle.newBuilder().setBeginTime(0).setEndTime(2059483200).setCycleIdx(3));
|
||||
|
||||
for (BattlePassReward reward : getTakenRewards().values()) {
|
||||
schedule.addRewardTakenList(reward.toProto());
|
||||
}
|
||||
|
||||
return schedule.build();
|
||||
}
|
||||
|
||||
public void save() {
|
||||
DatabaseHelper.saveBattlePass(this);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package emu.grasscutter.game.battlepass;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import dev.morphia.annotations.Transient;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.BattlePassMissionData;
|
||||
import emu.grasscutter.game.props.BattlePassMissionStatus;
|
||||
|
||||
@Entity
|
||||
public class BattlePassMission {
|
||||
private int id;
|
||||
private int progress;
|
||||
private BattlePassMissionStatus status;
|
||||
|
||||
@Transient
|
||||
private BattlePassMissionData data;
|
||||
|
||||
@Deprecated // Morphia only
|
||||
public BattlePassMission() {}
|
||||
|
||||
public BattlePassMission(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public BattlePassMissionData getData() {
|
||||
if (this.data == null) {
|
||||
this.data = GameData.getBattlePassMissionDataMap().get(getId());
|
||||
}
|
||||
return this.data;
|
||||
}
|
||||
|
||||
public int getProgress() {
|
||||
return progress;
|
||||
}
|
||||
|
||||
public void addProgress(int addProgress, int maxProgress) {
|
||||
this.progress = Math.min(addProgress + this.progress, maxProgress);
|
||||
}
|
||||
|
||||
public BattlePassMissionStatus getStatus() {
|
||||
if (status == null) status = BattlePassMissionStatus.MISSION_STATUS_UNFINISHED;
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(BattlePassMissionStatus status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public boolean isFinshed() {
|
||||
return getStatus().getValue() >= 2;
|
||||
}
|
||||
|
||||
public emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission toProto() {
|
||||
var protoBuilder = emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.newBuilder();
|
||||
|
||||
protoBuilder
|
||||
.setMissionId(getId())
|
||||
.setCurProgress(getProgress())
|
||||
.setTotalProgress(getData().getProgress())
|
||||
.setRewardBattlePassPoint(getData().getAddPoint())
|
||||
.setMissionStatus(getStatus().getMissionStatus())
|
||||
.setMissionType(getData().getRefreshType() == null ? 0 : getData().getRefreshType().getValue());
|
||||
|
||||
return protoBuilder.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package emu.grasscutter.game.battlepass;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.BattlePassMissionData;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.BattlePassMissionRefreshType;
|
||||
import emu.grasscutter.game.props.BattlePassMissionStatus;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
import emu.grasscutter.server.packet.send.PacketBattlePassMissionUpdateNotify;
|
||||
|
||||
public class BattlePassMissionManager {
|
||||
private final GameServer server;
|
||||
private final Map<WatcherTriggerType, List<BattlePassMissionData>> cachedTriggers;
|
||||
|
||||
// BP Mission manager for the server, contains cached triggers so we dont have to load it for each player
|
||||
public BattlePassMissionManager(GameServer server) {
|
||||
this.server = server;
|
||||
this.cachedTriggers = new HashMap<>();
|
||||
|
||||
for (BattlePassMissionData missionData : GameData.getBattlePassMissionDataMap().values()) {
|
||||
if (missionData.isValidRefreshType()) {
|
||||
List<BattlePassMissionData> triggerList = getTriggers().computeIfAbsent(missionData.getTriggerType(), e -> new ArrayList<>());
|
||||
triggerList.add(missionData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GameServer getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
private Map<WatcherTriggerType, List<BattlePassMissionData>> getTriggers() {
|
||||
return cachedTriggers;
|
||||
}
|
||||
|
||||
public void triggerMission(Player player, WatcherTriggerType triggerType) {
|
||||
triggerMission(player, triggerType, 0, 1);
|
||||
}
|
||||
|
||||
public void triggerMission(Player player, WatcherTriggerType triggerType, int param, int progress) {
|
||||
List<BattlePassMissionData> triggerList = getTriggers().get(triggerType);
|
||||
|
||||
if (triggerList == null || triggerList.isEmpty()) return;
|
||||
|
||||
for (BattlePassMissionData data : triggerList) {
|
||||
// Skip params check if param == 0
|
||||
if (param != 0) {
|
||||
if (!data.getMainParams().contains(param)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Get mission from player, if it doesnt exist, then we make one
|
||||
BattlePassMission mission = player.getBattlePassManager().loadMissionById(data.getId());
|
||||
|
||||
if (mission.isFinshed()) continue;
|
||||
|
||||
// Add progress
|
||||
mission.addProgress(progress, data.getProgress());
|
||||
|
||||
if (mission.getProgress() >= data.getProgress()) {
|
||||
mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_FINISHED);
|
||||
}
|
||||
|
||||
// Save to db
|
||||
player.getBattlePassManager().save();
|
||||
|
||||
// Packet
|
||||
player.sendPacket(new PacketBattlePassMissionUpdateNotify(mission));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package emu.grasscutter.game.battlepass;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import dev.morphia.annotations.Transient;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.BattlePassMissionData;
|
||||
import emu.grasscutter.data.excels.BattlePassRewardData;
|
||||
import emu.grasscutter.game.props.BattlePassMissionStatus;
|
||||
import emu.grasscutter.net.proto.BattlePassRewardTagOuterClass.BattlePassRewardTag;
|
||||
import emu.grasscutter.net.proto.BattlePassUnlockStatusOuterClass.BattlePassUnlockStatus;
|
||||
|
||||
@Entity
|
||||
public class BattlePassReward {
|
||||
private int level;
|
||||
private int rewardId;
|
||||
private boolean paid;
|
||||
|
||||
@Transient
|
||||
private BattlePassMissionData data;
|
||||
|
||||
@Deprecated // Morphia only
|
||||
public BattlePassReward() {}
|
||||
|
||||
public BattlePassReward(int level, int rewardId, boolean paid) {
|
||||
this.level = level;
|
||||
this.rewardId = rewardId;
|
||||
this.paid = paid;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public int getRewardId() {
|
||||
return rewardId;
|
||||
}
|
||||
|
||||
public boolean isPaid() {
|
||||
return paid;
|
||||
}
|
||||
|
||||
public BattlePassRewardTag toProto() {
|
||||
var protoBuilder = BattlePassRewardTag.newBuilder();
|
||||
|
||||
protoBuilder
|
||||
.setLevel(this.getLevel())
|
||||
.setRewardId(this.getRewardId())
|
||||
.setUnlockStatus(this.isPaid() ? BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_PAID : BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE);
|
||||
|
||||
return protoBuilder.build();
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.inventory.ItemType;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
||||
import emu.grasscutter.scripts.constants.EventType;
|
||||
@@ -98,6 +99,8 @@ public class DungeonChallenge extends WorldChallenge {
|
||||
getScene().getDungeonSettleObservers().forEach(o -> o.onDungeonSettle(getScene()));
|
||||
getScene().getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE,
|
||||
new ScriptArgs(this.isSuccess() ? 1 : 0));
|
||||
// Battle pass trigger
|
||||
this.getScene().getPlayers().forEach(p -> p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_FINISH_DUNGEON));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.EntityIdType;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
|
||||
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
|
||||
@@ -154,6 +155,8 @@ public class EntityMonster extends GameEntity {
|
||||
getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_DIE, new ScriptArgs().setParam1(this.getConfigId()));
|
||||
}
|
||||
}
|
||||
// Battle Pass trigger
|
||||
getScene().getPlayers().forEach(p -> p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_MONSTER_DIE, this.getMonsterId(), 1));
|
||||
}
|
||||
|
||||
public void recalcStats() {
|
||||
|
||||
@@ -27,6 +27,7 @@ import emu.grasscutter.game.inventory.Inventory;
|
||||
import emu.grasscutter.game.inventory.ItemType;
|
||||
import emu.grasscutter.game.inventory.MaterialType;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.net.proto.GachaItemOuterClass.GachaItem;
|
||||
import emu.grasscutter.net.proto.GachaTransferItemOuterClass.GachaTransferItem;
|
||||
import emu.grasscutter.net.proto.GetGachaInfoRspOuterClass.GetGachaInfoRsp;
|
||||
@@ -372,9 +373,12 @@ public class GachaManager {
|
||||
if (starglitter > 0) {
|
||||
inventory.addItem(starglitterId, starglitter);
|
||||
}
|
||||
|
||||
|
||||
// Packets
|
||||
player.sendPacket(new PacketDoGachaRsp(banner, list, gachaInfo));
|
||||
|
||||
// Battle Pass trigger
|
||||
player.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_GACHA_NUM, 0, times);
|
||||
}
|
||||
|
||||
private synchronized void startWatcher(GameServer server) {
|
||||
|
||||
@@ -33,34 +33,36 @@ import emu.grasscutter.net.proto.SceneReliquaryInfoOuterClass.SceneReliquaryInfo
|
||||
import emu.grasscutter.net.proto.SceneWeaponInfoOuterClass.SceneWeaponInfo;
|
||||
import emu.grasscutter.net.proto.WeaponOuterClass.Weapon;
|
||||
import emu.grasscutter.utils.WeightedList;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity(value = "items", useDiscriminator = false)
|
||||
public class GameItem {
|
||||
@Id private ObjectId id;
|
||||
@Indexed private int ownerId;
|
||||
private int itemId;
|
||||
private int count;
|
||||
@Getter @Setter private int itemId;
|
||||
@Getter @Setter private int count;
|
||||
|
||||
@Transient private long guid; // Player unique id
|
||||
@Transient private ItemData itemData;
|
||||
@Transient @Getter private long guid; // Player unique id
|
||||
@Transient @Getter @Setter private ItemData itemData;
|
||||
|
||||
// Equips
|
||||
private int level;
|
||||
private int exp;
|
||||
private int totalExp;
|
||||
private int promoteLevel;
|
||||
private boolean locked;
|
||||
@Getter @Setter private int level;
|
||||
@Getter @Setter private int exp;
|
||||
@Getter @Setter private int totalExp;
|
||||
@Getter @Setter private int promoteLevel;
|
||||
@Getter @Setter private boolean locked;
|
||||
|
||||
// Weapon
|
||||
private List<Integer> affixes;
|
||||
private int refinement = 0;
|
||||
@Getter private List<Integer> affixes;
|
||||
@Getter @Setter private int refinement = 0;
|
||||
|
||||
// Relic
|
||||
private int mainPropId;
|
||||
private List<Integer> appendPropIdList;
|
||||
@Getter @Setter private int mainPropId;
|
||||
@Getter private List<Integer> appendPropIdList;
|
||||
|
||||
private int equipCharacter;
|
||||
@Transient private int weaponEntityId;
|
||||
@Getter @Setter private int equipCharacter;
|
||||
@Transient @Getter @Setter private int weaponEntityId;
|
||||
|
||||
public GameItem() {
|
||||
// Morphia only
|
||||
@@ -82,42 +84,37 @@ public class GameItem {
|
||||
this.itemId = data.getId();
|
||||
this.itemData = data;
|
||||
|
||||
if (data.getItemType() == ItemType.ITEM_VIRTUAL) {
|
||||
switch (data.getItemType()) {
|
||||
case ITEM_VIRTUAL:
|
||||
this.count = count;
|
||||
} else {
|
||||
this.count = Math.min(count, data.getStackLimit());
|
||||
break;
|
||||
case ITEM_WEAPON:
|
||||
this.count = 1;
|
||||
this.level = Math.max(this.count, 1); // ??????????????????
|
||||
this.affixes = new ArrayList<>(2);
|
||||
if (data.getSkillAffix() != null) {
|
||||
for (int skillAffix : data.getSkillAffix()) {
|
||||
if (skillAffix > 0) {
|
||||
this.affixes.add(skillAffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ITEM_RELIQUARY:
|
||||
this.count = 1;
|
||||
this.level = 1;
|
||||
this.appendPropIdList = new ArrayList<>();
|
||||
// Create main property
|
||||
ReliquaryMainPropData mainPropData = GameDepot.getRandomRelicMainProp(data.getMainPropDepotId());
|
||||
if (mainPropData != null) {
|
||||
this.mainPropId = mainPropData.getId();
|
||||
}
|
||||
// Create extra stats
|
||||
this.addAppendProps(data.getAppendPropNum());
|
||||
break;
|
||||
default:
|
||||
this.count = Math.min(count, data.getStackLimit());
|
||||
}
|
||||
|
||||
// Equip data
|
||||
if (getItemType() == ItemType.ITEM_WEAPON) {
|
||||
this.level = Math.max(this.count, 1);
|
||||
this.affixes = new ArrayList<>(2);
|
||||
if (getItemData().getSkillAffix() != null) {
|
||||
for (int skillAffix : getItemData().getSkillAffix()) {
|
||||
if (skillAffix > 0) {
|
||||
this.affixes.add(skillAffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (getItemType() == ItemType.ITEM_RELIQUARY) {
|
||||
this.level = 1;
|
||||
this.appendPropIdList = new ArrayList<>();
|
||||
// Create main property
|
||||
ReliquaryMainPropData mainPropData = GameDepot.getRandomRelicMainProp(getItemData().getMainPropDepotId());
|
||||
if (mainPropData != null) {
|
||||
this.mainPropId = mainPropData.getId();
|
||||
}
|
||||
// Create extra stats
|
||||
if (getItemData().getAppendPropNum() > 0) {
|
||||
for (int i = 0; i < getItemData().getAppendPropNum(); i++) {
|
||||
this.addAppendProp();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectId getObjectId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getOwnerId() {
|
||||
@@ -128,162 +125,88 @@ public class GameItem {
|
||||
this.ownerId = player.getUid();
|
||||
this.guid = player.getNextGameGuid();
|
||||
}
|
||||
public int getItemId() {
|
||||
return itemId;
|
||||
}
|
||||
|
||||
public void setItemId(int itemId) {
|
||||
this.itemId = itemId;
|
||||
}
|
||||
|
||||
public long getGuid() {
|
||||
return guid;
|
||||
public ObjectId getObjectId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public ItemType getItemType() {
|
||||
return this.itemData.getItemType();
|
||||
}
|
||||
|
||||
public ItemData getItemData() {
|
||||
return itemData;
|
||||
}
|
||||
|
||||
public void setItemData(ItemData materialData) {
|
||||
this.itemData = materialData;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(int count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public int getExp() {
|
||||
return exp;
|
||||
}
|
||||
|
||||
public void setExp(int exp) {
|
||||
this.exp = exp;
|
||||
}
|
||||
|
||||
public int getTotalExp() {
|
||||
return totalExp;
|
||||
}
|
||||
|
||||
public void setTotalExp(int totalExp) {
|
||||
this.totalExp = totalExp;
|
||||
}
|
||||
|
||||
public int getPromoteLevel() {
|
||||
return promoteLevel;
|
||||
}
|
||||
|
||||
public void setPromoteLevel(int promoteLevel) {
|
||||
this.promoteLevel = promoteLevel;
|
||||
public static int getMinPromoteLevel(int level) {
|
||||
if (level > 80) {
|
||||
return 6;
|
||||
} else if (level > 70) {
|
||||
return 5;
|
||||
} else if (level > 60) {
|
||||
return 4;
|
||||
} else if (level > 50) {
|
||||
return 3;
|
||||
} else if (level > 40) {
|
||||
return 2;
|
||||
} else if (level > 20) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getEquipSlot() {
|
||||
return this.getItemData().getEquipType().getValue();
|
||||
}
|
||||
|
||||
public int getEquipCharacter() {
|
||||
return equipCharacter;
|
||||
}
|
||||
|
||||
public void setEquipCharacter(int equipCharacter) {
|
||||
this.equipCharacter = equipCharacter;
|
||||
}
|
||||
|
||||
public boolean isEquipped() {
|
||||
return this.getEquipCharacter() > 0;
|
||||
}
|
||||
|
||||
public boolean isLocked() {
|
||||
return locked;
|
||||
}
|
||||
|
||||
public void setLocked(boolean locked) {
|
||||
this.locked = locked;
|
||||
}
|
||||
|
||||
public boolean isDestroyable() {
|
||||
return !this.isLocked() && !this.isEquipped();
|
||||
}
|
||||
|
||||
public int getWeaponEntityId() {
|
||||
return weaponEntityId;
|
||||
}
|
||||
|
||||
public void setWeaponEntityId(int weaponEntityId) {
|
||||
this.weaponEntityId = weaponEntityId;
|
||||
}
|
||||
|
||||
public List<Integer> getAffixes() {
|
||||
return affixes;
|
||||
}
|
||||
|
||||
public int getRefinement() {
|
||||
return refinement;
|
||||
}
|
||||
|
||||
public void setRefinement(int refinement) {
|
||||
this.refinement = refinement;
|
||||
}
|
||||
|
||||
public int getMainPropId() {
|
||||
return mainPropId;
|
||||
}
|
||||
|
||||
public void setMainPropId(int mainPropId) {
|
||||
this.mainPropId = mainPropId;
|
||||
}
|
||||
|
||||
public List<Integer> getAppendPropIdList() {
|
||||
return appendPropIdList;
|
||||
}
|
||||
|
||||
public void addAppendProp() {
|
||||
if (this.getAppendPropIdList() == null) {
|
||||
if (this.appendPropIdList == null) {
|
||||
this.appendPropIdList = new ArrayList<>();
|
||||
}
|
||||
|
||||
if (this.getAppendPropIdList().size() < 4) {
|
||||
addNewAppendProp();
|
||||
if (this.appendPropIdList.size() < 4) {
|
||||
this.addNewAppendProp();
|
||||
} else {
|
||||
upgradeRandomAppendProp();
|
||||
this.upgradeRandomAppendProp();
|
||||
}
|
||||
}
|
||||
|
||||
public void addAppendProps(int quantity) {
|
||||
int num = Math.max(quantity, 0);
|
||||
for (int i = 0; i < num; i++) {
|
||||
this.addAppendProp();
|
||||
}
|
||||
}
|
||||
|
||||
private Set<FightProperty> getAppendFightProperties() {
|
||||
Set<FightProperty> props = new HashSet<>();
|
||||
// Previously this would check no more than the first four affixes, however custom artifacts may not respect this order.
|
||||
for (int appendPropId : this.appendPropIdList) {
|
||||
ReliquaryAffixData affixData = GameData.getReliquaryAffixDataMap().get(appendPropId);
|
||||
if (affixData != null) {
|
||||
props.add(affixData.getFightProp());
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
private void addNewAppendProp() {
|
||||
List<ReliquaryAffixData> affixList = GameDepot.getRandomRelicAffixList(getItemData().getAppendPropDepotId());
|
||||
List<ReliquaryAffixData> affixList = GameDepot.getRelicAffixList(this.itemData.getAppendPropDepotId());
|
||||
|
||||
if (affixList == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Build blacklist - Dont add same stat as main/sub stat
|
||||
Set<FightProperty> blacklist = new HashSet<>();
|
||||
ReliquaryMainPropData mainPropData = GameData.getReliquaryMainPropDataMap().get(this.getMainPropId());
|
||||
Set<FightProperty> blacklist = this.getAppendFightProperties();
|
||||
ReliquaryMainPropData mainPropData = GameData.getReliquaryMainPropDataMap().get(this.mainPropId);
|
||||
if (mainPropData != null) {
|
||||
blacklist.add(mainPropData.getFightProp());
|
||||
}
|
||||
int len = Math.min(4, this.getAppendPropIdList().size());
|
||||
for (int i = 0; i < len; i++) {
|
||||
ReliquaryAffixData affixData = GameData.getReliquaryAffixDataMap().get((int) this.getAppendPropIdList().get(i));
|
||||
if (affixData != null) {
|
||||
blacklist.add(affixData.getFightProp());
|
||||
}
|
||||
}
|
||||
|
||||
// Build random list
|
||||
WeightedList<ReliquaryAffixData> randomList = new WeightedList<>();
|
||||
@@ -299,25 +222,18 @@ public class GameItem {
|
||||
|
||||
// Add random stat
|
||||
ReliquaryAffixData affixData = randomList.next();
|
||||
this.getAppendPropIdList().add(affixData.getId());
|
||||
this.appendPropIdList.add(affixData.getId());
|
||||
}
|
||||
|
||||
private void upgradeRandomAppendProp() {
|
||||
List<ReliquaryAffixData> affixList = GameDepot.getRandomRelicAffixList(getItemData().getAppendPropDepotId());
|
||||
List<ReliquaryAffixData> affixList = GameDepot.getRelicAffixList(this.itemData.getAppendPropDepotId());
|
||||
|
||||
if (affixList == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Build whitelist
|
||||
Set<FightProperty> whitelist = new HashSet<>();
|
||||
int len = Math.min(4, this.getAppendPropIdList().size());
|
||||
for (int i = 0; i < len; i++) {
|
||||
ReliquaryAffixData affixData = GameData.getReliquaryAffixDataMap().get((int) this.getAppendPropIdList().get(i));
|
||||
if (affixData != null) {
|
||||
whitelist.add(affixData.getFightProp());
|
||||
}
|
||||
}
|
||||
Set<FightProperty> whitelist = this.getAppendFightProperties();
|
||||
|
||||
// Build random list
|
||||
WeightedList<ReliquaryAffixData> randomList = new WeightedList<>();
|
||||
@@ -329,7 +245,7 @@ public class GameItem {
|
||||
|
||||
// Add random stat
|
||||
ReliquaryAffixData affixData = randomList.next();
|
||||
this.getAppendPropIdList().add(affixData.getId());
|
||||
this.appendPropIdList.add(affixData.getId());
|
||||
}
|
||||
|
||||
@PostLoad
|
||||
|
||||
@@ -18,6 +18,7 @@ import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam;
|
||||
import emu.grasscutter.server.packet.send.PacketAvatarEquipChangeNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketItemAddHintNotify;
|
||||
@@ -95,6 +96,7 @@ public class Inventory implements Iterable<GameItem> {
|
||||
GameItem result = putItem(item);
|
||||
|
||||
if (result != null) {
|
||||
getPlayer().getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_OBTAIN_MATERIAL_NUM, result.getItemId(), result.getCount());
|
||||
getPlayer().sendPacket(new PacketStoreItemChangeNotify(result));
|
||||
return true;
|
||||
}
|
||||
@@ -131,7 +133,9 @@ public class Inventory implements Iterable<GameItem> {
|
||||
|
||||
for (GameItem item : items) {
|
||||
GameItem result = putItem(item);
|
||||
|
||||
if (result != null) {
|
||||
getPlayer().getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_OBTAIN_MATERIAL_NUM, result.getItemId(), result.getCount());
|
||||
changedItems.add(result);
|
||||
}
|
||||
}
|
||||
@@ -170,80 +174,86 @@ public class Inventory implements Iterable<GameItem> {
|
||||
InventoryTab tab = getInventoryTab(type);
|
||||
|
||||
// Add
|
||||
if (type == ItemType.ITEM_WEAPON || type == ItemType.ITEM_RELIQUARY) {
|
||||
if (tab.getSize() >= tab.getMaxCapacity()) {
|
||||
return null;
|
||||
}
|
||||
// Duplicates cause problems
|
||||
item.setCount(Math.max(item.getCount(), 1));
|
||||
// Adds to inventory
|
||||
putItem(item, tab);
|
||||
} else if (type == ItemType.ITEM_VIRTUAL) {
|
||||
// Handle
|
||||
this.addVirtualItem(item.getItemId(), item.getCount());
|
||||
return item;
|
||||
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_ADSORBATE) {
|
||||
this.player.getEnergyManager().handlePickupElemBall(item);
|
||||
return null;
|
||||
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_AVATAR) {
|
||||
// Get avatar id
|
||||
int avatarId = (item.getItemId() % 1000) + 10000000;
|
||||
// Dont let people give themselves extra main characters
|
||||
if (avatarId == GameConstants.MAIN_CHARACTER_MALE || avatarId == GameConstants.MAIN_CHARACTER_FEMALE) {
|
||||
return null;
|
||||
}
|
||||
// Add avatar
|
||||
AvatarData avatarData = GameData.getAvatarDataMap().get(avatarId);
|
||||
if (avatarData != null && !player.getAvatars().hasAvatar(avatarId)) {
|
||||
this.getPlayer().addAvatar(new Avatar(avatarData));
|
||||
}
|
||||
return null;
|
||||
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_FLYCLOAK) {
|
||||
AvatarFlycloakData flycloakData = GameData.getAvatarFlycloakDataMap().get(item.getItemId());
|
||||
if (flycloakData != null && !player.getFlyCloakList().contains(item.getItemId())) {
|
||||
getPlayer().addFlycloak(item.getItemId());
|
||||
}
|
||||
return null;
|
||||
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_COSTUME) {
|
||||
AvatarCostumeData costumeData = GameData.getAvatarCostumeDataItemIdMap().get(item.getItemId());
|
||||
if (costumeData != null && !player.getCostumeList().contains(costumeData.getId())) {
|
||||
getPlayer().addCostume(costumeData.getId());
|
||||
}
|
||||
return null;
|
||||
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_NAMECARD) {
|
||||
if (!player.getNameCardList().contains(item.getItemId())) {
|
||||
getPlayer().addNameCard(item.getItemId());
|
||||
}
|
||||
return null;
|
||||
} else if (tab != null) {
|
||||
GameItem existingItem = tab.getItemById(item.getItemId());
|
||||
if (existingItem == null) {
|
||||
// Item type didnt exist before, we will add it to main inventory map if there is enough space
|
||||
switch (type) {
|
||||
case ITEM_WEAPON:
|
||||
case ITEM_RELIQUARY:
|
||||
if (tab.getSize() >= tab.getMaxCapacity()) {
|
||||
return null;
|
||||
}
|
||||
putItem(item, tab);
|
||||
} else {
|
||||
// Add count
|
||||
existingItem.setCount(Math.min(existingItem.getCount() + item.getCount(), item.getItemData().getStackLimit()));
|
||||
existingItem.save();
|
||||
return existingItem;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Set ownership and save to db
|
||||
if (item.getItemData().getItemType() != ItemType.ITEM_VIRTUAL)
|
||||
item.save();
|
||||
|
||||
return item;
|
||||
// Duplicates cause problems
|
||||
item.setCount(Math.max(item.getCount(), 1));
|
||||
// Adds to inventory
|
||||
this.putItem(item, tab);
|
||||
// Set ownership and save to db
|
||||
item.save();
|
||||
return item;
|
||||
case ITEM_VIRTUAL:
|
||||
// Handle
|
||||
this.addVirtualItem(item.getItemId(), item.getCount());
|
||||
return item;
|
||||
default:
|
||||
switch (item.getItemData().getMaterialType()) {
|
||||
case MATERIAL_ADSORBATE:
|
||||
this.player.getEnergyManager().handlePickupElemBall(item);
|
||||
return null;
|
||||
case MATERIAL_AVATAR:
|
||||
// Get avatar id
|
||||
int avatarId = (item.getItemId() % 1000) + 10000000;
|
||||
// Dont let people give themselves extra main characters
|
||||
if (avatarId == GameConstants.MAIN_CHARACTER_MALE || avatarId == GameConstants.MAIN_CHARACTER_FEMALE) {
|
||||
return null;
|
||||
}
|
||||
// Add avatar
|
||||
AvatarData avatarData = GameData.getAvatarDataMap().get(avatarId);
|
||||
if (avatarData != null && !this.player.getAvatars().hasAvatar(avatarId)) {
|
||||
this.player.addAvatar(new Avatar(avatarData));
|
||||
}
|
||||
return null;
|
||||
case MATERIAL_FLYCLOAK:
|
||||
AvatarFlycloakData flycloakData = GameData.getAvatarFlycloakDataMap().get(item.getItemId());
|
||||
if (flycloakData != null && !this.player.getFlyCloakList().contains(item.getItemId())) {
|
||||
this.player.addFlycloak(item.getItemId());
|
||||
}
|
||||
return null;
|
||||
case MATERIAL_COSTUME:
|
||||
AvatarCostumeData costumeData = GameData.getAvatarCostumeDataItemIdMap().get(item.getItemId());
|
||||
if (costumeData != null && !this.player.getCostumeList().contains(costumeData.getId())) {
|
||||
this.player.addCostume(costumeData.getId());
|
||||
}
|
||||
return null;
|
||||
case MATERIAL_NAMECARD:
|
||||
if (!this.player.getNameCardList().contains(item.getItemId())) {
|
||||
this.player.addNameCard(item.getItemId());
|
||||
}
|
||||
return null;
|
||||
default:
|
||||
if (tab == null) {
|
||||
return null;
|
||||
}
|
||||
GameItem existingItem = tab.getItemById(item.getItemId());
|
||||
if (existingItem == null) {
|
||||
// Item type didnt exist before, we will add it to main inventory map if there is enough space
|
||||
if (tab.getSize() >= tab.getMaxCapacity()) {
|
||||
return null;
|
||||
}
|
||||
this.putItem(item, tab);
|
||||
// Set ownership and save to db
|
||||
item.save();
|
||||
return item;
|
||||
} else {
|
||||
// Add count
|
||||
existingItem.setCount(Math.min(existingItem.getCount() + item.getCount(), item.getItemData().getStackLimit()));
|
||||
existingItem.save();
|
||||
return existingItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void putItem(GameItem item, InventoryTab tab) {
|
||||
getPlayer().getCodex().checkAddedItem(item);
|
||||
// Set owner and guid FIRST!
|
||||
item.setOwner(getPlayer());
|
||||
this.player.getCodex().checkAddedItem(item);
|
||||
// Set owner and guid FIRST!
|
||||
item.setOwner(this.player);
|
||||
// Put in item store
|
||||
getItems().put(item.getGuid(), item);
|
||||
if (tab != null) {
|
||||
@@ -254,36 +264,36 @@ public class Inventory implements Iterable<GameItem> {
|
||||
private void addVirtualItem(int itemId, int count) {
|
||||
switch (itemId) {
|
||||
case 101 -> // Character exp
|
||||
getPlayer().getServer().getInventoryManager().upgradeAvatar(player, getPlayer().getTeamManager().getCurrentAvatarEntity().getAvatar(), count);
|
||||
case 102 -> // Adventure exp
|
||||
getPlayer().addExpDirectly(count);
|
||||
case 105 -> // Companionship exp
|
||||
getPlayer().getServer().getInventoryManager().upgradeAvatarFetterLevel(player, getPlayer().getTeamManager().getCurrentAvatarEntity().getAvatar(), count);
|
||||
case 106 -> // Resin
|
||||
getPlayer().getResinManager().addResin(count);
|
||||
case 201 -> // Primogem
|
||||
getPlayer().setPrimogems(player.getPrimogems() + count);
|
||||
case 202 -> // Mora
|
||||
getPlayer().setMora(player.getMora() + count);
|
||||
case 203 -> // Genesis Crystals
|
||||
getPlayer().setCrystals(player.getCrystals() + count);
|
||||
case 204 -> // Home Coin
|
||||
getPlayer().setHomeCoin(player.getHomeCoin() + count);
|
||||
this.player.getServer().getInventoryManager().upgradeAvatar(this.player, this.player.getTeamManager().getCurrentAvatarEntity().getAvatar(), count);
|
||||
case 102 -> // Adventure exp
|
||||
this.player.addExpDirectly(count);
|
||||
case 105 -> // Companionship exp
|
||||
this.player.getServer().getInventoryManager().upgradeAvatarFetterLevel(this.player, this.player.getTeamManager().getCurrentAvatarEntity().getAvatar(), count);
|
||||
case 106 -> // Resin
|
||||
this.player.getResinManager().addResin(count);
|
||||
case 201 -> // Primogem
|
||||
this.player.setPrimogems(this.player.getPrimogems() + count);
|
||||
case 202 -> // Mora
|
||||
this.player.setMora(this.player.getMora() + count);
|
||||
case 203 -> // Genesis Crystals
|
||||
this.player.setCrystals(this.player.getCrystals() + count);
|
||||
case 204 -> // Home Coin
|
||||
this.player.setHomeCoin(this.player.getHomeCoin() + count);
|
||||
}
|
||||
}
|
||||
|
||||
private int getVirtualItemCount(int itemId) {
|
||||
switch (itemId) {
|
||||
case 201: // Primogem
|
||||
return player.getPrimogems();
|
||||
return this.player.getPrimogems();
|
||||
case 202: // Mora
|
||||
return player.getMora();
|
||||
return this.player.getMora();
|
||||
case 203: // Genesis Crystals
|
||||
return player.getCrystals();
|
||||
return this.player.getCrystals();
|
||||
case 106: // Resin
|
||||
return player.getProperty(PlayerProperty.PROP_PLAYER_RESIN);
|
||||
return this.player.getProperty(PlayerProperty.PROP_PLAYER_RESIN);
|
||||
case 204: // Home Coin
|
||||
return player.getHomeCoin();
|
||||
return this.player.getHomeCoin();
|
||||
default:
|
||||
GameItem item = getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(itemId); // What if we ever want to operate on weapons/relics/furniture? :S
|
||||
return (item == null) ? 0 : item.getCount();
|
||||
@@ -368,7 +378,7 @@ public class Inventory implements Iterable<GameItem> {
|
||||
if (count <= 0 || item == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (item.getItemData().isEquip()) {
|
||||
item.setCount(0);
|
||||
} else {
|
||||
@@ -389,6 +399,10 @@ public class Inventory implements Iterable<GameItem> {
|
||||
getPlayer().sendPacket(new PacketStoreItemChangeNotify(item));
|
||||
}
|
||||
|
||||
// Battle pass trigger
|
||||
int removeCount = Math.min(count, item.getCount());
|
||||
getPlayer().getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_COST_MATERIAL, item.getItemId(), removeCount);
|
||||
|
||||
// Update in db
|
||||
item.save();
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ public class InventoryManager {
|
||||
int totalExp = relic.getTotalExp();
|
||||
int reqExp = GameData.getRelicExpRequired(relic.getItemData().getRankLevel(), level);
|
||||
int upgrades = 0;
|
||||
List<Integer> oldAppendPropIdList = relic.getAppendPropIdList();
|
||||
List<Integer> oldAppendPropIdList = new ArrayList<>(relic.getAppendPropIdList());
|
||||
|
||||
while (expGain > 0 && reqExp > 0 && level < relic.getItemData().getMaxLevel()) {
|
||||
// Do calculations
|
||||
@@ -169,13 +169,7 @@ public class InventoryManager {
|
||||
}
|
||||
}
|
||||
|
||||
if (upgrades > 0) {
|
||||
oldAppendPropIdList = new ArrayList<>(relic.getAppendPropIdList());
|
||||
while (upgrades > 0) {
|
||||
relic.addAppendProp();
|
||||
upgrades -= 1;
|
||||
}
|
||||
}
|
||||
relic.addAppendProps(upgrades);
|
||||
|
||||
// Save
|
||||
relic.setLevel(level);
|
||||
|
||||
@@ -2,6 +2,7 @@ package emu.grasscutter.game.managers;
|
||||
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.server.packet.send.PacketPlayerPropNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketResinChangeNotify;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
@@ -43,9 +44,11 @@ public class ResinManager {
|
||||
}
|
||||
|
||||
// Send packets.
|
||||
this.player.sendPacket(new PacketPlayerPropNotify(this.player, PlayerProperty.PROP_PLAYER_RESIN));
|
||||
this.player.sendPacket(new PacketResinChangeNotify(this.player));
|
||||
|
||||
|
||||
// Battle Pass trigger
|
||||
this.player.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_COST_MATERIAL, 106, amount); // Resin item id = 106
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -66,7 +69,6 @@ public class ResinManager {
|
||||
}
|
||||
|
||||
// Send packets.
|
||||
this.player.sendPacket(new PacketPlayerPropNotify(this.player, PlayerProperty.PROP_PLAYER_RESIN));
|
||||
this.player.sendPacket(new PacketResinChangeNotify(this.player));
|
||||
}
|
||||
|
||||
@@ -113,7 +115,6 @@ public class ResinManager {
|
||||
}
|
||||
|
||||
// Send packets.
|
||||
this.player.sendPacket(new PacketPlayerPropNotify(this.player, PlayerProperty.PROP_PLAYER_RESIN));
|
||||
this.player.sendPacket(new PacketResinChangeNotify(this.player));
|
||||
}
|
||||
|
||||
@@ -137,7 +138,6 @@ public class ResinManager {
|
||||
}
|
||||
|
||||
// Send initial notifications on logon.
|
||||
this.player.sendPacket(new PacketPlayerPropNotify(this.player, PlayerProperty.PROP_PLAYER_RESIN));
|
||||
this.player.sendPacket(new PacketResinChangeNotify(this.player));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.net.proto.ChangeHpReasonOuterClass.ChangeHpReason;
|
||||
import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
||||
|
||||
@@ -26,7 +25,7 @@ public class SotSManager {
|
||||
private Timer autoRecoverTimer;
|
||||
private final boolean enablePriorityHealing = false;
|
||||
|
||||
public final static int GlobalMaximumSpringVolume = 8500000;
|
||||
public final static int GlobalMaximumSpringVolume = PlayerProperty.PROP_MAX_SPRING_VOLUME.getMax();
|
||||
|
||||
public SotSManager(Player player) {
|
||||
this.player = player;
|
||||
|
||||
@@ -446,5 +446,10 @@ public class EnergyManager {
|
||||
|
||||
public void setEnergyUsage(Boolean energyUsage) {
|
||||
this.energyUsage = energyUsage;
|
||||
if (!energyUsage) { // Refill team energy if usage is disabled
|
||||
for (EntityAvatar entityAvatar : player.getTeamManager().getActiveTeam()) {
|
||||
entityAvatar.addEnergy(1000, PropChangeReason.PROP_CHANGE_REASON_GM,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,18 +5,15 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.mongodb.QueryBuilder;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
import emu.grasscutter.data.excels.ForgeData;
|
||||
import emu.grasscutter.data.excels.ItemData;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.inventory.ItemType;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.net.proto.ForgeStartReqOuterClass;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.net.proto.ForgeQueueDataOuterClass.ForgeQueueData;
|
||||
import emu.grasscutter.net.proto.ForgeQueueManipulateReqOuterClass.ForgeQueueManipulateReq;
|
||||
import emu.grasscutter.net.proto.ForgeQueueManipulateTypeOuterClass.ForgeQueueManipulateType;
|
||||
@@ -147,6 +144,13 @@ public class ForgingManager {
|
||||
}
|
||||
|
||||
ForgeData forgeData = GameData.getForgeDataMap().get(req.getForgeId());
|
||||
|
||||
//Check if the player has sufficient forge points.
|
||||
int requiredPoints = forgeData.getForgePoint() * req.getForgeCount();
|
||||
if (requiredPoints > this.player.getForgePoints()) {
|
||||
this.player.sendPacket(new PacketForgeStartRsp(Retcode.RET_FORGE_POINT_NOT_ENOUGH));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we have enough of each material and consume.
|
||||
List<ItemParamData> material = new ArrayList<>(forgeData.getMaterialItems());
|
||||
@@ -158,6 +162,9 @@ public class ForgingManager {
|
||||
this.player.sendPacket(new PacketForgeStartRsp(Retcode.RET_FORGE_POINT_NOT_ENOUGH)); //ToDo: Probably the wrong return code.
|
||||
}
|
||||
|
||||
// Consume forge points.
|
||||
this.player.setForgePoints(this.player.getForgePoints() - requiredPoints);
|
||||
|
||||
// Create and add active forge.
|
||||
ActiveForgeData activeForge = new ActiveForgeData();
|
||||
activeForge.setForgeId(req.getForgeId());
|
||||
@@ -195,6 +202,9 @@ public class ForgingManager {
|
||||
|
||||
GameItem addItem = new GameItem(resultItemData, data.getResultItemCount() * finished);
|
||||
this.player.getInventory().addItem(addItem);
|
||||
|
||||
// Battle pass trigger handler
|
||||
this.player.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_DO_FORGE, 0, finished);
|
||||
|
||||
// Replace active forge with a new one for the unfinished items, if there are any.
|
||||
if (unfinished > 0) {
|
||||
@@ -252,6 +262,12 @@ public class ForgingManager {
|
||||
GameItem returnMora = new GameItem(moraItem, data.getScoinCost() * forge.getCount());
|
||||
returnItems.add(returnMora);
|
||||
|
||||
// Return forge points to the player.
|
||||
int requiredPoints = data.getForgePoint() * forge.getCount();
|
||||
int newPoints = Math.min(this.player.getForgePoints() + requiredPoints, 300_000);
|
||||
|
||||
this.player.setForgePoints(newPoints);
|
||||
|
||||
// Remove the forge queue.
|
||||
this.player.getActiveForges().remove(queueId - 1);
|
||||
this.sendForgeQueueDataNotify(true);
|
||||
|
||||
@@ -2,8 +2,6 @@ package emu.grasscutter.game.managers.stamina;
|
||||
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.commands.NoStaminaCommand;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.game.entity.GameEntity;
|
||||
@@ -112,8 +110,8 @@ public class StaminaManager {
|
||||
}};
|
||||
|
||||
private final Logger logger = Grasscutter.getLogger();
|
||||
public final static int GlobalCharacterMaximumStamina = 24000;
|
||||
public final static int GlobalVehicleMaxStamina = 24000;
|
||||
public final static int GlobalCharacterMaximumStamina = PlayerProperty.PROP_MAX_STAMINA.getMax();
|
||||
public final static int GlobalVehicleMaxStamina = PlayerProperty.PROP_MAX_STAMINA.getMax();
|
||||
private Position currentCoordinates = new Position(0, 0, 0);
|
||||
private Position previousCoordinates = new Position(0, 0, 0);
|
||||
private MotionState currentState = MotionState.MOTION_STATE_STANDBY;
|
||||
@@ -285,14 +283,13 @@ public class StaminaManager {
|
||||
// Returns new stamina and sends PlayerPropNotify or VehicleStaminaNotify
|
||||
public int setStamina(GameSession session, String reason, int newStamina, boolean isCharacterStamina) {
|
||||
// Target Player
|
||||
if (!GAME_OPTIONS.staminaUsage || session.getPlayer().getStamina()) {
|
||||
if (!GAME_OPTIONS.staminaUsage || session.getPlayer().getUnlimitedStamina()) {
|
||||
newStamina = getMaxCharacterStamina();
|
||||
}
|
||||
|
||||
// set stamina if is character stamina
|
||||
if (isCharacterStamina) {
|
||||
player.setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, newStamina);
|
||||
session.send(new PacketPlayerPropNotify(player, PlayerProperty.PROP_CUR_PERSIST_STAMINA));
|
||||
} else {
|
||||
vehicleStamina = newStamina;
|
||||
session.send(new PacketVehicleStaminaNotify(vehicleId, ((float) newStamina) / 100));
|
||||
|
||||
@@ -7,6 +7,7 @@ import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.PlayerLevelData;
|
||||
import emu.grasscutter.data.excels.WeatherData;
|
||||
import emu.grasscutter.database.DatabaseHelper;
|
||||
import emu.grasscutter.database.DatabaseManager;
|
||||
import emu.grasscutter.game.Account;
|
||||
import emu.grasscutter.game.CoopRequest;
|
||||
import emu.grasscutter.game.ability.AbilityManager;
|
||||
@@ -42,6 +43,7 @@ import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.game.props.ClimateType;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.game.props.SceneType;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.game.quest.QuestManager;
|
||||
import emu.grasscutter.game.shop.ShopLimit;
|
||||
import emu.grasscutter.game.tower.TowerData;
|
||||
@@ -75,6 +77,9 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
@@ -180,6 +185,7 @@ public class Player {
|
||||
private long springLastUsed;
|
||||
private HashMap<String, MapMark> mapMarks;
|
||||
private int nextResinRefresh;
|
||||
private int lastDailyReset;
|
||||
|
||||
@Deprecated
|
||||
@SuppressWarnings({"rawtypes", "unchecked"}) // Morphia only!
|
||||
@@ -253,14 +259,14 @@ public class Player {
|
||||
this.teamManager = new TeamManager(this);
|
||||
this.birthday = new PlayerBirthday();
|
||||
this.codex = new PlayerCodex(this);
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_LEVEL, 1);
|
||||
this.setProperty(PlayerProperty.PROP_IS_SPRING_AUTO_USE, 1);
|
||||
this.setProperty(PlayerProperty.PROP_SPRING_AUTO_USE_PERCENT, 50);
|
||||
this.setProperty(PlayerProperty.PROP_IS_FLYABLE, 1);
|
||||
this.setProperty(PlayerProperty.PROP_IS_TRANSFERABLE, 1);
|
||||
this.setProperty(PlayerProperty.PROP_MAX_STAMINA, 24000);
|
||||
this.setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, 24000);
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_RESIN, 160);
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_LEVEL, 1, false);
|
||||
this.setProperty(PlayerProperty.PROP_IS_SPRING_AUTO_USE, 1, false);
|
||||
this.setProperty(PlayerProperty.PROP_SPRING_AUTO_USE_PERCENT, 50, false);
|
||||
this.setProperty(PlayerProperty.PROP_IS_FLYABLE, 1, false);
|
||||
this.setProperty(PlayerProperty.PROP_IS_TRANSFERABLE, 1, false);
|
||||
this.setProperty(PlayerProperty.PROP_MAX_STAMINA, 24000, false);
|
||||
this.setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, 24000, false);
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_RESIN, 160, false);
|
||||
this.getFlyCloakList().add(140001);
|
||||
this.getNameCardList().add(210001);
|
||||
this.getPos().set(GameConstants.START_POSITION);
|
||||
@@ -290,7 +296,9 @@ public class Player {
|
||||
}
|
||||
|
||||
public Account getAccount() {
|
||||
return account;
|
||||
if (this.account == null)
|
||||
this.account = DatabaseHelper.getAccountById(Integer.toString(this.id));
|
||||
return this.account;
|
||||
}
|
||||
|
||||
public void setAccount(Account account) {
|
||||
@@ -429,12 +437,13 @@ public class Player {
|
||||
return this.getProperty(PlayerProperty.PROP_PLAYER_LEVEL);
|
||||
}
|
||||
|
||||
public void setLevel(int level) {
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_LEVEL, level);
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_LEVEL));
|
||||
|
||||
this.updateWorldLevel();
|
||||
this.updateProfile();
|
||||
public boolean setLevel(int level) {
|
||||
if (this.setProperty(PlayerProperty.PROP_PLAYER_LEVEL, level)) {
|
||||
this.updateWorldLevel();
|
||||
this.updateProfile();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getExp() {
|
||||
@@ -444,48 +453,59 @@ public class Player {
|
||||
public int getWorldLevel() {
|
||||
return this.getProperty(PlayerProperty.PROP_PLAYER_WORLD_LEVEL);
|
||||
}
|
||||
|
||||
public boolean setWorldLevel(int level) {
|
||||
if (this.setProperty(PlayerProperty.PROP_PLAYER_WORLD_LEVEL, level)) {
|
||||
if (this.world.getHost() == this) // Don't update World's WL if we are in someone else's world
|
||||
this.world.setWorldLevel(level);
|
||||
this.updateProfile();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setWorldLevel(int level) {
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_WORLD_LEVEL, level);
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_WORLD_LEVEL));
|
||||
public int getForgePoints() {
|
||||
return this.getProperty(PlayerProperty.PROP_PLAYER_FORGE_POINT);
|
||||
}
|
||||
|
||||
this.updateProfile();
|
||||
public boolean setForgePoints(int value) {
|
||||
if (value == this.getForgePoints()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.setProperty(PlayerProperty.PROP_PLAYER_FORGE_POINT, value);
|
||||
}
|
||||
|
||||
public int getPrimogems() {
|
||||
return this.getProperty(PlayerProperty.PROP_PLAYER_HCOIN);
|
||||
}
|
||||
|
||||
public void setPrimogems(int primogem) {
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_HCOIN, primogem);
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_HCOIN));
|
||||
public boolean setPrimogems(int primogem) {
|
||||
return this.setProperty(PlayerProperty.PROP_PLAYER_HCOIN, primogem);
|
||||
}
|
||||
|
||||
public int getMora() {
|
||||
return this.getProperty(PlayerProperty.PROP_PLAYER_SCOIN);
|
||||
}
|
||||
|
||||
public void setMora(int mora) {
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_SCOIN, mora);
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_SCOIN));
|
||||
public boolean setMora(int mora) {
|
||||
return this.setProperty(PlayerProperty.PROP_PLAYER_SCOIN, mora);
|
||||
}
|
||||
|
||||
public int getCrystals() {
|
||||
return this.getProperty(PlayerProperty.PROP_PLAYER_MCOIN);
|
||||
}
|
||||
|
||||
public void setCrystals(int crystals) {
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_MCOIN, crystals);
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_MCOIN));
|
||||
public boolean setCrystals(int crystals) {
|
||||
return this.setProperty(PlayerProperty.PROP_PLAYER_MCOIN, crystals);
|
||||
}
|
||||
|
||||
public int getHomeCoin() {
|
||||
return this.getProperty(PlayerProperty.PROP_PLAYER_HOME_COIN);
|
||||
}
|
||||
|
||||
public void setHomeCoin(int coin) {
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_HOME_COIN, coin);
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_HOME_COIN));
|
||||
public boolean setHomeCoin(int coin) {
|
||||
return this.setProperty(PlayerProperty.PROP_PLAYER_HOME_COIN, coin);
|
||||
}
|
||||
private int getExpRequired(int level) {
|
||||
PlayerLevelData levelData = GameData.getPlayerLevelDataMap().get(level);
|
||||
@@ -523,9 +543,6 @@ public class Player {
|
||||
|
||||
// Set exp
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_EXP, exp);
|
||||
|
||||
// Update player with packet
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_EXP));
|
||||
}
|
||||
|
||||
private void updateWorldLevel() {
|
||||
@@ -544,7 +561,6 @@ public class Player {
|
||||
0;
|
||||
|
||||
if (newWorldLevel != currentWorldLevel) {
|
||||
this.getWorld().setWorldLevel(newWorldLevel);
|
||||
this.setWorldLevel(newWorldLevel);
|
||||
}
|
||||
}
|
||||
@@ -566,7 +582,7 @@ public class Player {
|
||||
}
|
||||
|
||||
public TowerData getTowerData() {
|
||||
if(towerData==null){
|
||||
if (towerData == null) {
|
||||
// because of mistake, null may be saved as storage at some machine, this if can be removed in future
|
||||
towerData = new TowerData();
|
||||
}
|
||||
@@ -599,7 +615,11 @@ public class Player {
|
||||
}
|
||||
|
||||
public boolean setProperty(PlayerProperty prop, int value) {
|
||||
return setPropertyWithSanityCheck(prop, value);
|
||||
return setPropertyWithSanityCheck(prop, value, true);
|
||||
}
|
||||
|
||||
public boolean setProperty(PlayerProperty prop, int value, boolean sendPacket) {
|
||||
return setPropertyWithSanityCheck(prop, value, sendPacket);
|
||||
}
|
||||
|
||||
public int getProperty(PlayerProperty prop) {
|
||||
@@ -794,6 +814,14 @@ public class Player {
|
||||
return showAvatarList;
|
||||
}
|
||||
|
||||
public int getLastDailyReset() {
|
||||
return this.lastDailyReset;
|
||||
}
|
||||
|
||||
public void setLastDailyReset(int value) {
|
||||
this.lastDailyReset = value;
|
||||
}
|
||||
|
||||
public boolean inMoonCard() {
|
||||
return moonCard;
|
||||
}
|
||||
@@ -926,12 +954,10 @@ public class Player {
|
||||
}
|
||||
this.save();
|
||||
}
|
||||
public boolean getStamina() {
|
||||
// Get Stamina
|
||||
public boolean getUnlimitedStamina() {
|
||||
return stamina;
|
||||
}
|
||||
public void setStamina(boolean stamina) {
|
||||
// Set Stamina
|
||||
public void setUnlimitedStamina(boolean stamina) {
|
||||
this.stamina = stamina;
|
||||
}
|
||||
public boolean inGodmode() {
|
||||
@@ -1268,6 +1294,7 @@ public class Player {
|
||||
public void loadBattlePassManager() {
|
||||
if (this.battlePassManager != null) return;
|
||||
this.battlePassManager = DatabaseHelper.loadBattlePass(this);
|
||||
this.battlePassManager.getMissions().values().removeIf(mission -> mission.getData() == null);
|
||||
}
|
||||
|
||||
public AbilityManager getAbilityManager() {
|
||||
@@ -1313,6 +1340,10 @@ public class Player {
|
||||
this.resetSendPlayerLocTime();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle daily reset.
|
||||
this.doDailyReset();
|
||||
|
||||
// Expedition
|
||||
var timeNow = Utils.getCurrentSeconds();
|
||||
var needNotify = false;
|
||||
@@ -1337,8 +1368,24 @@ public class Player {
|
||||
this.getResinManager().rechargeResin();
|
||||
}
|
||||
|
||||
private void doDailyReset() {
|
||||
// Check if we should execute a daily reset on this tick.
|
||||
int currentTime = Utils.getCurrentSeconds();
|
||||
|
||||
var currentDate = LocalDate.ofInstant(Instant.ofEpochSecond(currentTime), ZoneId.systemDefault());
|
||||
var lastResetDate = LocalDate.ofInstant(Instant.ofEpochSecond(this.getLastDailyReset()), ZoneId.systemDefault());
|
||||
|
||||
if (!currentDate.isAfter(lastResetDate)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We should - now execute all the resetting logic we need.
|
||||
// Reset forge points.
|
||||
this.setForgePoints(300_000);
|
||||
|
||||
// Done. Update last reset time.
|
||||
this.setLastDailyReset(currentTime);
|
||||
}
|
||||
|
||||
public void resetSendPlayerLocTime() {
|
||||
this.nextSendPlayerLocTime = System.currentTimeMillis() + 5000;
|
||||
@@ -1405,8 +1452,8 @@ public class Player {
|
||||
world.addPlayer(this);
|
||||
|
||||
// Multiplayer setting
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_MP_SETTING_TYPE, this.getMpSetting().getNumber());
|
||||
this.setProperty(PlayerProperty.PROP_IS_MP_MODE_AVAILABLE, 1);
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_MP_SETTING_TYPE, this.getMpSetting().getNumber(), false);
|
||||
this.setProperty(PlayerProperty.PROP_IS_MP_MODE_AVAILABLE, 1, false);
|
||||
|
||||
// Packets
|
||||
session.send(new PacketPlayerDataNotify(this)); // Player data
|
||||
@@ -1425,6 +1472,9 @@ public class Player {
|
||||
|
||||
getTodayMoonCard(); // The timer works at 0:0, some users log in after that, use this method to check if they have received a reward today or not. If not, send the reward.
|
||||
|
||||
// Battle Pass trigger
|
||||
this.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_LOGIN);
|
||||
|
||||
this.furnitureManager.onLogin();
|
||||
// Home
|
||||
home = GameHome.getByUid(getUid());
|
||||
@@ -1478,10 +1528,6 @@ public class Player {
|
||||
|
||||
// Call quit event.
|
||||
PlayerQuitEvent event = new PlayerQuitEvent(this); event.call();
|
||||
|
||||
//reset wood
|
||||
getDeforestationManager().resetWood();
|
||||
|
||||
}catch (Throwable e){
|
||||
e.printStackTrace();
|
||||
Grasscutter.getLogger().warn("Player (UID {}) save failure", getUid());
|
||||
@@ -1515,101 +1561,41 @@ public class Player {
|
||||
this.messageHandler = messageHandler;
|
||||
}
|
||||
|
||||
private void saveSanityCheckedProperty(PlayerProperty prop, int value) {
|
||||
getProperties().put(prop.getId(), value);
|
||||
public int getPropertyMin(PlayerProperty prop) {
|
||||
if (prop.getDynamicRange()) {
|
||||
return switch (prop) {
|
||||
default -> 0;
|
||||
};
|
||||
} else {
|
||||
return prop.getMin();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean setPropertyWithSanityCheck(PlayerProperty prop, int value) {
|
||||
if (prop == PlayerProperty.PROP_EXP) { // 1001
|
||||
if (!(value >= 0)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_BREAK_LEVEL) { // 1002
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_SATIATION_VAL) { // 1003
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_SATIATION_PENALTY_TIME) { // 1004
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_LEVEL) { // 4001
|
||||
if (!(value >= 0 && value <= 90)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_LAST_CHANGE_AVATAR_TIME) { // 10001
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_MAX_SPRING_VOLUME) { // 10002
|
||||
if (!(value >= 0 && value <= SotSManager.GlobalMaximumSpringVolume)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_CUR_SPRING_VOLUME) { // 10003
|
||||
int playerMaximumSpringVolume = getProperty(PlayerProperty.PROP_MAX_SPRING_VOLUME);
|
||||
if (!(value >= 0 && value <= playerMaximumSpringVolume)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_IS_SPRING_AUTO_USE) { // 10004
|
||||
if (!(value >= 0 && value <= 1)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_SPRING_AUTO_USE_PERCENT) { // 10005
|
||||
if (!(value >= 0 && value <= 100)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_IS_FLYABLE) { // 10006
|
||||
if (!(0 <= value && value <= 1)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_IS_WEATHER_LOCKED) { // 10007
|
||||
if (!(0 <= value && value <= 1)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_IS_GAME_TIME_LOCKED) { // 10008
|
||||
if (!(0 <= value && value <= 1)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_IS_TRANSFERABLE) { // 10009
|
||||
if (!(0 <= value && value <= 1)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_MAX_STAMINA) { // 10010
|
||||
if (!(value >= 0 && value <= StaminaManager.GlobalCharacterMaximumStamina)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_CUR_PERSIST_STAMINA) { // 10011
|
||||
int playerMaximumStamina = getProperty(PlayerProperty.PROP_MAX_STAMINA);
|
||||
if (!(value >= 0 && value <= playerMaximumStamina)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_CUR_TEMPORARY_STAMINA) { // 10012
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_LEVEL) { // 10013
|
||||
if (!(0 < value && value <= 90)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_EXP) { // 10014
|
||||
if (!(0 <= value)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_HCOIN) { // 10015
|
||||
// see PlayerProperty.PROP_PLAYER_HCOIN comments
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_SCOIN) { // 10016
|
||||
// See 10015
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_MP_SETTING_TYPE) { // 10017
|
||||
if (!(0 <= value && value <= 2)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_IS_MP_MODE_AVAILABLE) { // 10018
|
||||
if (!(0 <= value && value <= 1)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_WORLD_LEVEL) { // 10019
|
||||
if (!(0 <= value && value <= 8)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_RESIN) { // 10020
|
||||
// Do not set 160 as a cap, because player can have more than 160 when they use fragile resin.
|
||||
if (!(0 <= value)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_WAIT_SUB_HCOIN) { // 10022
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_WAIT_SUB_SCOIN) { // 10023
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_IS_ONLY_MP_WITH_PS_PLAYER) { // 10024
|
||||
if (!(0 <= value && value <= 1)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_MCOIN) { // 10025
|
||||
// see 10015
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_WAIT_SUB_MCOIN) { // 10026
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_LEGENDARY_KEY) { // 10027
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_IS_HAS_FIRST_SHARE) { // 10028
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_FORGE_POINT) { // 10029
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_CUR_CLIMATE_METER) { // 10035
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_CUR_CLIMATE_TYPE) { // 10036
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_CUR_CLIMATE_AREA_ID) { // 10037
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_CUR_CLIMATE_AREA_CLIMATE_TYPE) { // 10038
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_WORLD_LEVEL_LIMIT) { // 10039
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_WORLD_LEVEL_ADJUST_CD) { // 10040
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_LEGENDARY_DAILY_TASK_NUM) { // 10041
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_HOME_COIN) { // 10042
|
||||
if (!(0 <= value)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_WAIT_SUB_HOME_COIN) { // 10043
|
||||
// TODO: implement sanity check
|
||||
public int getPropertyMax(PlayerProperty prop) {
|
||||
if (prop.getDynamicRange()) {
|
||||
return switch (prop) {
|
||||
case PROP_CUR_SPRING_VOLUME -> getProperty(PlayerProperty.PROP_MAX_SPRING_VOLUME);
|
||||
case PROP_CUR_PERSIST_STAMINA -> getProperty(PlayerProperty.PROP_MAX_STAMINA);
|
||||
default -> 0;
|
||||
};
|
||||
} else {
|
||||
return prop.getMax();
|
||||
}
|
||||
saveSanityCheckedProperty(prop, value);
|
||||
}
|
||||
|
||||
private boolean setPropertyWithSanityCheck(PlayerProperty prop, int value, boolean sendPacket) {
|
||||
int min = this.getPropertyMin(prop);
|
||||
int max = this.getPropertyMax(prop);
|
||||
if (min <= value && value <= max) {
|
||||
this.properties.put(prop.getId(), value);
|
||||
if (sendPacket) {
|
||||
// Update player with packet
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, prop));
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package emu.grasscutter.game.props;
|
||||
|
||||
public enum BattlePassMissionRefreshType {
|
||||
BATTLE_PASS_MISSION_REFRESH_DAILY (0),
|
||||
BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE (1), // Weekly
|
||||
BATTLE_PASS_MISSION_REFRESH_SCHEDULE (2), // Per BP
|
||||
BATTLE_PASS_MISSION_REFRESH_CYCLE (1); // Event?
|
||||
|
||||
private final int value;
|
||||
|
||||
BattlePassMissionRefreshType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package emu.grasscutter.game.props;
|
||||
|
||||
import emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.MissionStatus;
|
||||
|
||||
public enum BattlePassMissionStatus {
|
||||
MISSION_STATUS_INVALID (0, MissionStatus.MISSION_STATUS_INVALID),
|
||||
MISSION_STATUS_UNFINISHED (1, MissionStatus.MISSION_STATUS_UNFINISHED),
|
||||
MISSION_STATUS_FINISHED (2, MissionStatus.MISSION_STATUS_FINISHED),
|
||||
MISSION_STATUS_POINT_TAKEN (3, MissionStatus.MISSION_STATUS_POINT_TAKEN);
|
||||
|
||||
private final int value;
|
||||
private final MissionStatus missionStatus;
|
||||
|
||||
BattlePassMissionStatus(int value, MissionStatus missionStatus) {
|
||||
this.value = value;
|
||||
this.missionStatus = missionStatus; // In case proto enum values change later
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public MissionStatus getMissionStatus() {
|
||||
return missionStatus;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,13 @@
|
||||
package emu.grasscutter.game.props;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Map.entry;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
@@ -133,4 +139,65 @@ public enum FightProperty {
|
||||
public static FightProperty getPropByName(String name) {
|
||||
return stringMap.getOrDefault(name, FIGHT_PROP_NONE);
|
||||
}
|
||||
|
||||
public static FightProperty getPropByShortName(String name) {
|
||||
return shortNameMap.getOrDefault(name, FIGHT_PROP_NONE);
|
||||
}
|
||||
|
||||
public static Set<String> getShortNames() {
|
||||
return shortNameMap.keySet();
|
||||
}
|
||||
|
||||
// This was originally for relic properties so some names might not be applicable for e.g. setstats
|
||||
private static final Map<String, FightProperty> shortNameMap = Map.ofEntries(
|
||||
// Normal relic stats
|
||||
entry("hp", FIGHT_PROP_HP),
|
||||
entry("atk", FIGHT_PROP_ATTACK),
|
||||
entry("def", FIGHT_PROP_DEFENSE),
|
||||
entry("hp%", FIGHT_PROP_HP_PERCENT),
|
||||
entry("atk%", FIGHT_PROP_ATTACK_PERCENT),
|
||||
entry("def%", FIGHT_PROP_DEFENSE_PERCENT),
|
||||
entry("em", FIGHT_PROP_ELEMENT_MASTERY),
|
||||
entry("er", FIGHT_PROP_CHARGE_EFFICIENCY),
|
||||
entry("hb", FIGHT_PROP_HEAL_ADD),
|
||||
entry("heal", FIGHT_PROP_HEAL_ADD),
|
||||
entry("cd", FIGHT_PROP_CRITICAL_HURT),
|
||||
entry("cdmg", FIGHT_PROP_CRITICAL_HURT),
|
||||
entry("cr", FIGHT_PROP_CRITICAL),
|
||||
entry("crate", FIGHT_PROP_CRITICAL),
|
||||
entry("phys%", FIGHT_PROP_PHYSICAL_ADD_HURT),
|
||||
entry("dendro%", FIGHT_PROP_GRASS_ADD_HURT),
|
||||
entry("geo%", FIGHT_PROP_ROCK_ADD_HURT),
|
||||
entry("anemo%", FIGHT_PROP_WIND_ADD_HURT),
|
||||
entry("hydro%", FIGHT_PROP_WATER_ADD_HURT),
|
||||
entry("cryo%", FIGHT_PROP_ICE_ADD_HURT),
|
||||
entry("electro%", FIGHT_PROP_ELEC_ADD_HURT),
|
||||
entry("pyro%", FIGHT_PROP_FIRE_ADD_HURT),
|
||||
// Other stats
|
||||
entry("maxhp", FIGHT_PROP_MAX_HP),
|
||||
entry("dmg", FIGHT_PROP_ADD_HURT), // This seems to get reset after attacks
|
||||
entry("cdr", FIGHT_PROP_SKILL_CD_MINUS_RATIO),
|
||||
entry("heali", FIGHT_PROP_HEALED_ADD),
|
||||
entry("shield", FIGHT_PROP_SHIELD_COST_MINUS_RATIO),
|
||||
entry("defi", FIGHT_PROP_DEFENCE_IGNORE_RATIO),
|
||||
entry("resall", FIGHT_PROP_SUB_HURT), // This seems to get reset after attacks
|
||||
entry("resanemo", FIGHT_PROP_WIND_SUB_HURT),
|
||||
entry("rescryo", FIGHT_PROP_ICE_SUB_HURT),
|
||||
entry("resdendro", FIGHT_PROP_GRASS_SUB_HURT),
|
||||
entry("reselectro", FIGHT_PROP_ELEC_SUB_HURT),
|
||||
entry("resgeo", FIGHT_PROP_ROCK_SUB_HURT),
|
||||
entry("reshydro", FIGHT_PROP_WATER_SUB_HURT),
|
||||
entry("respyro", FIGHT_PROP_FIRE_SUB_HURT),
|
||||
entry("resphys", FIGHT_PROP_PHYSICAL_SUB_HURT)
|
||||
);
|
||||
|
||||
private static final List<FightProperty> flatProps = Arrays.asList(
|
||||
FIGHT_PROP_BASE_HP, FIGHT_PROP_HP, FIGHT_PROP_BASE_ATTACK, FIGHT_PROP_ATTACK, FIGHT_PROP_BASE_DEFENSE,
|
||||
FIGHT_PROP_DEFENSE, FIGHT_PROP_HEALED_ADD, FIGHT_PROP_CUR_FIRE_ENERGY, FIGHT_PROP_CUR_ELEC_ENERGY,
|
||||
FIGHT_PROP_CUR_WATER_ENERGY, FIGHT_PROP_CUR_GRASS_ENERGY, FIGHT_PROP_CUR_WIND_ENERGY, FIGHT_PROP_CUR_ICE_ENERGY,
|
||||
FIGHT_PROP_CUR_ROCK_ENERGY, FIGHT_PROP_CUR_HP, FIGHT_PROP_MAX_HP, FIGHT_PROP_CUR_ATTACK, FIGHT_PROP_CUR_DEFENSE);
|
||||
|
||||
public static boolean isPercentage(FightProperty prop) {
|
||||
return !flatProps.contains(prop);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,41 +6,42 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
public enum PlayerProperty {
|
||||
PROP_EXP (1001),
|
||||
PROP_NONE (0),
|
||||
PROP_EXP (1001, 0),
|
||||
PROP_BREAK_LEVEL (1002),
|
||||
PROP_SATIATION_VAL (1003),
|
||||
PROP_SATIATION_PENALTY_TIME (1004),
|
||||
PROP_LEVEL (4001),
|
||||
PROP_LEVEL (4001, 0, 90),
|
||||
PROP_LAST_CHANGE_AVATAR_TIME (10001),
|
||||
PROP_MAX_SPRING_VOLUME (10002), // Maximum volume of the Statue of the Seven for the player [0, 8500000]
|
||||
PROP_CUR_SPRING_VOLUME (10003), // Current volume of the Statue of the Seven [0, PROP_MAX_SPRING_VOLUME]
|
||||
PROP_IS_SPRING_AUTO_USE (10004), // Auto HP recovery when approaching the Statue of the Seven [0, 1]
|
||||
PROP_SPRING_AUTO_USE_PERCENT (10005), // Auto HP recovery percentage [0, 100]
|
||||
PROP_IS_FLYABLE (10006), // Are you in a state that disables your flying ability? e.g. new player [0, 1]
|
||||
PROP_IS_WEATHER_LOCKED (10007),
|
||||
PROP_IS_GAME_TIME_LOCKED (10008),
|
||||
PROP_IS_TRANSFERABLE (10009),
|
||||
PROP_MAX_STAMINA (10010), // Maximum stamina of the player (0 - 24000)
|
||||
PROP_CUR_PERSIST_STAMINA (10011), // Used stamina of the player (0 - PROP_MAX_STAMINA)
|
||||
PROP_MAX_SPRING_VOLUME (10002, 0, 8_500_000), // Maximum volume of the Statue of the Seven for the player [0, 8500000]
|
||||
PROP_CUR_SPRING_VOLUME (10003, true), // Current volume of the Statue of the Seven [0, PROP_MAX_SPRING_VOLUME]
|
||||
PROP_IS_SPRING_AUTO_USE (10004, 0, 1), // Auto HP recovery when approaching the Statue of the Seven [0, 1]
|
||||
PROP_SPRING_AUTO_USE_PERCENT (10005, 0, 100), // Auto HP recovery percentage [0, 100]
|
||||
PROP_IS_FLYABLE (10006, 0, 1), // Are you in a state that disables your flying ability? e.g. new player [0, 1]
|
||||
PROP_IS_WEATHER_LOCKED (10007, 0, 1),
|
||||
PROP_IS_GAME_TIME_LOCKED (10008, 0, 1),
|
||||
PROP_IS_TRANSFERABLE (10009, 0, 1),
|
||||
PROP_MAX_STAMINA (10010, 0, 24_000), // Maximum stamina of the player (0 - 24000)
|
||||
PROP_CUR_PERSIST_STAMINA (10011, true), // Used stamina of the player (0 - PROP_MAX_STAMINA)
|
||||
PROP_CUR_TEMPORARY_STAMINA (10012),
|
||||
PROP_PLAYER_LEVEL (10013),
|
||||
PROP_PLAYER_LEVEL (10013, 1, 60),
|
||||
PROP_PLAYER_EXP (10014),
|
||||
PROP_PLAYER_HCOIN (10015), // Primogem (-inf, +inf)
|
||||
// It is known that Mihoyo will make Primogem negative in the cases that a player spends
|
||||
// his gems and then got a money refund, so negative is allowed.
|
||||
PROP_PLAYER_SCOIN (10016), // Mora [0, +inf)
|
||||
PROP_PLAYER_MP_SETTING_TYPE (10017), // Do you allow other players to join your game? [0=no 1=direct 2=approval]
|
||||
PROP_IS_MP_MODE_AVAILABLE (10018), // 0 if in quest or something that disables MP [0, 1]
|
||||
PROP_PLAYER_WORLD_LEVEL (10019), // [0, 8]
|
||||
PROP_PLAYER_RESIN (10020), // Original Resin [0, +inf)
|
||||
PROP_PLAYER_SCOIN (10016, 0), // Mora [0, +inf)
|
||||
PROP_PLAYER_MP_SETTING_TYPE (10017, 0, 2), // Do you allow other players to join your game? [0=no 1=direct 2=approval]
|
||||
PROP_IS_MP_MODE_AVAILABLE (10018, 0, 1), // 0 if in quest or something that disables MP [0, 1]
|
||||
PROP_PLAYER_WORLD_LEVEL (10019, 0, 8), // [0, 8]
|
||||
PROP_PLAYER_RESIN (10020, 0, 2000), // Original Resin [0, 2000] - note that values above 160 require refills
|
||||
PROP_PLAYER_WAIT_SUB_HCOIN (10022),
|
||||
PROP_PLAYER_WAIT_SUB_SCOIN (10023),
|
||||
PROP_IS_ONLY_MP_WITH_PS_PLAYER (10024), // Is only MP with PlayStation players? [0, 1]
|
||||
PROP_IS_ONLY_MP_WITH_PS_PLAYER (10024, 0, 1), // Is only MP with PlayStation players? [0, 1]
|
||||
PROP_PLAYER_MCOIN (10025), // Genesis Crystal (-inf, +inf) see 10015
|
||||
PROP_PLAYER_WAIT_SUB_MCOIN (10026),
|
||||
PROP_PLAYER_LEGENDARY_KEY (10027),
|
||||
PROP_IS_HAS_FIRST_SHARE (10028),
|
||||
PROP_PLAYER_FORGE_POINT (10029),
|
||||
PROP_PLAYER_FORGE_POINT (10029, 0, 300_000),
|
||||
PROP_CUR_CLIMATE_METER (10035),
|
||||
PROP_CUR_CLIMATE_TYPE (10036),
|
||||
PROP_CUR_CLIMATE_AREA_ID (10037),
|
||||
@@ -48,22 +49,55 @@ public enum PlayerProperty {
|
||||
PROP_PLAYER_WORLD_LEVEL_LIMIT (10039),
|
||||
PROP_PLAYER_WORLD_LEVEL_ADJUST_CD (10040),
|
||||
PROP_PLAYER_LEGENDARY_DAILY_TASK_NUM (10041),
|
||||
PROP_PLAYER_HOME_COIN (10042), // Realm currency [0, +inf)
|
||||
PROP_PLAYER_HOME_COIN (10042, 0), // Realm currency [0, +inf)
|
||||
PROP_PLAYER_WAIT_SUB_HOME_COIN (10043);
|
||||
|
||||
private final int id;
|
||||
private static final int inf = Integer.MAX_VALUE; // Maybe this should be something else?
|
||||
private final int id, min, max;
|
||||
private final boolean dynamicRange;
|
||||
private static final Int2ObjectMap<PlayerProperty> map = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
static {
|
||||
Stream.of(values()).forEach(e -> map.put(e.getId(), e));
|
||||
}
|
||||
|
||||
PlayerProperty(int id) {
|
||||
PlayerProperty(int id, int min, int max, boolean dynamicRange) {
|
||||
this.id = id;
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.dynamicRange = dynamicRange;
|
||||
}
|
||||
|
||||
PlayerProperty(int id, int min) {
|
||||
this(id, min, inf, false);
|
||||
}
|
||||
|
||||
PlayerProperty(int id, int min, int max) {
|
||||
this(id, min, max, false);
|
||||
}
|
||||
|
||||
PlayerProperty(int id) {
|
||||
this(id, Integer.MIN_VALUE, inf, false);
|
||||
}
|
||||
|
||||
PlayerProperty(int id, boolean dynamicRange) {
|
||||
this(id, Integer.MIN_VALUE, inf, dynamicRange);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public int getMin() {
|
||||
return this.min;
|
||||
}
|
||||
|
||||
public int getMax() {
|
||||
return this.max;
|
||||
}
|
||||
|
||||
public boolean getDynamicRange() {
|
||||
return dynamicRange;
|
||||
}
|
||||
|
||||
public static PlayerProperty getPropById(int value) {
|
||||
|
||||
337
src/main/java/emu/grasscutter/game/props/WatcherTriggerType.java
Normal file
337
src/main/java/emu/grasscutter/game/props/WatcherTriggerType.java
Normal file
@@ -0,0 +1,337 @@
|
||||
package emu.grasscutter.game.props;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
public enum WatcherTriggerType {
|
||||
TRIGGER_NONE (0),
|
||||
TRIGGER_COMBAT_CONFIG_COMMON (1),
|
||||
TRIGGER_ELEMENT_VIEW (2),
|
||||
TRIGGER_ENTER_AIRFLOW (5),
|
||||
TRIGGER_NEW_MONSTER (6),
|
||||
TRIGGER_NEW_AFFIX (8),
|
||||
TRIGGER_CHANGE_INPUT_DEVICE_TYPE (9),
|
||||
TRIGGER_PAIMON_ANGRY_VOICE_EASTER_EGG (10),
|
||||
TRIGGER_WIND_CRYSTAL (11),
|
||||
TRIGGER_ELEMENT_BALL (101),
|
||||
TRIGGER_WORLD_LEVEL_UP (102),
|
||||
TRIGGER_DUNGEON_ENTRY_TO_BE_EXPLORED (103),
|
||||
TRIGGER_UNLOCK_GATE_TEMPLE (104),
|
||||
TRIGGER_UNLOCK_AREA (105),
|
||||
TRIGGER_UNLOCK_TRANS_POINT (106),
|
||||
TRIGGER_OPEN_CHEST_WITH_GADGET_ID (107),
|
||||
TRIGGER_CITY_LEVEL_UP (108),
|
||||
TRIGGER_MONSTER_DIE (109),
|
||||
TRIGGER_PLATFORM_START_MOVE (110),
|
||||
TRIGGER_GROUP_NOTIFY (111),
|
||||
TRIGGER_ELEMENT_TYPE_CHANGE (112),
|
||||
TRIGGER_GADGET_INTERACTABLE (113),
|
||||
TRIGGER_COLLECT_SET_OF_READINGS (114),
|
||||
TRIGGER_TELEPORT_WITH_CERTAIN_PORTAL (115),
|
||||
TRIGGER_WORLD_GATHER (116),
|
||||
TRIGGER_TAKE_GENERAL_REWARD (117),
|
||||
TRIGGER_BATTLE_FOR_MONSTER_DIE_OR (118),
|
||||
TRIGGER_BATTLE_FOR_MONSTER_DIE_AND (119),
|
||||
TRIGGER_OPEN_WORLD_CHEST (120),
|
||||
TRIGGER_ENTER_CLIMATE_AREA (121),
|
||||
TRIGGER_UNLOCK_SCENE_POINT (122),
|
||||
TRIGGER_INTERACT_GADGET_WITH_INTERACT_ID (123),
|
||||
TRIGGER_OBTAIN_AVATAR (201),
|
||||
TRIGGER_PLAYER_LEVEL (202),
|
||||
TRIGGER_AVATAR_UPGRADE (203),
|
||||
TRIGGER_AVATAR_PROMOTE (204),
|
||||
TRIGGER_WEAPON_UPGRADE (205),
|
||||
TRIGGER_WEAPON_PROMOTE (206),
|
||||
TRIGGER_RELIQUARY_UPGRADE (207),
|
||||
TRIGGER_WEAR_RELIQUARY (208),
|
||||
TRIGGER_UPGRADE_TALENT (209),
|
||||
TRIGGER_UNLOCK_RECIPE (210),
|
||||
TRIGGER_RELIQUARY_SET_NUM (211),
|
||||
TRIGGER_OBTAIN_MATERIAL_NUM (212),
|
||||
TRIGGER_OBTAIN_RELIQUARY_NUM (213),
|
||||
TRIGGER_GACHA_NUM (214),
|
||||
TRIGGER_ANY_RELIQUARY_UPGRADE (215),
|
||||
TRIGGER_FETTER_LEVEL_AVATAR_NUM (216),
|
||||
TRIGGER_SKILLED_AT_RECIPE (217),
|
||||
TRIGGER_RELIQUARY_UPGRADE_EQUAL_RANK_LEVEL (218),
|
||||
TRIGGER_SPECIFIED_WEAPON_UPGRADE (219),
|
||||
TRIGGER_SPECIFIED_WEAPON_AWAKEN (220),
|
||||
TRIGGER_UNLOCK_SPECIFIC_RECIPE_OR (221),
|
||||
TRIGGER_POSSESS_MATERIAL_NUM (222),
|
||||
TRIGGER_EXHIBITION_ACCUMULABLE_VALUE (223),
|
||||
TRIGGER_EXHIBITION_REPLACEABLE_VALUE_SETTLE_NUM (224),
|
||||
TRIGGER_ANY_WEAPON_UPGRADE_NUM (225),
|
||||
TRIGGER_ANY_RELIQUARY_UPGRADE_NUM (226),
|
||||
TRIGGER_ACTIVITY_SCORE_EXCEED_VALUE (227),
|
||||
TRIGGER_UNLOCK_SPECIFIC_FORGE_OR (228),
|
||||
TRIGGER_UNLOCK_SPECIFIC_ANIMAL_CODEX (229),
|
||||
TRIGGER_OBTAIN_ITEM_NUM (230),
|
||||
TRIGGER_CAPTURE_ANIMAL (231),
|
||||
TRIGGER_DAILY_TASK (301),
|
||||
TRIGGER_RAND_TASK (302),
|
||||
TRIGGER_AVATAR_EXPEDITION (303),
|
||||
TRIGGER_FINISH_TOWER_LEVEL (304),
|
||||
TRIGGER_WORLD_BOSS_REWARD (306),
|
||||
TRIGGER_FINISH_DUNGEON (307),
|
||||
TRIGGER_START_AVATAR_EXPEDITION (308),
|
||||
TRIGGER_OPEN_BLOSSOM_CHEST (309),
|
||||
TRIGGER_FINISH_BLOSSOM_PROGRESS (310),
|
||||
TRIGGER_DONE_TOWER_GADGET_UNHURT (311),
|
||||
TRIGGER_DONE_TOWER_STARS (312),
|
||||
TRIGGER_DONE_TOWER_UNHURT (313),
|
||||
TRIGGER_STEAL_FOOD_TIMES (314),
|
||||
TRIGGER_DONE_DUNGEON_WITH_SAME_ELEMENT_AVATARS (315),
|
||||
TRIGGER_GROUP_FLIGHT_CHALLENGE_REACH_POINTS (316),
|
||||
TRIGGER_FINISH_DAILY_DELIVERY_NUM (317),
|
||||
TRIGGER_TOWER_STARS_NUM (318),
|
||||
TRIGGER_FINISH_SPECIFED_TYPE_BLOSSOM_NUM (319),
|
||||
TRIGGER_FINISH_SPECIFED_TYPE_BLOSSOM_CLIMATE_METER (320),
|
||||
TRIGGER_FINISH_BLOSSOM_GROUP_VARIABLE_GT (321),
|
||||
TRIGGER_EFFIGY_CHALLENGE_SCORE (322),
|
||||
TRIGGER_FINISH_ROUTINE (323),
|
||||
TRIGGER_ACTIVITY_EXPEDITION_FINISH (324),
|
||||
TRIGGER_ACTIVITY_CHANNELLER_SLAB_FINISH_ALL_CAMP (325),
|
||||
TRIGGER_ACTIVITY_CHANNELLER_SLAB_FINISH_ALL_ONEOFF_DUNGEON (326),
|
||||
TRIGGER_ACTIVITY_CHANNELLER_SLAB_LOOP_DUNGEON_TOTAL_SCORE (327),
|
||||
TRIGGER_GROUP_SUMMER_TIME_SPRINT_BOAT_REACH_POINTS (328),
|
||||
TRIGGER_WEEKLY_BOSS_KILL (329),
|
||||
TRIGGER_BOUNCE_CONJURING_FINISH_COUNT (330),
|
||||
TRIGGER_BOUNCE_CONJURING_SCORE (331),
|
||||
TRIGGER_GROUP_VARIABLE_SET_VALUE_TO (332),
|
||||
TRIGGER_KILL_GADGETS_BY_SPECIFIC_SKILL (333),
|
||||
TRIGGER_KILL_MONSTERS_WITHOUT_VEHICLE (334),
|
||||
TRIGGER_KILL_MONSTER_IN_AREA (335),
|
||||
TRIGGER_ENTER_VEHICLE (336),
|
||||
TRIGGER_VEHICLE_DURATION (337),
|
||||
TRIGGER_VEHICLE_FRIENDS (338),
|
||||
TRIGGER_VEHICLE_KILLED_BY_MONSTER (339),
|
||||
TRIGGER_VEHICLE_DASH (340),
|
||||
TRIGGER_DO_COOK (401),
|
||||
TRIGGER_DO_FORGE (402),
|
||||
TRIGGER_DO_COMPOUND (403),
|
||||
TRIGGER_DO_COMBINE (404),
|
||||
TRIGGER_BUY_SHOP_GOODS (405),
|
||||
TRIGGER_FORGE_WEAPON (406),
|
||||
TRIGGER_MP_PLAY_BATTLE_WIN (421),
|
||||
TRIGGER_KILL_GROUP_MONSTER (422),
|
||||
TRIGGER_CRUCIBLE_ELEMENT_SCORE (423),
|
||||
TRIGGER_MP_DUNGEON_TIMES (424),
|
||||
TRIGGER_MP_KILL_MONSTER_NUM (425),
|
||||
TRIGGER_CRUCIBLE_MAX_BALL (426),
|
||||
TRIGGER_CRUCIBLE_MAX_SCORE (427),
|
||||
TRIGGER_CRUCIBLE_SUBMIT_BALL (428),
|
||||
TRIGGER_CRUCIBLE_WORLD_LEVEL_SCORE (429),
|
||||
TRIGGER_MP_PLAY_GROUP_STATISTIC (430),
|
||||
TRIGGER_KILL_GROUP_SPECIFIC_MONSTER (431),
|
||||
TRIGGER_REACH_MP_PLAY_SCORE (432),
|
||||
TRIGGER_REACH_MP_PLAY_RECORD (433),
|
||||
TRIGGER_TREASURE_MAP_DONE_REGION (434),
|
||||
TRIGGER_SEA_LAMP_MINI_QUEST (435),
|
||||
TRIGGER_FINISH_FIND_HILICHURL_LEVEL (436),
|
||||
TRIGGER_COMBINE_ITEM (437),
|
||||
TRIGGER_FINISH_CHALLENGE_IN_DURATION (438),
|
||||
TRIGGER_FINISH_CHALLENGE_LEFT_TIME (439),
|
||||
TRIGGER_MP_KILL_MONSTER_ID_NUM (440),
|
||||
TRIGGER_LOGIN (501),
|
||||
TRIGGER_COST_MATERIAL (502),
|
||||
TRIGGER_DELIVER_ITEM_TO_SALESMAN (503),
|
||||
TRIGGER_USE_ITEM (504),
|
||||
TRIGGER_ACCUMULATE_DAILY_LOGIN (505),
|
||||
TRIGGER_FINISH_CHALLENGE (601),
|
||||
TRIGGER_MECHANICUS_UNLOCK_GEAR (602),
|
||||
TRIGGER_MECHANICUS_LEVELUP_GEAR (603),
|
||||
TRIGGER_MECHANICUS_DIFFICULT (604),
|
||||
TRIGGER_MECHANICUS_DIFFICULT_SCORE (605),
|
||||
TRIGGER_MECHANICUS_KILL_MONSTER (606),
|
||||
TRIGGER_MECHANICUS_BUILDING_POINT (607),
|
||||
TRIGGER_MECHANICUS_DIFFICULT_EQ (608),
|
||||
TRIGGER_MECHANICUS_BATTLE_END (609),
|
||||
TRIGGER_MECHANICUS_BATTLE_END_EXCAPED_LESS_THAN (610),
|
||||
TRIGGER_MECHANICUS_BATTLE_END_POINTS_MORE_THAN (611),
|
||||
TRIGGER_MECHANICUS_BATTLE_END_GEAR_MORE_THAN (612),
|
||||
TRIGGER_MECHANICUS_BATTLE_END_PURE_GEAR_DAMAGE (613),
|
||||
TRIGGER_MECHANICUS_BATTLE_END_CARD_PICK_MORE_THAN (614),
|
||||
TRIGGER_MECHANICUS_BATTLE_END_CARD_TARGET_MORE_THAN (615),
|
||||
TRIGGER_MECHANICUS_BATTLE_END_BUILD_GEAR_MORE_THAN (616),
|
||||
TRIGGER_MECHANICUS_BATTLE_END_GEAR_KILL_MORE_THAN (617),
|
||||
TRIGGER_MECHANICUS_BATTLE_END_ROUND_MORE_THAN (618),
|
||||
TRIGGER_MECHANICUS_BATTLE_END_ROUND (619),
|
||||
TRIGGER_MECHANICUS_BATTLE_FIN_CHALLENGE_MORE_THAN (620),
|
||||
TRIGGER_MECHANICUS_BATTLE_WATCHER_FINISH_COUNT (621),
|
||||
TRIGGER_MECHANICUS_BATTLE_INTERACT_COUNT (622),
|
||||
TRIGGER_MECHANICUS_BATTLE_DIFFICULT_ESCAPE (623),
|
||||
TRIGGER_MECHANICUS_BATTLE_DIFFICULT_GEAR_NUM (624),
|
||||
TRIGGER_MECHANICUS_BATTLE_DIFFICULT_GEAR_ID_NUM (625),
|
||||
TRIGGER_FLEUR_FAIR_DUNGEON_FINISH_IN_LIMIT_TIME (626),
|
||||
TRIGGER_FLEUR_FAIR_DUNGEON_FINISH_KEEP_ENERGY (627),
|
||||
TRIGGER_FLEUR_FAIR_DUNGEON_FINISH_WITH_GROUP_VARIABLE (628),
|
||||
TRIGGER_FLEUR_FAIR_DUNGEON_FINISH_WITH_BUFF_NUM (629),
|
||||
TRIGGER_FLEUR_FAIR_DUNGEON_MISSION_FINISH (630),
|
||||
TRIGGER_FINISH_DUNGEON_AND_CHALLENGE_REMAIN_TIME_GREATER_THAN (631),
|
||||
TRIGGER_FINISH_DUNGEON_WITH_MIST_TRIAL_STAT (632),
|
||||
TRIGGER_DUNGEON_MIST_TRIAL_STAT (633),
|
||||
TRIGGER_DUNGEON_ELEMENT_REACTION_NUM (634),
|
||||
TRIGGER_LEVEL_AVATAR_FINISH_DUNGEON_COUNT (635),
|
||||
TRIGGER_CHESS_REACH_LEVEL (636),
|
||||
TRIGGER_CHESS_DUNGEON_ADD_SCORE (637),
|
||||
TRIGGER_CHESS_DUNGEON_SUCC_WITH_ESCAPED_MONSTERS_LESS_THAN (638),
|
||||
TRIGGER_CHESS_DUNGEON_SUCC_WITH_TOWER_COUNT_LESS_OR_EQUAL (639),
|
||||
TRIGGER_CHESS_DUNGEON_SUCC_WITH_CARD_COUNT_LESS_OR_EQUAL (640),
|
||||
TRIGGER_CHESS_DUNGEON_SUCC_WITH_CARD_COUNT_GREATER_THAN (641),
|
||||
TRIGGER_CHESS_KILL_MONSTERS (642),
|
||||
TRIGGER_CHESS_COST_BUILDING_POINTS (643),
|
||||
TRIGGER_SUMO_STAGE_SCORE_REACH (644),
|
||||
TRIGGER_SUMO_TOTAL_MAX_SCORE_REACH (645),
|
||||
TRIGGER_ROGUE_DESTROY_GADGET_NUM (646),
|
||||
TRIGGER_ROGUE_KILL_MONSTER_NUM (647),
|
||||
TRIGGER_ROGUE_FINISH_WITHOUT_USING_SPRING_CELL (649),
|
||||
TRIGGER_ROGUE_FINISH_ALL_CHALLENGE_CELL (650),
|
||||
TRIGGER_ROGUE_FINISH_WITH_AVATAR_ELEMENT_TYPE_NUM_LESS_THAN (651),
|
||||
TRIGGER_ROGUE_FINISH_WITH_AVATAR_NUM_LESS_THAN (652),
|
||||
TRIGGER_ROGUE_FINISH_NO_AVATAR_DEAD (653),
|
||||
TRIGGER_ROGUE_SHIKIGAMI_UPGRADE (654),
|
||||
TRIGGER_ROGUE_CURSE_NUM (655),
|
||||
TRIGGER_ROGUE_SELECT_CARD_NUM (656),
|
||||
TRIGGER_FINISH_QUEST_AND (700),
|
||||
TRIGGER_FINISH_QUEST_OR (701),
|
||||
TRIGGER_DAILY_TASK_VAR_EQUAL (702),
|
||||
TRIGGER_QUEST_GLOBAL_VAR_EQUAL (703),
|
||||
TRIGGER_TALK_NUM (704),
|
||||
TRIGGER_FINISH_PARENT_QUEST_AND (705),
|
||||
TRIGGER_FINISH_PARENT_QUEST_OR (706),
|
||||
TRIGGER_ELEMENT_REACTION_TIMELIMIT_NUM (800),
|
||||
TRIGGER_ELEMENT_REACTION_TIMELIMIT_KILL_NUM (801),
|
||||
TRIGGER_ELEMENT_REACTION_TIMELIMIT_DAMAGE_NUM (802),
|
||||
TRIGGER_ABILITY_STATE_PASS_TIME (803),
|
||||
TRIGGER_MAX_CRITICAL_DAMAGE (804),
|
||||
TRIGGER_FULL_SATIATION_TEAM_AVATAR_NUM (805),
|
||||
TRIGGER_KILLED_BY_CERTAIN_MONSTER (806),
|
||||
TRIGGER_CUR_AVATAR_HURT (807),
|
||||
TRIGGER_CUR_AVATAR_ABILITY_STATE (808),
|
||||
TRIGGER_USE_ENERGY_SKILL_NUM_TIMELIMIT (809),
|
||||
TRIGGER_SHIELD_SOURCE_NUM (810),
|
||||
TRIGGER_CUR_AVATAR_HURT_BY_SPECIFIC_ABILITY (811),
|
||||
TRIGGER_KILLED_BY_SPECIFIC_ABILITY (812),
|
||||
TRIGGER_MAX_DASH_TIME (900),
|
||||
TRIGGER_MAX_FLY_TIME (901),
|
||||
TRIGGER_MAX_FLY_MAP_DISTANCE (902),
|
||||
TRIGGER_SIT_DOWN_IN_POINT (903),
|
||||
TRIGGER_DASH (904),
|
||||
TRIGGER_CLIMB (905),
|
||||
TRIGGER_FLY (906),
|
||||
TRIGGER_CITY_REPUTATION_LEVEL (930),
|
||||
TRIGGER_CITY_REPUTATION_FINISH_REQUEST (931),
|
||||
TRIGGER_HUNTING_FINISH_NUM (932),
|
||||
TRIGGER_HUNTING_FAIL_NUM (933),
|
||||
TRIGGER_OFFERING_LEVEL (934),
|
||||
TRIGGER_MIRACLE_RING_DELIVER_ITEM (935),
|
||||
TRIGGER_MIRACLE_RING_TAKE_REWARD (936),
|
||||
TRIGGER_BLESSING_EXCHANGE_PIC_NUM (937),
|
||||
TRIGGER_BLESSING_REDEEM_REWARD_NUM (938),
|
||||
TRIGGER_GALLERY_BALLOON_REACH_SCORE (939),
|
||||
TRIGGER_GALLERY_FALL_REACH_SCORE (940),
|
||||
TRIGGER_FLEUR_FAIR_MUSIC_GAME_REACH_SCORE (941),
|
||||
TRIGGER_MAIN_COOP_SAVE_POINT_AND (942),
|
||||
TRIGGER_MAIN_COOP_SAVE_POINT_OR (943),
|
||||
TRIGGER_MAIN_COOP_VAR_EQUAL (944),
|
||||
TRIGGER_FINISH_ALL_ARENA_CHALLENGE_WATCHER_IN_SCHEDULE (945),
|
||||
TRIGGER_GALLERY_BUOYANT_COMBAT_REACH_SCORE (946),
|
||||
TRIGGER_BUOYANT_COMBAT_REACH_NEW_SCORE_LEVEL (947),
|
||||
TRIGGER_PLACE_MIRACLE_RING (948),
|
||||
TRIGGER_LUNA_RITE_SEARCH (949),
|
||||
TRIGGER_GALLERY_FISH_REACH_SCORE (950),
|
||||
TRIGGER_GALLERY_TRIATHLON_REACH_SCORE (951),
|
||||
TRIGGER_WINTER_CAMP_SNOWMAN_COMPLEIET (952),
|
||||
TRIGGER_CREATE_CUSTOM_DUNGEON (953),
|
||||
TRIGGER_PUBLISH_CUSTOM_DUNGEON (954),
|
||||
TRIGGER_PLAY_OTHER_CUSTOM_DUNGEON (955),
|
||||
TRIGGER_FINISH_CUSTOM_DUNGEON_OFFICIAL (956),
|
||||
TRIGGER_CUSTOM_DUNGEON_OFFICIAL_COIN (957),
|
||||
TRIGGER_OBTAIN_WOOD_TYPE (1000),
|
||||
TRIGGER_OBTAIN_WOOD_COUNT (1001),
|
||||
TRIGGER_UNLOCK_FURNITURE_COUNT (1002),
|
||||
TRIGGER_FURNITURE_MAKE (1003),
|
||||
TRIGGER_HOME_LEVEL (1004),
|
||||
TRIGGER_HOME_COIN (1005),
|
||||
TRIGGER_HOME_COMFORT_LEVEL (1006),
|
||||
TRIGGER_HOME_LIMITED_SHOP_BUY (1007),
|
||||
TRIGGER_FURNITURE_SUITE_TYPE (1008),
|
||||
TRIGGER_ARRANGEMENT_FURNITURE_COUNT (1009),
|
||||
TRIGGER_ENTER_SELF_HOME (1010),
|
||||
TRIGGER_HOME_MODULE_COMFORT_VALUE (1011),
|
||||
TRIGGER_HOME_ENTER_ROOM (1012),
|
||||
TRIGGER_HOME_AVATAR_IN (1013),
|
||||
TRIGGER_HOME_AVATAR_REWARD_EVENT_COUNT (1014),
|
||||
TRIGGER_HOME_AVATAR_TALK_FINISH_COUNT (1015),
|
||||
TRIGGER_HOME_AVATAR_REWARD_EVENT_ALL_COUNT (1016),
|
||||
TRIGGER_HOME_AVATAR_TALK_FINISH_ALL_COUNT (1017),
|
||||
TRIGGER_HOME_AVATAR_FETTER_GET (1018),
|
||||
TRIGGER_HOME_AVATAR_IN_COUNT (1019),
|
||||
TRIGGER_HOME_DO_PLANT (1020),
|
||||
TRIGGER_ARRANGEMENT_FURNITURE (1021),
|
||||
TRIGGER_HOME_GATHER_COUNT (1022),
|
||||
TRIGGER_HOME_FIELD_GATHER_COUNT (1023),
|
||||
TRIGGER_HOME_UNLOCK_BGM_COUNT (1024),
|
||||
TRIGGER_FISHING_SUCC_NUM (1100),
|
||||
TRIGGER_FISHING_KEEP_BONUS (1101),
|
||||
TRIGGER_EMPTY_FISH_POOL (1102),
|
||||
TRIGGER_FISHING_FAIL_NUM (1103),
|
||||
TRIGGER_SHOCK_FISH_NUM (1104),
|
||||
TRIGGER_PLANT_FLOWER_SET_WISH (1105),
|
||||
TRIGGER_PLANT_FLOWER_GIVE_FLOWER (1106),
|
||||
TRIGGER_PLANT_FLOWER_OBTAIN_FLOWER_TYPE (1107),
|
||||
TRIGGER_PLANT_FLOWER_COMMON_OBTAIN_FLOWER_TYPE (1108),
|
||||
TRIGGER_FINISH_LANV2_PROJECTION_LEVEL (1111),
|
||||
TRIGGER_GALLERY_SALVAGE_REACH_SCORE (1112),
|
||||
TRIGGER_LANV2_FIREWORKS_CHALLENGE_REACH_SCORE (1113),
|
||||
TRIGGER_POTION_STAGE_LEVEL_PASS_NUM (1115),
|
||||
TRIGGER_POTION_STAGE_OBTAIN_MEDAL_NUM (1116),
|
||||
TRIGGER_POTION_STAGE_REACH_TOTAL_SCORE (1117),
|
||||
TRIGGER_BARTENDER_FINISH_STORY_MODULE (1120),
|
||||
TRIGGER_BARTENDER_CHALLENGE_MODULE_LEVEL_SCORE (1121),
|
||||
TRIGGER_BARTENDER_UNLOCK_FORMULA (1122),
|
||||
TRIGGER_MICHIAE_MATSURI_UNLOCK_CRYSTAL_SKILL_REACH_NUM (1123),
|
||||
TRIGGER_MICHIAE_MATSURI_FINISH_DARK_CHALLENGE_REACH_NUM (1124),
|
||||
TRIGGER_CAPTURE_ENV_ANIMAL_REACH_NUM (1125),
|
||||
TRIGGER_SPICE_MAKE_FORMULA_TIMES (1126),
|
||||
TRIGGER_SPICE_GIVE_FOOD_TIMES (1127),
|
||||
TRIGGER_SPICE_MAKE_FORMULA_SUCCESSFUL_TIMES (1128),
|
||||
TRIGGER_IRODORI_FINISH_FLOWER_THEME (1131),
|
||||
TRIGGER_IRODORI_FINISH_MASTER_STAGE (1132),
|
||||
TRIGGER_IRODORI_CHESS_STAGE_REACH_SCORE (1133),
|
||||
TRIGGER_IRODORI_FINISH_POETRY_THEME (1134),
|
||||
TRIGGER_PHOTO_FINISH_POS_ID (1135),
|
||||
TRIGGER_CRYSTAL_LINK_LEVEL_SCORE_REACH (1138),
|
||||
TRIGGER_CRYSTAL_LINK_TOTAL_MAX_SCORE_REACH (1139);
|
||||
|
||||
private final int value;
|
||||
private static final Int2ObjectMap<WatcherTriggerType> map = new Int2ObjectOpenHashMap<>();
|
||||
private static final Map<String, WatcherTriggerType> stringMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
Stream.of(values()).forEach(e -> {
|
||||
map.put(e.getValue(), e);
|
||||
stringMap.put(e.name(), e);
|
||||
});
|
||||
}
|
||||
|
||||
private WatcherTriggerType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static WatcherTriggerType getTypeByValue(int value) {
|
||||
return map.getOrDefault(value, TRIGGER_NONE);
|
||||
}
|
||||
|
||||
public static WatcherTriggerType getTypeByName(String name) {
|
||||
return stringMap.getOrDefault(name, TRIGGER_NONE);
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import emu.grasscutter.server.game.GameServer;
|
||||
import java.io.FileReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static emu.grasscutter.Configuration.*;
|
||||
@@ -49,6 +50,12 @@ public class TowerScheduleManager {
|
||||
return data;
|
||||
}
|
||||
|
||||
public List<Integer> getAllFloors() {
|
||||
List<Integer> floors = new ArrayList<>(this.getCurrentTowerScheduleData().getEntranceFloorId());
|
||||
floors.addAll(this.getScheduleFloors());
|
||||
return floors;
|
||||
}
|
||||
|
||||
public List<Integer> getScheduleFloors() {
|
||||
return getCurrentTowerScheduleData().getSchedules().get(0).getFloorList();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user