mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2026-02-06 18:17:00 +01:00
Merge remote-tracking branch 'origin/development' into tower
This commit is contained in:
202
src/main/java/emu/grasscutter/game/ability/AbilityManager.java
Normal file
202
src/main/java/emu/grasscutter/game/ability/AbilityManager.java
Normal file
@@ -0,0 +1,202 @@
|
||||
package emu.grasscutter.game.ability;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.custom.AbilityModifier;
|
||||
import emu.grasscutter.data.custom.AbilityModifier.AbilityModifierAction;
|
||||
import emu.grasscutter.data.custom.AbilityModifier.AbilityModifierActionType;
|
||||
import emu.grasscutter.data.def.ItemData;
|
||||
import emu.grasscutter.data.custom.AbilityModifierEntry;
|
||||
import emu.grasscutter.game.entity.EntityItem;
|
||||
import emu.grasscutter.game.entity.GameEntity;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.proto.AbilityActionGenerateElemBallOuterClass.AbilityActionGenerateElemBall;
|
||||
import emu.grasscutter.net.proto.AbilityInvokeArgumentOuterClass.AbilityInvokeArgument;
|
||||
import emu.grasscutter.net.proto.AbilityInvokeEntryHeadOuterClass.AbilityInvokeEntryHead;
|
||||
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
|
||||
import emu.grasscutter.net.proto.AbilityMetaModifierChangeOuterClass.AbilityMetaModifierChange;
|
||||
import emu.grasscutter.net.proto.AbilityMetaReInitOverrideMapOuterClass.AbilityMetaReInitOverrideMap;
|
||||
import emu.grasscutter.net.proto.AbilityScalarTypeOuterClass.AbilityScalarType;
|
||||
import emu.grasscutter.net.proto.AbilityScalarValueEntryOuterClass.AbilityScalarValueEntry;
|
||||
import emu.grasscutter.net.proto.ModifierActionOuterClass.ModifierAction;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
|
||||
public class AbilityManager {
|
||||
private Player player;
|
||||
|
||||
public AbilityManager(Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
public void onAbilityInvoke(AbilityInvokeEntry invoke) throws Exception {
|
||||
//System.out.println(invoke.getArgumentType() + " (" + invoke.getArgumentTypeValue() + "): " + Utils.bytesToHex(invoke.toByteArray()));
|
||||
switch (invoke.getArgumentType()) {
|
||||
case ABILITY_META_OVERRIDE_PARAM:
|
||||
handleOverrideParam(invoke);
|
||||
break;
|
||||
case ABILITY_META_REINIT_OVERRIDEMAP:
|
||||
handleReinitOverrideMap(invoke);
|
||||
break;
|
||||
case ABILITY_META_MODIFIER_CHANGE:
|
||||
handleModifierChange(invoke);
|
||||
break;
|
||||
case ABILITY_MIXIN_COST_STAMINA:
|
||||
handleMixinCostStamina(invoke);
|
||||
break;
|
||||
case ABILITY_ACTION_GENERATE_ELEM_BALL:
|
||||
handleGenerateElemBall(invoke);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleOverrideParam(AbilityInvokeEntry invoke) throws Exception {
|
||||
GameEntity entity = player.getScene().getEntityById(invoke.getEntityId());
|
||||
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
AbilityScalarValueEntry entry = AbilityScalarValueEntry.parseFrom(invoke.getAbilityData());
|
||||
|
||||
entity.getMetaOverrideMap().put(entry.getKey().getStr(), entry.getFloatValue());
|
||||
}
|
||||
|
||||
private void handleReinitOverrideMap(AbilityInvokeEntry invoke) throws Exception {
|
||||
GameEntity entity = player.getScene().getEntityById(invoke.getEntityId());
|
||||
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
AbilityMetaReInitOverrideMap map = AbilityMetaReInitOverrideMap.parseFrom(invoke.getAbilityData());
|
||||
|
||||
for (AbilityScalarValueEntry entry : map.getOverrideMapList()) {
|
||||
entity.getMetaOverrideMap().put(entry.getKey().getStr(), entry.getFloatValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleModifierChange(AbilityInvokeEntry invoke) throws Exception {
|
||||
GameEntity target = player.getScene().getEntityById(invoke.getEntityId());
|
||||
if (target == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
AbilityInvokeEntryHead head = invoke.getHead();
|
||||
if (head == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
AbilityMetaModifierChange data = AbilityMetaModifierChange.parseFrom(invoke.getAbilityData());
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntity sourceEntity = player.getScene().getEntityById(data.getApplyEntityId());
|
||||
if (sourceEntity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This is not how it works but we will keep it for now since healing abilities dont work properly anyways
|
||||
if (data.getAction() == ModifierAction.ADDED && data.getParentAbilityName() != null) {
|
||||
// Handle add modifier here
|
||||
String modifierString = data.getParentAbilityName().getStr();
|
||||
AbilityModifierEntry modifier = GameData.getAbilityModifiers().get(modifierString);
|
||||
|
||||
if (modifier != null && modifier.getOnAdded().size() > 0) {
|
||||
for (AbilityModifierAction action : modifier.getOnAdded()) {
|
||||
invokeAction(action, target, sourceEntity);
|
||||
}
|
||||
}
|
||||
|
||||
// Add to meta modifier list
|
||||
target.getMetaModifiers().put(head.getInstancedModifierId(), modifierString);
|
||||
} else if (data.getAction() == ModifierAction.REMOVED) {
|
||||
String modifierString = target.getMetaModifiers().get(head.getInstancedModifierId());
|
||||
|
||||
if (modifierString != null) {
|
||||
// Get modifier and call on remove event
|
||||
AbilityModifierEntry modifier = GameData.getAbilityModifiers().get(modifierString);
|
||||
|
||||
if (modifier != null && modifier.getOnRemoved().size() > 0) {
|
||||
for (AbilityModifierAction action : modifier.getOnRemoved()) {
|
||||
invokeAction(action, target, sourceEntity);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from meta modifiers
|
||||
target.getMetaModifiers().remove(head.getInstancedModifierId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleMixinCostStamina(AbilityInvokeEntry invoke) {
|
||||
// Not the right way of doing this
|
||||
if (Grasscutter.getConfig().OpenStamina) {
|
||||
// getPlayer().getStaminaManager().updateStamina(getPlayer().getSession(), -450);
|
||||
// TODO
|
||||
// set flag in stamina/movement manager that specifies the player is currently using an alternate sprint
|
||||
}
|
||||
}
|
||||
|
||||
private void handleGenerateElemBall(AbilityInvokeEntry invoke) throws InvalidProtocolBufferException {
|
||||
AbilityActionGenerateElemBall action = AbilityActionGenerateElemBall.parseFrom(invoke.getAbilityData());
|
||||
if (action == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemData itemData = GameData.getItemDataMap().get(2024);
|
||||
if (itemData == null) {
|
||||
return; // Should never happen
|
||||
}
|
||||
|
||||
EntityItem energyBall = new EntityItem(getPlayer().getScene(), getPlayer(), itemData, new Position(action.getPos()), 1);
|
||||
energyBall.getRotation().set(action.getRot());
|
||||
|
||||
getPlayer().getScene().addEntity(energyBall);
|
||||
}
|
||||
|
||||
private void invokeAction(AbilityModifierAction action, GameEntity target, GameEntity sourceEntity) {
|
||||
switch (action.type) {
|
||||
case HealHP -> {
|
||||
if (action.amount == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
float healAmount = 0;
|
||||
|
||||
if (action.amount.isDynamic && action.amount.dynamicKey != null) {
|
||||
healAmount = sourceEntity.getMetaOverrideMap().getOrDefault(action.amount.dynamicKey, 0f);
|
||||
}
|
||||
|
||||
if (healAmount > 0) {
|
||||
target.heal(healAmount);
|
||||
}
|
||||
}
|
||||
case LoseHP -> {
|
||||
if (action.amountByTargetCurrentHPRatio == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
float damageAmount = 0;
|
||||
|
||||
if (action.amount.isDynamic && action.amount.dynamicKey != null) {
|
||||
damageAmount = sourceEntity.getMetaOverrideMap().getOrDefault(action.amount.dynamicKey, 0f);
|
||||
}
|
||||
|
||||
if (damageAmount > 0) {
|
||||
target.damage(damageAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ public class Avatar {
|
||||
|
||||
@Transient private Player owner;
|
||||
@Transient private AvatarData data;
|
||||
@Transient private AvatarSkillDepotData skillDepot;
|
||||
@Transient private long guid; // Player unique id
|
||||
private int avatarId; // Id of avatar
|
||||
|
||||
@@ -103,8 +104,8 @@ public class Avatar {
|
||||
private int nameCardRewardId;
|
||||
private int nameCardId;
|
||||
|
||||
@Deprecated // Do not use. Morhpia only!
|
||||
public Avatar() {
|
||||
// Morhpia only!
|
||||
this.equips = new Int2ObjectOpenHashMap<>();
|
||||
this.fightProp = new Int2FloatOpenHashMap();
|
||||
this.extraAbilityEmbryos = new HashSet<>();
|
||||
@@ -140,7 +141,7 @@ public class Avatar {
|
||||
}
|
||||
|
||||
// Skill depot
|
||||
this.setSkillDepot(getAvatarData().getSkillDepot());
|
||||
this.setSkillDepotData(getAvatarData().getSkillDepot());
|
||||
|
||||
// Set stats
|
||||
this.recalcStats();
|
||||
@@ -164,7 +165,8 @@ public class Avatar {
|
||||
}
|
||||
|
||||
protected void setAvatarData(AvatarData data) {
|
||||
this.data = data;
|
||||
if (this.data != null) return;
|
||||
this.data = data; // Used while loading this from the database
|
||||
}
|
||||
|
||||
public int getOwnerId() {
|
||||
@@ -257,9 +259,19 @@ public class Avatar {
|
||||
return skillDepotId;
|
||||
}
|
||||
|
||||
public void setSkillDepot(AvatarSkillDepotData skillDepot) {
|
||||
// Set id
|
||||
public AvatarSkillDepotData getSkillDepot() {
|
||||
return skillDepot;
|
||||
}
|
||||
|
||||
protected void setSkillDepot(AvatarSkillDepotData skillDepot) {
|
||||
if (this.skillDepot != null) return;
|
||||
this.skillDepot = skillDepot; // Used while loading this from the database
|
||||
}
|
||||
|
||||
public void setSkillDepotData(AvatarSkillDepotData skillDepot) {
|
||||
// Set id and depot
|
||||
this.skillDepotId = skillDepot.getId();
|
||||
this.skillDepot = skillDepot;
|
||||
// Clear, then add skills
|
||||
getSkillLevelMap().clear();
|
||||
if (skillDepot.getEnergySkill() > 0) {
|
||||
@@ -501,8 +513,8 @@ public class Avatar {
|
||||
// Set energy usage
|
||||
if (data.getSkillDepot() != null && data.getSkillDepot().getEnergySkillData() != null) {
|
||||
ElementType element = data.getSkillDepot().getElementType();
|
||||
this.setFightProperty(element.getEnergyProperty(), data.getSkillDepot().getEnergySkillData().getCostElemVal());
|
||||
this.setFightProperty((element.getEnergyProperty().getId() % 70) + 1000, data.getSkillDepot().getEnergySkillData().getCostElemVal());
|
||||
this.setFightProperty(element.getMaxEnergyProp(), data.getSkillDepot().getEnergySkillData().getCostElemVal());
|
||||
this.setFightProperty((element.getMaxEnergyProp().getId() % 70) + 1000, data.getSkillDepot().getEnergySkillData().getCostElemVal());
|
||||
}
|
||||
|
||||
// Artifacts
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.util.List;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.AvatarData;
|
||||
import emu.grasscutter.data.def.AvatarSkillDepotData;
|
||||
import emu.grasscutter.database.DatabaseHelper;
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
@@ -139,12 +140,14 @@ public class AvatarStorage implements Iterable<Avatar> {
|
||||
}
|
||||
|
||||
AvatarData avatarData = GameData.getAvatarDataMap().get(avatar.getAvatarId());
|
||||
if (avatarData == null) {
|
||||
AvatarSkillDepotData skillDepot = GameData.getAvatarSkillDepotDataMap().get(avatar.getSkillDepotId());
|
||||
if (avatarData == null || skillDepot == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set ownerships
|
||||
avatar.setAvatarData(avatarData);
|
||||
avatar.setSkillDepot(skillDepot);
|
||||
avatar.setOwner(getPlayer());
|
||||
|
||||
// Force recalc of const boosted skills
|
||||
|
||||
@@ -17,17 +17,22 @@ import emu.grasscutter.net.proto.AbilityControlBlockOuterClass.AbilityControlBlo
|
||||
import emu.grasscutter.net.proto.AbilityEmbryoOuterClass.AbilityEmbryo;
|
||||
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
|
||||
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
|
||||
import emu.grasscutter.net.proto.ChangeHpReasonOuterClass.ChangeHpReason;
|
||||
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
|
||||
import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData;
|
||||
import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo;
|
||||
import emu.grasscutter.net.proto.FightPropPairOuterClass.FightPropPair;
|
||||
import emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType;
|
||||
import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason;
|
||||
import emu.grasscutter.net.proto.PropPairOuterClass.PropPair;
|
||||
import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType;
|
||||
import emu.grasscutter.net.proto.SceneAvatarInfoOuterClass.SceneAvatarInfo;
|
||||
import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo;
|
||||
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||
import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import emu.grasscutter.utils.ProtoHelper;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
@@ -110,6 +115,35 @@ public class EntityAvatar extends GameEntity {
|
||||
this.killedBy = killerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float heal(float amount) {
|
||||
float healed = super.heal(amount);
|
||||
|
||||
if (healed > 0f) {
|
||||
getScene().broadcastPacket(
|
||||
new PacketEntityFightPropChangeReasonNotify(this, FightProperty.FIGHT_PROP_CUR_HP, healed, PropChangeReason.PROP_CHANGE_ABILITY, ChangeHpReason.ChangeHpAddAbility)
|
||||
);
|
||||
}
|
||||
|
||||
return healed;
|
||||
}
|
||||
|
||||
public void addEnergy(float amount) {
|
||||
FightProperty curEnergyProp = getAvatar().getSkillDepot().getElementType().getCurEnergyProp();
|
||||
FightProperty maxEnergyProp = getAvatar().getSkillDepot().getElementType().getMaxEnergyProp();
|
||||
|
||||
float curEnergy = this.getFightProperty(curEnergyProp);
|
||||
float maxEnergy = this.getFightProperty(maxEnergyProp);
|
||||
float newEnergy = Math.min(curEnergy + amount, maxEnergy);
|
||||
|
||||
if (newEnergy != curEnergy) {
|
||||
setFightProperty(curEnergyProp, newEnergy);
|
||||
|
||||
getScene().broadcastPacket(new PacketAvatarFightPropUpdateNotify(getAvatar(), curEnergyProp));
|
||||
getScene().broadcastPacket(new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, newEnergy, PropChangeReason.PROP_CHANGE_ENERGY_BALL));
|
||||
}
|
||||
}
|
||||
|
||||
public SceneAvatarInfo getSceneAvatarInfo() {
|
||||
SceneAvatarInfo.Builder avatarInfo = SceneAvatarInfo.newBuilder()
|
||||
.setUid(this.getPlayer().getUid())
|
||||
@@ -241,5 +275,5 @@ public class EntityAvatar extends GameEntity {
|
||||
|
||||
//
|
||||
return abilityControlBlock.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package emu.grasscutter.game.entity;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.game.props.LifeState;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
@@ -9,8 +12,11 @@ import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
|
||||
import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState;
|
||||
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
public abstract class GameEntity {
|
||||
protected int id;
|
||||
@@ -25,6 +31,10 @@ public abstract class GameEntity {
|
||||
private int lastMoveSceneTimeMs;
|
||||
private int lastMoveReliableSeq;
|
||||
|
||||
// Abilities
|
||||
private Map<String, Float> metaOverrideMap;
|
||||
private Int2ObjectMap<String> metaModifiers;
|
||||
|
||||
public GameEntity(Scene scene) {
|
||||
this.scene = scene;
|
||||
this.moveState = MotionState.MOTION_NONE;
|
||||
@@ -54,6 +64,20 @@ public abstract class GameEntity {
|
||||
return isAlive() ? LifeState.LIFE_ALIVE : LifeState.LIFE_DEAD;
|
||||
}
|
||||
|
||||
public Map<String, Float> getMetaOverrideMap() {
|
||||
if (this.metaOverrideMap == null) {
|
||||
this.metaOverrideMap = new HashMap<>();
|
||||
}
|
||||
return this.metaOverrideMap;
|
||||
}
|
||||
|
||||
public Int2ObjectMap<String> getMetaModifiers() {
|
||||
if (this.metaModifiers == null) {
|
||||
this.metaModifiers = new Int2ObjectOpenHashMap<>();
|
||||
}
|
||||
return this.metaModifiers;
|
||||
}
|
||||
|
||||
public abstract Int2FloatOpenHashMap getFightProperties();
|
||||
|
||||
public abstract Position getPosition();
|
||||
@@ -146,4 +170,53 @@ public abstract class GameEntity {
|
||||
public void setSpawnEntry(SpawnDataEntry spawnEntry) {
|
||||
this.spawnEntry = spawnEntry;
|
||||
}
|
||||
|
||||
public float heal(float amount) {
|
||||
if (this.getFightProperties() == null) {
|
||||
return 0f;
|
||||
}
|
||||
|
||||
float curHp = getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
||||
float maxHp = getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||
|
||||
if (curHp >= maxHp) {
|
||||
return 0f;
|
||||
}
|
||||
|
||||
float healed = Math.min(maxHp - curHp, amount);
|
||||
this.addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, healed);
|
||||
|
||||
getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, FightProperty.FIGHT_PROP_CUR_HP));
|
||||
|
||||
return healed;
|
||||
}
|
||||
|
||||
public void damage(float amount) {
|
||||
damage(amount, 0);
|
||||
}
|
||||
|
||||
public void damage(float amount, int killerId) {
|
||||
// Sanity check
|
||||
if (getFightProperties() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Lose hp
|
||||
addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, -amount);
|
||||
|
||||
// Check if dead
|
||||
boolean isDead = false;
|
||||
if (getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) <= 0f) {
|
||||
setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 0f);
|
||||
isDead = true;
|
||||
}
|
||||
|
||||
// Packets
|
||||
this.getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, FightProperty.FIGHT_PROP_CUR_HP));
|
||||
|
||||
// Check if dead
|
||||
if (isDead) {
|
||||
getScene().killEntity(this, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,6 +172,9 @@ public class Inventory implements Iterable<GameItem> {
|
||||
// Handle
|
||||
this.addVirtualItem(item.getItemId(), item.getCount());
|
||||
return item;
|
||||
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_ADSORBATE) {
|
||||
player.getTeamManager().addEnergyToTeam(item);
|
||||
return null;
|
||||
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_AVATAR) {
|
||||
// Get avatar id
|
||||
int avatarId = (item.getItemId() % 1000) + 10000000;
|
||||
|
||||
@@ -30,7 +30,7 @@ public class InvokeHandler<T> {
|
||||
}
|
||||
|
||||
public synchronized void update(Player player) {
|
||||
if (player.getWorld() == null) {
|
||||
if (player.getWorld() == null || player.getScene() == null) {
|
||||
this.entryListForwardAll.clear();
|
||||
this.entryListForwardAllExceptCur.clear();
|
||||
this.entryListForwardHost.clear();
|
||||
|
||||
@@ -8,6 +8,7 @@ import emu.grasscutter.data.def.PlayerLevelData;
|
||||
import emu.grasscutter.database.DatabaseHelper;
|
||||
import emu.grasscutter.game.Account;
|
||||
import emu.grasscutter.game.CoopRequest;
|
||||
import emu.grasscutter.game.ability.AbilityManager;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.avatar.AvatarProfileData;
|
||||
import emu.grasscutter.game.avatar.AvatarStorage;
|
||||
@@ -89,7 +90,8 @@ public class Player {
|
||||
@Transient private FriendsList friendsList;
|
||||
@Transient private MailHandler mailHandler;
|
||||
@Transient private MessageHandler messageHandler;
|
||||
|
||||
@Transient private AbilityManager abilityManager;
|
||||
|
||||
@Transient private SotSManager sotsManager;
|
||||
|
||||
private TeamManager teamManager;
|
||||
@@ -142,6 +144,7 @@ public class Player {
|
||||
this.friendsList = new FriendsList(this);
|
||||
this.mailHandler = new MailHandler(this);
|
||||
this.towerManager = new TowerManager(this);
|
||||
this.abilityManager = new AbilityManager(this);
|
||||
this.pos = new Position();
|
||||
this.rotation = new Position();
|
||||
this.properties = new HashMap<>();
|
||||
@@ -1025,6 +1028,10 @@ public class Player {
|
||||
|
||||
public SotSManager getSotSManager() { return sotsManager; }
|
||||
|
||||
public AbilityManager getAbilityManager() {
|
||||
return abilityManager;
|
||||
}
|
||||
|
||||
public synchronized void onTick() {
|
||||
// Check ping
|
||||
if (this.getLastPingTime() > System.currentTimeMillis() + 60000) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import emu.grasscutter.data.def.AvatarSkillDepotData;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.game.entity.EntityBaseGadget;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.props.ElementType;
|
||||
import emu.grasscutter.game.props.EnterReason;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
@@ -579,6 +580,24 @@ public class TeamManager {
|
||||
// Packets
|
||||
getPlayer().sendPacket(new BasePacket(PacketOpcodes.WorldPlayerReviveRsp));
|
||||
}
|
||||
|
||||
public synchronized void addEnergyToTeam(GameItem energyBall) {
|
||||
// TODO
|
||||
float baseEnergy = 2;
|
||||
|
||||
for (int i = 0; i < getActiveTeam().size(); i++) {
|
||||
EntityAvatar entity = getActiveTeam().get(i);
|
||||
|
||||
float energyGain = baseEnergy;
|
||||
|
||||
// Active character gets full hp
|
||||
if (getCurrentCharacterIndex() != i) {
|
||||
energyGain *= Math.max(1.0 - (getActiveTeam().size() * .1f), .6f);
|
||||
}
|
||||
|
||||
entity.addEnergy(energyGain);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveAvatars() {
|
||||
// Save all avatars from active team
|
||||
|
||||
@@ -9,21 +9,22 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
public enum ElementType {
|
||||
None (0, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY),
|
||||
Fire (1, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY, 10101, "TeamResonance_Fire_Lv2"),
|
||||
Water (2, FightProperty.FIGHT_PROP_MAX_WATER_ENERGY, 10201, "TeamResonance_Water_Lv2"),
|
||||
Grass (3, FightProperty.FIGHT_PROP_MAX_GRASS_ENERGY),
|
||||
Electric (4, FightProperty.FIGHT_PROP_MAX_ELEC_ENERGY, 10401, "TeamResonance_Electric_Lv2"),
|
||||
Ice (5, FightProperty.FIGHT_PROP_MAX_ICE_ENERGY, 10601, "TeamResonance_Ice_Lv2"),
|
||||
Frozen (6, FightProperty.FIGHT_PROP_MAX_ICE_ENERGY),
|
||||
Wind (7, FightProperty.FIGHT_PROP_MAX_WIND_ENERGY, 10301, "TeamResonance_Wind_Lv2"),
|
||||
Rock (8, FightProperty.FIGHT_PROP_MAX_ROCK_ENERGY, 10701, "TeamResonance_Rock_Lv2"),
|
||||
AntiFire (9, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY),
|
||||
Default (255, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY, 10801, "TeamResonance_AllDifferent");
|
||||
None (0, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY),
|
||||
Fire (1, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY, 10101, "TeamResonance_Fire_Lv2"),
|
||||
Water (2, FightProperty.FIGHT_PROP_CUR_WATER_ENERGY, FightProperty.FIGHT_PROP_MAX_WATER_ENERGY, 10201, "TeamResonance_Water_Lv2"),
|
||||
Grass (3, FightProperty.FIGHT_PROP_CUR_GRASS_ENERGY, FightProperty.FIGHT_PROP_MAX_GRASS_ENERGY),
|
||||
Electric (4, FightProperty.FIGHT_PROP_CUR_ELEC_ENERGY, FightProperty.FIGHT_PROP_MAX_ELEC_ENERGY, 10401, "TeamResonance_Electric_Lv2"),
|
||||
Ice (5, FightProperty.FIGHT_PROP_CUR_ICE_ENERGY, FightProperty.FIGHT_PROP_MAX_ICE_ENERGY, 10601, "TeamResonance_Ice_Lv2"),
|
||||
Frozen (6, FightProperty.FIGHT_PROP_CUR_ICE_ENERGY, FightProperty.FIGHT_PROP_MAX_ICE_ENERGY),
|
||||
Wind (7, FightProperty.FIGHT_PROP_CUR_WIND_ENERGY, FightProperty.FIGHT_PROP_MAX_WIND_ENERGY, 10301, "TeamResonance_Wind_Lv2"),
|
||||
Rock (8, FightProperty.FIGHT_PROP_CUR_ROCK_ENERGY, FightProperty.FIGHT_PROP_MAX_ROCK_ENERGY, 10701, "TeamResonance_Rock_Lv2"),
|
||||
AntiFire (9, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY),
|
||||
Default (255, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY, 10801, "TeamResonance_AllDifferent");
|
||||
|
||||
private final int value;
|
||||
private final int teamResonanceId;
|
||||
private final FightProperty energyProperty;
|
||||
private final FightProperty curEnergyProp;
|
||||
private final FightProperty maxEnergyProp;
|
||||
private final int configHash;
|
||||
private static final Int2ObjectMap<ElementType> map = new Int2ObjectOpenHashMap<>();
|
||||
private static final Map<String, ElementType> stringMap = new HashMap<>();
|
||||
@@ -35,13 +36,14 @@ public enum ElementType {
|
||||
});
|
||||
}
|
||||
|
||||
private ElementType(int value, FightProperty energyProperty) {
|
||||
this(value, energyProperty, 0, null);
|
||||
private ElementType(int value, FightProperty curEnergyProp, FightProperty maxEnergyProp) {
|
||||
this(value, curEnergyProp, maxEnergyProp, 0, null);
|
||||
}
|
||||
|
||||
private ElementType(int value, FightProperty energyProperty, int teamResonanceId, String configName) {
|
||||
private ElementType(int value, FightProperty curEnergyProp, FightProperty maxEnergyProp, int teamResonanceId, String configName) {
|
||||
this.value = value;
|
||||
this.energyProperty = energyProperty;
|
||||
this.curEnergyProp = curEnergyProp;
|
||||
this.maxEnergyProp = maxEnergyProp;
|
||||
this.teamResonanceId = teamResonanceId;
|
||||
if (configName != null) {
|
||||
this.configHash = Utils.abilityHash(configName);
|
||||
@@ -54,8 +56,12 @@ public enum ElementType {
|
||||
return value;
|
||||
}
|
||||
|
||||
public FightProperty getEnergyProperty() {
|
||||
return energyProperty;
|
||||
public FightProperty getCurEnergyProp() {
|
||||
return curEnergyProp;
|
||||
}
|
||||
|
||||
public FightProperty getMaxEnergyProp() {
|
||||
return maxEnergyProp;
|
||||
}
|
||||
|
||||
public int getTeamResonanceId() {
|
||||
|
||||
@@ -385,27 +385,7 @@ public class Scene {
|
||||
}
|
||||
|
||||
// Sanity check
|
||||
if (target.getFightProperties() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Lose hp
|
||||
target.addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, -result.getDamage());
|
||||
|
||||
// Check if dead
|
||||
boolean isDead = false;
|
||||
if (target.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) <= 0f) {
|
||||
target.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 0f);
|
||||
isDead = true;
|
||||
}
|
||||
|
||||
// Packets
|
||||
this.broadcastPacket(new PacketEntityFightPropUpdateNotify(target, FightProperty.FIGHT_PROP_CUR_HP));
|
||||
|
||||
// Check if dead
|
||||
if (isDead) {
|
||||
this.killEntity(target, result.getAttackerId());
|
||||
}
|
||||
target.damage(result.getDamage(), result.getAttackerId());
|
||||
}
|
||||
|
||||
public void killEntity(GameEntity target, int attackerId) {
|
||||
|
||||
Reference in New Issue
Block a user