mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-12-16 00:44:46 +01:00
Merge branch 'development' into more-events
# Conflicts: # src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java # src/main/java/emu/grasscutter/game/entity/EntityAvatar.java # src/main/java/emu/grasscutter/game/entity/GameEntity.java # src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java
This commit is contained in:
@@ -30,7 +30,6 @@ 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.event.player.PlayerMoveEvent;
|
||||
import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
||||
@@ -64,13 +63,13 @@ public class EntityAvatar extends GameEntity {
|
||||
this.avatar.setCurrentEnergy();
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return avatar.getPlayer();
|
||||
}
|
||||
public Player getPlayer() {
|
||||
return avatar.getPlayer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return getPlayer().getPos();
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return getPlayer().getPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -107,12 +106,12 @@ public class EntityAvatar extends GameEntity {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeath(int killerId) {
|
||||
this.killedType = PlayerDieType.PLAYER_DIE_TYPE_KILL_BY_MONSTER;
|
||||
this.killedBy = killerId;
|
||||
clearEnergy(ChangeEnergyReason.CHANGE_ENERGY_REASON_NONE);
|
||||
}
|
||||
@Override
|
||||
public void onDeath(int killerId) {
|
||||
this.killedType = PlayerDieType.PLAYER_DIE_TYPE_KILL_BY_MONSTER;
|
||||
this.killedBy = killerId;
|
||||
clearEnergy(ChangeEnergyReason.CHANGE_ENERGY_REASON_NONE);
|
||||
}
|
||||
|
||||
public void onDeath(PlayerDieType dieType, int killerId) {
|
||||
this.killedType = dieType;
|
||||
@@ -126,7 +125,7 @@ public class EntityAvatar extends GameEntity {
|
||||
|
||||
if (healed > 0f) {
|
||||
getScene().broadcastPacket(
|
||||
new PacketEntityFightPropChangeReasonNotify(this, FightProperty.FIGHT_PROP_CUR_HP, healed, PropChangeReason.PROP_CHANGE_REASON_ABILITY, ChangeHpReason.CHANGE_HP_REASON_CHANGE_HP_ADD_ABILITY)
|
||||
new PacketEntityFightPropChangeReasonNotify(this, FightProperty.FIGHT_PROP_CUR_HP, healed, PropChangeReason.PROP_CHANGE_REASON_ABILITY, ChangeHpReason.CHANGE_HP_REASON_ADD_ABILITY)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -138,14 +137,14 @@ public class EntityAvatar extends GameEntity {
|
||||
FightProperty curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp();
|
||||
FightProperty maxEnergyProp = this.getAvatar().getSkillDepot().getElementType().getMaxEnergyProp();
|
||||
|
||||
// Get max energy.
|
||||
float maxEnergy = this.avatar.getFightProperty(maxEnergyProp);
|
||||
// Get max energy.
|
||||
float maxEnergy = this.avatar.getFightProperty(maxEnergyProp);
|
||||
|
||||
// Set energy to zero.
|
||||
this.avatar.setCurrentEnergy(curEnergyProp, 0);
|
||||
// Set energy to zero.
|
||||
this.avatar.setCurrentEnergy(curEnergyProp, 0);
|
||||
|
||||
// Send packets.
|
||||
this.getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, curEnergyProp));
|
||||
// Send packets.
|
||||
this.getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, curEnergyProp));
|
||||
|
||||
if (reason == ChangeEnergyReason.CHANGE_ENERGY_REASON_SKILL_START) {
|
||||
this.getScene().broadcastPacket(new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, -maxEnergy, reason));
|
||||
@@ -166,10 +165,10 @@ public class EntityAvatar extends GameEntity {
|
||||
// Get energy recharge.
|
||||
float energyRecharge = this.getFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY);
|
||||
|
||||
// Scale amount by energy recharge, if the amount is not flat.
|
||||
if (!isFlat) {
|
||||
amount *= energyRecharge;
|
||||
}
|
||||
// Scale amount by energy recharge, if the amount is not flat.
|
||||
if (!isFlat) {
|
||||
amount *= energyRecharge;
|
||||
}
|
||||
|
||||
// Determine the new energy value.
|
||||
float newEnergy = Math.min(curEnergy + amount, maxEnergy);
|
||||
|
||||
@@ -3,6 +3,7 @@ package emu.grasscutter.game.entity;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.GadgetData;
|
||||
import emu.grasscutter.game.entity.gadget.*;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.EntityIdType;
|
||||
import emu.grasscutter.game.props.EntityType;
|
||||
import emu.grasscutter.game.props.LifeState;
|
||||
@@ -15,6 +16,7 @@ import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityIn
|
||||
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.GadgetInteractReqOuterClass.GadgetInteractReq;
|
||||
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
|
||||
import emu.grasscutter.net.proto.PropPairOuterClass.PropPair;
|
||||
import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType;
|
||||
@@ -22,6 +24,7 @@ import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo;
|
||||
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
||||
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
|
||||
import emu.grasscutter.scripts.constants.EventType;
|
||||
import emu.grasscutter.scripts.data.SceneGadget;
|
||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||
@@ -35,186 +38,195 @@ import lombok.ToString;
|
||||
|
||||
@ToString(callSuper = true)
|
||||
public class EntityGadget extends EntityBaseGadget {
|
||||
private final GadgetData data;
|
||||
private final Position pos;
|
||||
private final Position rot;
|
||||
private int gadgetId;
|
||||
private final GadgetData data;
|
||||
private final Position pos;
|
||||
private final Position rot;
|
||||
private int gadgetId;
|
||||
|
||||
private int state;
|
||||
private int pointType;
|
||||
private GadgetContent content;
|
||||
private Int2FloatOpenHashMap fightProp;
|
||||
private SceneGadget metaGadget;
|
||||
private int state;
|
||||
private int pointType;
|
||||
private GadgetContent content;
|
||||
private Int2FloatOpenHashMap fightProp;
|
||||
private SceneGadget metaGadget;
|
||||
|
||||
public EntityGadget(Scene scene, int gadgetId, Position pos, Position rot) {
|
||||
super(scene);
|
||||
this.data = GameData.getGadgetDataMap().get(gadgetId);
|
||||
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
||||
this.gadgetId = gadgetId;
|
||||
this.pos = pos.clone();
|
||||
this.rot = rot != null ? rot.clone() : new Position();
|
||||
}
|
||||
public EntityGadget(Scene scene, int gadgetId, Position pos, Position rot) {
|
||||
super(scene);
|
||||
this.data = GameData.getGadgetDataMap().get(gadgetId);
|
||||
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
||||
this.gadgetId = gadgetId;
|
||||
this.pos = pos.clone();
|
||||
this.rot = rot != null ? rot.clone() : new Position();
|
||||
}
|
||||
|
||||
public EntityGadget(Scene scene, int gadgetId, Position pos) {
|
||||
this(scene, gadgetId, pos, new Position());
|
||||
}
|
||||
public EntityGadget(Scene scene, int gadgetId, Position pos) {
|
||||
this(scene, gadgetId, pos, new Position());
|
||||
}
|
||||
|
||||
public EntityGadget(Scene scene, int gadgetId, Position pos, Position rot, GadgetContent content) {
|
||||
this(scene, gadgetId, pos, rot);
|
||||
this.content = content;
|
||||
}
|
||||
public EntityGadget(Scene scene, int gadgetId, Position pos, Position rot, GadgetContent content) {
|
||||
this(scene, gadgetId, pos, rot);
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public GadgetData getGadgetData() {
|
||||
return data;
|
||||
}
|
||||
public GadgetData getGadgetData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return this.pos;
|
||||
}
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return this.pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getRotation() {
|
||||
return this.rot;
|
||||
}
|
||||
@Override
|
||||
public Position getRotation() {
|
||||
return this.rot;
|
||||
}
|
||||
|
||||
public int getGadgetId() {
|
||||
return gadgetId;
|
||||
}
|
||||
public int getGadgetId() {
|
||||
return gadgetId;
|
||||
}
|
||||
|
||||
public void setGadgetId(int gadgetId) {
|
||||
this.gadgetId = gadgetId;
|
||||
}
|
||||
public void setGadgetId(int gadgetId) {
|
||||
this.gadgetId = gadgetId;
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return state;
|
||||
}
|
||||
public int getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(int state) {
|
||||
this.state = state;
|
||||
}
|
||||
public void setState(int state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public void updateState(int state){
|
||||
this.setState(state);
|
||||
this.getScene().broadcastPacket(new PacketGadgetStateNotify(this, state));
|
||||
getScene().getScriptManager().callEvent(EventType.EVENT_GADGET_STATE_CHANGE, new ScriptArgs(state, this.getConfigId()));
|
||||
}
|
||||
public void updateState(int state) {
|
||||
this.setState(state);
|
||||
this.getScene().broadcastPacket(new PacketGadgetStateNotify(this, state));
|
||||
getScene().getScriptManager().callEvent(EventType.EVENT_GADGET_STATE_CHANGE, new ScriptArgs(state, this.getConfigId()));
|
||||
}
|
||||
|
||||
public int getPointType() {
|
||||
return pointType;
|
||||
}
|
||||
public int getPointType() {
|
||||
return pointType;
|
||||
}
|
||||
|
||||
public void setPointType(int pointType) {
|
||||
this.pointType = pointType;
|
||||
}
|
||||
public void setPointType(int pointType) {
|
||||
this.pointType = pointType;
|
||||
}
|
||||
|
||||
public GadgetContent getContent() {
|
||||
return content;
|
||||
}
|
||||
public GadgetContent getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
@Deprecated // Dont use!
|
||||
public void setContent(GadgetContent content) {
|
||||
this.content = this.content == null ? content : this.content;
|
||||
}
|
||||
@Deprecated // Dont use!
|
||||
public void setContent(GadgetContent content) {
|
||||
this.content = this.content == null ? content : this.content;
|
||||
}
|
||||
|
||||
public SceneGadget getMetaGadget() {
|
||||
return metaGadget;
|
||||
}
|
||||
public SceneGadget getMetaGadget() {
|
||||
return metaGadget;
|
||||
}
|
||||
|
||||
public void setMetaGadget(SceneGadget metaGadget) {
|
||||
this.metaGadget = metaGadget;
|
||||
}
|
||||
public void setMetaGadget(SceneGadget metaGadget) {
|
||||
this.metaGadget = metaGadget;
|
||||
}
|
||||
|
||||
// TODO refactor
|
||||
public void buildContent() {
|
||||
if (getContent() != null || getGadgetData() == null || getGadgetData().getType() == null) {
|
||||
return;
|
||||
}
|
||||
// TODO refactor
|
||||
public void buildContent() {
|
||||
if (getContent() != null || getGadgetData() == null || getGadgetData().getType() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
EntityType type = getGadgetData().getType();
|
||||
GadgetContent content = switch (type) {
|
||||
case GatherPoint -> new GadgetGatherPoint(this);
|
||||
case GatherObject -> new GadgetGatherObject(this);
|
||||
case Worktop -> new GadgetWorktop(this);
|
||||
case RewardStatue -> new GadgetRewardStatue(this);
|
||||
case Chest -> new GadgetChest(this);
|
||||
EntityType type = getGadgetData().getType();
|
||||
GadgetContent content = switch (type) {
|
||||
case GatherPoint -> new GadgetGatherPoint(this);
|
||||
case GatherObject -> new GadgetGatherObject(this);
|
||||
case Worktop -> new GadgetWorktop(this);
|
||||
case RewardStatue -> new GadgetRewardStatue(this);
|
||||
case Chest -> new GadgetChest(this);
|
||||
case Gadget -> new GadgetObject(this);
|
||||
default -> null;
|
||||
};
|
||||
default -> null;
|
||||
};
|
||||
|
||||
this.content = content;
|
||||
}
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Int2FloatOpenHashMap getFightProperties() {
|
||||
if (this.fightProp == null) this.fightProp = new Int2FloatOpenHashMap();
|
||||
return this.fightProp;
|
||||
}
|
||||
@Override
|
||||
public Int2FloatOpenHashMap getFightProperties() {
|
||||
if (this.fightProp == null) this.fightProp = new Int2FloatOpenHashMap();
|
||||
return this.fightProp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
// Lua event
|
||||
getScene().getScriptManager().callEvent(EventType.EVENT_GADGET_CREATE, new ScriptArgs(this.getConfigId()));
|
||||
}
|
||||
@Override
|
||||
public void onInteract(Player player, GadgetInteractReq interactReq) {
|
||||
if (this.getContent() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeath(int killerId) {
|
||||
if (this.getSpawnEntry() != null) {
|
||||
this.getScene().getDeadSpawnedEntities().add(getSpawnEntry());
|
||||
}
|
||||
if (getScene().getChallenge() != null) {
|
||||
getScene().getChallenge().onGadgetDeath(this);
|
||||
}
|
||||
getScene().getScriptManager().callEvent(EventType.EVENT_ANY_GADGET_DIE, new ScriptArgs(this.getConfigId()));
|
||||
}
|
||||
boolean shouldDelete = this.getContent().onInteract(player, interactReq);
|
||||
|
||||
@Override
|
||||
public SceneEntityInfo toProto() {
|
||||
EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder()
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder()))
|
||||
.setBornPos(Vector.newBuilder())
|
||||
.build();
|
||||
if (shouldDelete) {
|
||||
this.getScene().killEntity(this);
|
||||
}
|
||||
}
|
||||
|
||||
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder()
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
||||
.setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder()))
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setEntityClientData(EntityClientData.newBuilder())
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLifeState(1);
|
||||
@Override
|
||||
public void onCreate() {
|
||||
// Lua event
|
||||
getScene().getScriptManager().callEvent(EventType.EVENT_GADGET_CREATE, new ScriptArgs(this.getConfigId()));
|
||||
}
|
||||
|
||||
PropPair pair = PropPair.newBuilder()
|
||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1))
|
||||
.build();
|
||||
entityInfo.addPropList(pair);
|
||||
@Override
|
||||
public void onDeath(int killerId) {
|
||||
if (this.getSpawnEntry() != null) {
|
||||
this.getScene().getDeadSpawnedEntities().add(getSpawnEntry());
|
||||
}
|
||||
if (getScene().getChallenge() != null) {
|
||||
getScene().getChallenge().onGadgetDeath(this);
|
||||
}
|
||||
getScene().getScriptManager().callEvent(EventType.EVENT_ANY_GADGET_DIE, new ScriptArgs(this.getConfigId()));
|
||||
}
|
||||
|
||||
// We do not use the getter to null check because the getter will create a fight prop map if it is null
|
||||
if (this.fightProp != null) {
|
||||
this.addAllFightPropsToEntityInfo(entityInfo);
|
||||
}
|
||||
@Override
|
||||
public SceneEntityInfo toProto() {
|
||||
EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder()
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder()))
|
||||
.setBornPos(Vector.newBuilder())
|
||||
.build();
|
||||
|
||||
SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder()
|
||||
.setGadgetId(this.getGadgetId())
|
||||
.setGroupId(this.getGroupId())
|
||||
.setConfigId(this.getConfigId())
|
||||
.setGadgetState(this.getState())
|
||||
.setIsEnableInteract(true)
|
||||
.setAuthorityPeerId(this.getScene().getWorld().getHostPeerId());
|
||||
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder()
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
||||
.setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder()))
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setEntityClientData(EntityClientData.newBuilder())
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLifeState(1);
|
||||
|
||||
if (this.getContent() != null) {
|
||||
this.getContent().onBuildProto(gadgetInfo);
|
||||
}
|
||||
PropPair pair = PropPair.newBuilder()
|
||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1))
|
||||
.build();
|
||||
entityInfo.addPropList(pair);
|
||||
|
||||
entityInfo.setGadget(gadgetInfo);
|
||||
// We do not use the getter to null check because the getter will create a fight prop map if it is null
|
||||
if (this.fightProp != null) {
|
||||
this.addAllFightPropsToEntityInfo(entityInfo);
|
||||
}
|
||||
|
||||
return entityInfo.build();
|
||||
}
|
||||
public void die() {
|
||||
getScene().broadcastPacket(new PacketLifeStateChangeNotify(this, LifeState.LIFE_DEAD));
|
||||
this.onDeath(0);
|
||||
}
|
||||
SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder()
|
||||
.setGadgetId(this.getGadgetId())
|
||||
.setGroupId(this.getGroupId())
|
||||
.setConfigId(this.getConfigId())
|
||||
.setGadgetState(this.getState())
|
||||
.setIsEnableInteract(true)
|
||||
.setAuthorityPeerId(this.getScene().getWorld().getHostPeerId());
|
||||
|
||||
if (this.getContent() != null) {
|
||||
this.getContent().onBuildProto(gadgetInfo);
|
||||
}
|
||||
|
||||
entityInfo.setGadget(gadgetInfo);
|
||||
|
||||
return entityInfo.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package emu.grasscutter.game.entity;
|
||||
import emu.grasscutter.data.excels.ItemData;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.game.props.EntityIdType;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
@@ -12,6 +13,8 @@ import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityIn
|
||||
import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData;
|
||||
import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo;
|
||||
import emu.grasscutter.net.proto.GadgetBornTypeOuterClass.GadgetBornType;
|
||||
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
||||
import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType;
|
||||
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
|
||||
import emu.grasscutter.net.proto.PropPairOuterClass.PropPair;
|
||||
import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType;
|
||||
@@ -19,120 +22,145 @@ import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo;
|
||||
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
||||
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import emu.grasscutter.utils.ProtoHelper;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||
|
||||
public class EntityItem extends EntityBaseGadget {
|
||||
private final Position pos;
|
||||
private final Position rot;
|
||||
|
||||
private final GameItem item;
|
||||
private final long guid;
|
||||
private final Position pos;
|
||||
private final Position rot;
|
||||
|
||||
private final boolean share;
|
||||
private final GameItem item;
|
||||
private final long guid;
|
||||
|
||||
public EntityItem(Scene scene, Player player, ItemData itemData, Position pos, int count) {
|
||||
super(scene);
|
||||
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
||||
this.pos = new Position(pos);
|
||||
this.rot = new Position();
|
||||
this.guid = player == null ? scene.getWorld().getHost().getNextGameGuid() : player.getNextGameGuid();
|
||||
this.item = new GameItem(itemData, count);
|
||||
this.share = true;
|
||||
}
|
||||
private final boolean share;
|
||||
|
||||
// In official game, some drop items are shared to all players, and some other items are independent to all players
|
||||
// For example, if you killed a monster in MP mode, all players could get drops but rarity and number of them are different
|
||||
// but if you broke regional mine, when someone picked up the drop then it disappeared
|
||||
public EntityItem(Scene scene, Player player, ItemData itemData, Position pos, int count, boolean share) {
|
||||
super(scene);
|
||||
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
||||
this.pos = new Position(pos);
|
||||
this.rot = new Position();
|
||||
this.guid = player == null ? scene.getWorld().getHost().getNextGameGuid() : player.getNextGameGuid();
|
||||
this.item = new GameItem(itemData, count);
|
||||
this.share = share;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
private GameItem getItem() {
|
||||
return this.item;
|
||||
}
|
||||
public EntityItem(Scene scene, Player player, ItemData itemData, Position pos, int count) {
|
||||
super(scene);
|
||||
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
||||
this.pos = new Position(pos);
|
||||
this.rot = new Position();
|
||||
this.guid = player == null ? scene.getWorld().getHost().getNextGameGuid() : player.getNextGameGuid();
|
||||
this.item = new GameItem(itemData, count);
|
||||
this.share = true;
|
||||
}
|
||||
|
||||
public ItemData getItemData() {
|
||||
return this.getItem().getItemData();
|
||||
}
|
||||
// In official game, some drop items are shared to all players, and some other items are independent to all players
|
||||
// For example, if you killed a monster in MP mode, all players could get drops but rarity and number of them are different
|
||||
// but if you broke regional mine, when someone picked up the drop then it disappeared
|
||||
public EntityItem(Scene scene, Player player, ItemData itemData, Position pos, int count, boolean share) {
|
||||
super(scene);
|
||||
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
||||
this.pos = new Position(pos);
|
||||
this.rot = new Position();
|
||||
this.guid = player == null ? scene.getWorld().getHost().getNextGameGuid() : player.getNextGameGuid();
|
||||
this.item = new GameItem(itemData, count);
|
||||
this.share = share;
|
||||
}
|
||||
|
||||
public long getGuid() {
|
||||
return guid;
|
||||
}
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return this.getItem().getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGadgetId() {
|
||||
return this.getItemData().getGadgetId();
|
||||
}
|
||||
private GameItem getItem() {
|
||||
return this.item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return this.pos;
|
||||
}
|
||||
public ItemData getItemData() {
|
||||
return this.getItem().getItemData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getRotation() {
|
||||
return this.rot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Int2FloatOpenHashMap getFightProperties() {
|
||||
return null;
|
||||
}
|
||||
public long getGuid() {
|
||||
return guid;
|
||||
}
|
||||
|
||||
public boolean isShare() {
|
||||
return share;
|
||||
}
|
||||
public int getCount() {
|
||||
return this.getItem().getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SceneEntityInfo toProto() {
|
||||
EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder()
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder()))
|
||||
.setBornPos(Vector.newBuilder())
|
||||
.build();
|
||||
|
||||
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder()
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
||||
.setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder()))
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setEntityClientData(EntityClientData.newBuilder())
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLifeState(1);
|
||||
|
||||
PropPair pair = PropPair.newBuilder()
|
||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1))
|
||||
.build();
|
||||
entityInfo.addPropList(pair);
|
||||
|
||||
SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder()
|
||||
.setGadgetId(this.getItemData().getGadgetId())
|
||||
.setTrifleItem(this.getItem().toProto())
|
||||
.setBornType(GadgetBornType.GADGET_BORN_TYPE_IN_AIR)
|
||||
.setAuthorityPeerId(this.getWorld().getHostPeerId())
|
||||
.setIsEnableInteract(true);
|
||||
@Override
|
||||
public int getGadgetId() {
|
||||
return this.getItemData().getGadgetId();
|
||||
}
|
||||
|
||||
entityInfo.setGadget(gadgetInfo);
|
||||
|
||||
return entityInfo.build();
|
||||
}
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return this.pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getRotation() {
|
||||
return this.rot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Int2FloatOpenHashMap getFightProperties() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isShare() {
|
||||
return share;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInteract(Player player, GadgetInteractReq interactReq) {
|
||||
// check drop owner to avoid someone picked up item in others' world
|
||||
if (!this.isShare()) {
|
||||
int dropOwner = (int) (this.getGuid() >> 32);
|
||||
if (dropOwner != player.getUid()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.getScene().removeEntity(this);
|
||||
GameItem item = new GameItem(this.getItemData(), this.getCount());
|
||||
|
||||
// Add to inventory
|
||||
boolean success = player.getInventory().addItem(item, ActionReason.SubfieldDrop);
|
||||
if (success) {
|
||||
if (!this.isShare()) { // not shared drop
|
||||
player.sendPacket(new PacketGadgetInteractRsp(this, InteractType.INTERACT_TYPE_PICK_ITEM));
|
||||
} else {
|
||||
this.getScene().broadcastPacket(new PacketGadgetInteractRsp(this, InteractType.INTERACT_TYPE_PICK_ITEM));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SceneEntityInfo toProto() {
|
||||
EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder()
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder()))
|
||||
.setBornPos(Vector.newBuilder())
|
||||
.build();
|
||||
|
||||
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder()
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
||||
.setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder()))
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setEntityClientData(EntityClientData.newBuilder())
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLifeState(1);
|
||||
|
||||
PropPair pair = PropPair.newBuilder()
|
||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1))
|
||||
.build();
|
||||
entityInfo.addPropList(pair);
|
||||
|
||||
SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder()
|
||||
.setGadgetId(this.getItemData().getGadgetId())
|
||||
.setTrifleItem(this.getItem().toProto())
|
||||
.setBornType(GadgetBornType.GADGET_BORN_TYPE_IN_AIR)
|
||||
.setAuthorityPeerId(this.getWorld().getHostPeerId())
|
||||
.setIsEnableInteract(true);
|
||||
|
||||
entityInfo.setGadget(gadgetInfo);
|
||||
|
||||
return entityInfo.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,29 @@
|
||||
package emu.grasscutter.game.entity;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
import emu.grasscutter.data.common.PropGrowCurve;
|
||||
import emu.grasscutter.data.excels.EnvAnimalGatherConfigData;
|
||||
import emu.grasscutter.data.excels.ItemData;
|
||||
import emu.grasscutter.data.excels.MonsterCurveData;
|
||||
import emu.grasscutter.data.excels.MonsterData;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
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.VisionTypeOuterClass;
|
||||
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
|
||||
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
|
||||
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.GadgetInteractReqOuterClass.GadgetInteractReq;
|
||||
import emu.grasscutter.net.proto.MonsterBornTypeOuterClass.MonsterBornType;
|
||||
import emu.grasscutter.net.proto.PropPairOuterClass.PropPair;
|
||||
import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType;
|
||||
@@ -31,244 +39,257 @@ import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||
|
||||
public class EntityMonster extends GameEntity {
|
||||
private final MonsterData monsterData;
|
||||
private final Int2FloatOpenHashMap fightProp;
|
||||
|
||||
private final Position pos;
|
||||
private final Position rot;
|
||||
private final Position bornPos;
|
||||
private final int level;
|
||||
private int weaponEntityId;
|
||||
private int poseId;
|
||||
|
||||
public EntityMonster(Scene scene, MonsterData monsterData, Position pos, int level) {
|
||||
super(scene);
|
||||
this.id = getWorld().getNextEntityId(EntityIdType.MONSTER);
|
||||
this.monsterData = monsterData;
|
||||
this.fightProp = new Int2FloatOpenHashMap();
|
||||
this.pos = new Position(pos);
|
||||
this.rot = new Position();
|
||||
this.bornPos = getPosition().clone();
|
||||
this.level = level;
|
||||
|
||||
// Monster weapon
|
||||
if (getMonsterWeaponId() > 0) {
|
||||
this.weaponEntityId = getWorld().getNextEntityId(EntityIdType.WEAPON);
|
||||
}
|
||||
|
||||
this.recalcStats();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
private final MonsterData monsterData;
|
||||
private final Int2FloatOpenHashMap fightProp;
|
||||
|
||||
public MonsterData getMonsterData() {
|
||||
return monsterData;
|
||||
}
|
||||
|
||||
public int getMonsterWeaponId() {
|
||||
return getMonsterData().getWeaponId();
|
||||
}
|
||||
|
||||
private int getMonsterId() {
|
||||
return this.getMonsterData().getId();
|
||||
}
|
||||
private final Position pos;
|
||||
private final Position rot;
|
||||
private final Position bornPos;
|
||||
private final int level;
|
||||
private int weaponEntityId;
|
||||
private int poseId;
|
||||
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
public EntityMonster(Scene scene, MonsterData monsterData, Position pos, int level) {
|
||||
super(scene);
|
||||
this.id = getWorld().getNextEntityId(EntityIdType.MONSTER);
|
||||
this.monsterData = monsterData;
|
||||
this.fightProp = new Int2FloatOpenHashMap();
|
||||
this.pos = new Position(pos);
|
||||
this.rot = new Position();
|
||||
this.bornPos = getPosition().clone();
|
||||
this.level = level;
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return this.pos;
|
||||
}
|
||||
// Monster weapon
|
||||
if (getMonsterWeaponId() > 0) {
|
||||
this.weaponEntityId = getWorld().getNextEntityId(EntityIdType.WEAPON);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getRotation() {
|
||||
return this.rot;
|
||||
}
|
||||
|
||||
public Position getBornPos() {
|
||||
return bornPos;
|
||||
}
|
||||
this.recalcStats();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Int2FloatOpenHashMap getFightProperties() {
|
||||
return fightProp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAlive() {
|
||||
return this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) > 0f;
|
||||
}
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public int getPoseId() {
|
||||
return poseId;
|
||||
}
|
||||
public MonsterData getMonsterData() {
|
||||
return monsterData;
|
||||
}
|
||||
|
||||
public void setPoseId(int poseId) {
|
||||
this.poseId = poseId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
// Lua event
|
||||
getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_LIVE, new ScriptArgs(this.getConfigId()));
|
||||
}
|
||||
public int getMonsterWeaponId() {
|
||||
return getMonsterData().getWeaponId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage(float amount, int killerId) {
|
||||
// Get HP before damage.
|
||||
float hpBeforeDamage = this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
||||
private int getMonsterId() {
|
||||
return this.getMonsterData().getId();
|
||||
}
|
||||
|
||||
// Apply damage.
|
||||
super.damage(amount, killerId);
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
// Get HP after damage.
|
||||
float hpAfterDamage = this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return this.pos;
|
||||
}
|
||||
|
||||
// Invoke energy drop logic.
|
||||
for (Player player : this.getScene().getPlayers()) {
|
||||
player.getEnergyManager().handleMonsterEnergyDrop(this, hpBeforeDamage, hpAfterDamage);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public Position getRotation() {
|
||||
return this.rot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeath(int killerId) {
|
||||
if (this.getSpawnEntry() != null) {
|
||||
this.getScene().getDeadSpawnedEntities().add(getSpawnEntry());
|
||||
}
|
||||
// first set the challenge data
|
||||
if (getScene().getChallenge() != null) {
|
||||
getScene().getChallenge().onMonsterDeath(this);
|
||||
}
|
||||
if (getScene().getScriptManager().isInit() && this.getGroupId() > 0) {
|
||||
if(getScene().getScriptManager().getScriptMonsterSpawnService() != null){
|
||||
getScene().getScriptManager().getScriptMonsterSpawnService().onMonsterDead(this);
|
||||
}
|
||||
// prevent spawn monster after success
|
||||
if(getScene().getChallenge() != null && getScene().getChallenge().inProgress()){
|
||||
getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_DIE, new ScriptArgs().setParam1(this.getConfigId()));
|
||||
}else if(getScene().getChallenge() == null){
|
||||
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() {
|
||||
// Monster data
|
||||
MonsterData data = this.getMonsterData();
|
||||
public Position getBornPos() {
|
||||
return bornPos;
|
||||
}
|
||||
|
||||
// Get hp percent, set to 100% if none
|
||||
float hpPercent = this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) <= 0 ? 1f : this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) / this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||
|
||||
// Clear properties
|
||||
this.getFightProperties().clear();
|
||||
|
||||
// Base stats
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, data.getBaseHp());
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK, data.getBaseAttack());
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE, data.getBaseDefense());
|
||||
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_PHYSICAL_SUB_HURT, data.getPhysicalSubHurt());
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_FIRE_SUB_HURT, .1f);
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_ELEC_SUB_HURT, data.getElecSubHurt());
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_WATER_SUB_HURT, data.getWaterSubHurt());
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_GRASS_SUB_HURT, data.getGrassSubHurt());
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_WIND_SUB_HURT, data.getWindSubHurt());
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_ROCK_SUB_HURT, .1f);
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_ICE_SUB_HURT, data.getIceSubHurt());
|
||||
|
||||
// Level curve
|
||||
MonsterCurveData curve = GameData.getMonsterCurveDataMap().get(this.getLevel());
|
||||
if (curve != null) {
|
||||
for (PropGrowCurve growCurve : data.getPropGrowCurves()) {
|
||||
FightProperty prop = FightProperty.getPropByName(growCurve.getType());
|
||||
this.setFightProperty(prop, this.getFightProperty(prop) * curve.getMultByProp(growCurve.getGrowCurve()));
|
||||
}
|
||||
}
|
||||
|
||||
// Set % stats
|
||||
this.setFightProperty(
|
||||
FightProperty.FIGHT_PROP_MAX_HP,
|
||||
(getFightProperty(FightProperty.FIGHT_PROP_BASE_HP) * (1f + getFightProperty(FightProperty.FIGHT_PROP_HP_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_HP)
|
||||
);
|
||||
this.setFightProperty(
|
||||
FightProperty.FIGHT_PROP_CUR_ATTACK,
|
||||
(getFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK) * (1f + getFightProperty(FightProperty.FIGHT_PROP_ATTACK_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_ATTACK)
|
||||
);
|
||||
this.setFightProperty(
|
||||
FightProperty.FIGHT_PROP_CUR_DEFENSE,
|
||||
(getFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE) * (1f + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE)
|
||||
);
|
||||
|
||||
// Set current hp
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * hpPercent);
|
||||
}
|
||||
@Override
|
||||
public Int2FloatOpenHashMap getFightProperties() {
|
||||
return fightProp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SceneEntityInfo toProto() {
|
||||
EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder()
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(this.getBornPos().toProto()))
|
||||
.setBornPos(this.getBornPos().toProto())
|
||||
.build();
|
||||
|
||||
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder()
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_MONSTER)
|
||||
.setMotionInfo(this.getMotionInfo())
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setEntityClientData(EntityClientData.newBuilder())
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLifeState(this.getLifeState().getValue());
|
||||
|
||||
for (Int2FloatMap.Entry entry : getFightProperties().int2FloatEntrySet()) {
|
||||
if (entry.getIntKey() == 0) {
|
||||
continue;
|
||||
}
|
||||
FightPropPair fightProp = FightPropPair.newBuilder().setPropType(entry.getIntKey()).setPropValue(entry.getFloatValue()).build();
|
||||
entityInfo.addFightPropList(fightProp);
|
||||
}
|
||||
|
||||
PropPair pair = PropPair.newBuilder()
|
||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, getLevel()))
|
||||
.build();
|
||||
entityInfo.addPropList(pair);
|
||||
|
||||
SceneMonsterInfo.Builder monsterInfo = SceneMonsterInfo.newBuilder()
|
||||
.setMonsterId(getMonsterId())
|
||||
.setGroupId(this.getGroupId())
|
||||
.setConfigId(this.getConfigId())
|
||||
.addAllAffixList(getMonsterData().getAffix())
|
||||
.setAuthorityPeerId(getWorld().getHostPeerId())
|
||||
.setPoseId(this.getPoseId())
|
||||
.setBlockId(3001)
|
||||
.setBornType(MonsterBornType.MONSTER_BORN_TYPE_DEFAULT)
|
||||
.setSpecialNameId(40);
|
||||
|
||||
if (getMonsterData().getDescribeData() != null) {
|
||||
monsterInfo.setTitleId(getMonsterData().getDescribeData().getTitleID());
|
||||
}
|
||||
|
||||
if (this.getMonsterWeaponId() > 0) {
|
||||
SceneWeaponInfo weaponInfo = SceneWeaponInfo.newBuilder()
|
||||
.setEntityId(this.weaponEntityId)
|
||||
.setGadgetId(this.getMonsterWeaponId())
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.build();
|
||||
|
||||
monsterInfo.addWeaponList(weaponInfo);
|
||||
}
|
||||
|
||||
entityInfo.setMonster(monsterInfo);
|
||||
@Override
|
||||
public boolean isAlive() {
|
||||
return this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) > 0f;
|
||||
}
|
||||
|
||||
return entityInfo.build();
|
||||
}
|
||||
public int getPoseId() {
|
||||
return poseId;
|
||||
}
|
||||
|
||||
public void setPoseId(int poseId) {
|
||||
this.poseId = poseId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInteract(Player player, GadgetInteractReq interactReq) {
|
||||
EnvAnimalGatherConfigData gatherData = GameData.getEnvAnimalGatherConfigDataMap().get(this.getMonsterData().getId());
|
||||
|
||||
if (gatherData == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
player.getInventory().addItem(gatherData.getGatherItem(), ActionReason.SubfieldDrop);
|
||||
|
||||
this.getScene().killEntity(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
// Lua event
|
||||
getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_LIVE, new ScriptArgs(this.getConfigId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage(float amount, int killerId) {
|
||||
// Get HP before damage.
|
||||
float hpBeforeDamage = this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
||||
|
||||
// Apply damage.
|
||||
super.damage(amount, killerId);
|
||||
|
||||
// Get HP after damage.
|
||||
float hpAfterDamage = this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
||||
|
||||
// Invoke energy drop logic.
|
||||
for (Player player : this.getScene().getPlayers()) {
|
||||
player.getEnergyManager().handleMonsterEnergyDrop(this, hpBeforeDamage, hpAfterDamage);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeath(int killerId) {
|
||||
if (this.getSpawnEntry() != null) {
|
||||
this.getScene().getDeadSpawnedEntities().add(getSpawnEntry());
|
||||
}
|
||||
// first set the challenge data
|
||||
if (getScene().getChallenge() != null) {
|
||||
getScene().getChallenge().onMonsterDeath(this);
|
||||
}
|
||||
if (getScene().getScriptManager().isInit() && this.getGroupId() > 0) {
|
||||
if (getScene().getScriptManager().getScriptMonsterSpawnService() != null) {
|
||||
getScene().getScriptManager().getScriptMonsterSpawnService().onMonsterDead(this);
|
||||
}
|
||||
// prevent spawn monster after success
|
||||
if (getScene().getChallenge() != null && getScene().getChallenge().inProgress()) {
|
||||
getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_DIE, new ScriptArgs().setParam1(this.getConfigId()));
|
||||
}else if (getScene().getChallenge() == null) {
|
||||
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() {
|
||||
// Monster data
|
||||
MonsterData data = this.getMonsterData();
|
||||
|
||||
// Get hp percent, set to 100% if none
|
||||
float hpPercent = this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) <= 0 ? 1f : this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) / this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||
|
||||
// Clear properties
|
||||
this.getFightProperties().clear();
|
||||
|
||||
// Base stats
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, data.getBaseHp());
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK, data.getBaseAttack());
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE, data.getBaseDefense());
|
||||
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_PHYSICAL_SUB_HURT, data.getPhysicalSubHurt());
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_FIRE_SUB_HURT, .1f);
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_ELEC_SUB_HURT, data.getElecSubHurt());
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_WATER_SUB_HURT, data.getWaterSubHurt());
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_GRASS_SUB_HURT, data.getGrassSubHurt());
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_WIND_SUB_HURT, data.getWindSubHurt());
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_ROCK_SUB_HURT, .1f);
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_ICE_SUB_HURT, data.getIceSubHurt());
|
||||
|
||||
// Level curve
|
||||
MonsterCurveData curve = GameData.getMonsterCurveDataMap().get(this.getLevel());
|
||||
if (curve != null) {
|
||||
for (PropGrowCurve growCurve : data.getPropGrowCurves()) {
|
||||
FightProperty prop = FightProperty.getPropByName(growCurve.getType());
|
||||
this.setFightProperty(prop, this.getFightProperty(prop) * curve.getMultByProp(growCurve.getGrowCurve()));
|
||||
}
|
||||
}
|
||||
|
||||
// Set % stats
|
||||
this.setFightProperty(
|
||||
FightProperty.FIGHT_PROP_MAX_HP,
|
||||
(getFightProperty(FightProperty.FIGHT_PROP_BASE_HP) * (1f + getFightProperty(FightProperty.FIGHT_PROP_HP_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_HP)
|
||||
);
|
||||
this.setFightProperty(
|
||||
FightProperty.FIGHT_PROP_CUR_ATTACK,
|
||||
(getFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK) * (1f + getFightProperty(FightProperty.FIGHT_PROP_ATTACK_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_ATTACK)
|
||||
);
|
||||
this.setFightProperty(
|
||||
FightProperty.FIGHT_PROP_CUR_DEFENSE,
|
||||
(getFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE) * (1f + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE)
|
||||
);
|
||||
|
||||
// Set current hp
|
||||
this.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * hpPercent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SceneEntityInfo toProto() {
|
||||
EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder()
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(this.getBornPos().toProto()))
|
||||
.setBornPos(this.getBornPos().toProto())
|
||||
.build();
|
||||
|
||||
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder()
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_MONSTER)
|
||||
.setMotionInfo(this.getMotionInfo())
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setEntityClientData(EntityClientData.newBuilder())
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLifeState(this.getLifeState().getValue());
|
||||
|
||||
for (Int2FloatMap.Entry entry : getFightProperties().int2FloatEntrySet()) {
|
||||
if (entry.getIntKey() == 0) {
|
||||
continue;
|
||||
}
|
||||
FightPropPair fightProp = FightPropPair.newBuilder().setPropType(entry.getIntKey()).setPropValue(entry.getFloatValue()).build();
|
||||
entityInfo.addFightPropList(fightProp);
|
||||
}
|
||||
|
||||
PropPair pair = PropPair.newBuilder()
|
||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, getLevel()))
|
||||
.build();
|
||||
entityInfo.addPropList(pair);
|
||||
|
||||
SceneMonsterInfo.Builder monsterInfo = SceneMonsterInfo.newBuilder()
|
||||
.setMonsterId(getMonsterId())
|
||||
.setGroupId(this.getGroupId())
|
||||
.setConfigId(this.getConfigId())
|
||||
.addAllAffixList(getMonsterData().getAffix())
|
||||
.setAuthorityPeerId(getWorld().getHostPeerId())
|
||||
.setPoseId(this.getPoseId())
|
||||
.setBlockId(3001)
|
||||
.setBornType(MonsterBornType.MONSTER_BORN_TYPE_DEFAULT)
|
||||
.setSpecialNameId(40);
|
||||
|
||||
if (getMonsterData().getDescribeData() != null) {
|
||||
monsterInfo.setTitleId(getMonsterData().getDescribeData().getTitleID());
|
||||
}
|
||||
|
||||
if (this.getMonsterWeaponId() > 0) {
|
||||
SceneWeaponInfo weaponInfo = SceneWeaponInfo.newBuilder()
|
||||
.setEntityId(this.weaponEntityId)
|
||||
.setGadgetId(this.getMonsterWeaponId())
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.build();
|
||||
|
||||
monsterInfo.addWeaponList(weaponInfo);
|
||||
}
|
||||
|
||||
entityInfo.setMonster(monsterInfo);
|
||||
|
||||
return entityInfo.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.Animat
|
||||
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
|
||||
import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo;
|
||||
import emu.grasscutter.net.proto.FightPropPairOuterClass.*;
|
||||
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
||||
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
|
||||
import emu.grasscutter.net.proto.PropPairOuterClass.PropPair;
|
||||
import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType;
|
||||
@@ -30,104 +31,104 @@ import java.util.ArrayList;
|
||||
|
||||
public class EntityVehicle extends EntityBaseGadget {
|
||||
|
||||
private final Player owner;
|
||||
private final Int2FloatOpenHashMap fightProp;
|
||||
private final Player owner;
|
||||
private final Int2FloatOpenHashMap fightProp;
|
||||
|
||||
private final Position pos;
|
||||
private final Position rot;
|
||||
private final Position pos;
|
||||
private final Position rot;
|
||||
|
||||
private final int pointId;
|
||||
private final int gadgetId;
|
||||
private final int pointId;
|
||||
private final int gadgetId;
|
||||
|
||||
private float curStamina;
|
||||
private List<VehicleMember> vehicleMembers;
|
||||
private float curStamina;
|
||||
private List<VehicleMember> vehicleMembers;
|
||||
|
||||
public EntityVehicle(Scene scene, Player player, int gadgetId, int pointId, Position pos, Position rot) {
|
||||
super(scene);
|
||||
this.owner = player;
|
||||
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
||||
this.fightProp = new Int2FloatOpenHashMap();
|
||||
this.pos = new Position(pos);
|
||||
this.rot = new Position(rot);
|
||||
this.gadgetId = gadgetId;
|
||||
this.pointId = pointId;
|
||||
this.curStamina = 240;
|
||||
this.vehicleMembers = new ArrayList<VehicleMember>();
|
||||
}
|
||||
public EntityVehicle(Scene scene, Player player, int gadgetId, int pointId, Position pos, Position rot) {
|
||||
super(scene);
|
||||
this.owner = player;
|
||||
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
||||
this.fightProp = new Int2FloatOpenHashMap();
|
||||
this.pos = new Position(pos);
|
||||
this.rot = new Position(rot);
|
||||
this.gadgetId = gadgetId;
|
||||
this.pointId = pointId;
|
||||
this.curStamina = 240;
|
||||
this.vehicleMembers = new ArrayList<VehicleMember>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGadgetId() { return gadgetId; }
|
||||
@Override
|
||||
public int getGadgetId() { return gadgetId; }
|
||||
|
||||
public Player getOwner() {
|
||||
return owner;
|
||||
}
|
||||
public Player getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public float getCurStamina() { return curStamina; }
|
||||
public float getCurStamina() { return curStamina; }
|
||||
|
||||
public void setCurStamina(float stamina) { this.curStamina = stamina; }
|
||||
public void setCurStamina(float stamina) { this.curStamina = stamina; }
|
||||
|
||||
public int getPointId() { return pointId; }
|
||||
public int getPointId() { return pointId; }
|
||||
|
||||
public List<VehicleMember> getVehicleMembers() { return vehicleMembers; }
|
||||
public List<VehicleMember> getVehicleMembers() { return vehicleMembers; }
|
||||
|
||||
@Override
|
||||
public Int2FloatOpenHashMap getFightProperties() {
|
||||
return fightProp;
|
||||
}
|
||||
@Override
|
||||
public Int2FloatOpenHashMap getFightProperties() {
|
||||
return fightProp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() { return this.pos; }
|
||||
@Override
|
||||
public Position getPosition() { return this.pos; }
|
||||
|
||||
@Override
|
||||
public Position getRotation() {
|
||||
return this.rot;
|
||||
}
|
||||
@Override
|
||||
public Position getRotation() {
|
||||
return this.rot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SceneEntityInfo toProto() {
|
||||
@Override
|
||||
public SceneEntityInfo toProto() {
|
||||
|
||||
VehicleInfo vehicle = VehicleInfo.newBuilder()
|
||||
.setOwnerUid(this.owner.getUid())
|
||||
.setCurStamina(getCurStamina())
|
||||
.build();
|
||||
VehicleInfo vehicle = VehicleInfo.newBuilder()
|
||||
.setOwnerUid(this.owner.getUid())
|
||||
.setCurStamina(getCurStamina())
|
||||
.build();
|
||||
|
||||
EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder()
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(getPosition().toProto()))
|
||||
.setBornPos(getPosition().toProto())
|
||||
.build();
|
||||
EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder()
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(getPosition().toProto()))
|
||||
.setBornPos(getPosition().toProto())
|
||||
.build();
|
||||
|
||||
SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder()
|
||||
.setGadgetId(this.getGadgetId())
|
||||
.setAuthorityPeerId(this.getOwner().getPeerId())
|
||||
.setIsEnableInteract(true)
|
||||
.setVehicleInfo(vehicle);
|
||||
SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder()
|
||||
.setGadgetId(this.getGadgetId())
|
||||
.setAuthorityPeerId(this.getOwner().getPeerId())
|
||||
.setIsEnableInteract(true)
|
||||
.setVehicleInfo(vehicle);
|
||||
|
||||
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder()
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
||||
.setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder()))
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setGadget(gadgetInfo)
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLifeState(1);
|
||||
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder()
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
||||
.setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder()))
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setGadget(gadgetInfo)
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLifeState(1);
|
||||
|
||||
PropPair pair = PropPair.newBuilder()
|
||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 47))
|
||||
.build();
|
||||
PropPair pair = PropPair.newBuilder()
|
||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 47))
|
||||
.build();
|
||||
|
||||
for (Int2FloatMap.Entry entry : getFightProperties().int2FloatEntrySet()) {
|
||||
if (entry.getIntKey() == 0) {
|
||||
continue;
|
||||
}
|
||||
FightPropPair fightProp = FightPropPair.newBuilder().setPropType(entry.getIntKey()).setPropValue(entry.getFloatValue()).build();
|
||||
entityInfo.addFightPropList(fightProp);
|
||||
}
|
||||
for (Int2FloatMap.Entry entry : getFightProperties().int2FloatEntrySet()) {
|
||||
if (entry.getIntKey() == 0) {
|
||||
continue;
|
||||
}
|
||||
FightPropPair fightProp = FightPropPair.newBuilder().setPropType(entry.getIntKey()).setPropValue(entry.getFloatValue()).build();
|
||||
entityInfo.addFightPropList(fightProp);
|
||||
}
|
||||
|
||||
entityInfo.addPropList(pair);
|
||||
entityInfo.addPropList(pair);
|
||||
|
||||
return entityInfo.build();
|
||||
}
|
||||
return entityInfo.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,14 @@ package emu.grasscutter.game.entity;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.game.props.LifeState;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.game.world.SpawnDataEntry;
|
||||
import emu.grasscutter.game.world.World;
|
||||
import emu.grasscutter.net.proto.FightPropPairOuterClass.FightPropPair;
|
||||
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
||||
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
|
||||
import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState;
|
||||
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
||||
@@ -80,153 +82,153 @@ public abstract class GameEntity {
|
||||
return this.metaModifiers;
|
||||
}
|
||||
|
||||
public abstract Int2FloatOpenHashMap getFightProperties();
|
||||
public abstract Int2FloatOpenHashMap getFightProperties();
|
||||
|
||||
public abstract Position getPosition();
|
||||
public abstract Position getPosition();
|
||||
|
||||
public abstract Position getRotation();
|
||||
public abstract Position getRotation();
|
||||
|
||||
public MotionState getMotionState() {
|
||||
return moveState;
|
||||
}
|
||||
public MotionState getMotionState() {
|
||||
return moveState;
|
||||
}
|
||||
|
||||
public void setMotionState(MotionState moveState) {
|
||||
this.moveState = moveState;
|
||||
}
|
||||
public void setMotionState(MotionState moveState) {
|
||||
this.moveState = moveState;
|
||||
}
|
||||
|
||||
public int getLastMoveSceneTimeMs() {
|
||||
return lastMoveSceneTimeMs;
|
||||
}
|
||||
public int getLastMoveSceneTimeMs() {
|
||||
return lastMoveSceneTimeMs;
|
||||
}
|
||||
|
||||
public void setLastMoveSceneTimeMs(int lastMoveSceneTimeMs) {
|
||||
this.lastMoveSceneTimeMs = lastMoveSceneTimeMs;
|
||||
}
|
||||
public void setLastMoveSceneTimeMs(int lastMoveSceneTimeMs) {
|
||||
this.lastMoveSceneTimeMs = lastMoveSceneTimeMs;
|
||||
}
|
||||
|
||||
public int getLastMoveReliableSeq() {
|
||||
return lastMoveReliableSeq;
|
||||
}
|
||||
public int getLastMoveReliableSeq() {
|
||||
return lastMoveReliableSeq;
|
||||
}
|
||||
|
||||
public void setLastMoveReliableSeq(int lastMoveReliableSeq) {
|
||||
this.lastMoveReliableSeq = lastMoveReliableSeq;
|
||||
}
|
||||
public void setLastMoveReliableSeq(int lastMoveReliableSeq) {
|
||||
this.lastMoveReliableSeq = lastMoveReliableSeq;
|
||||
}
|
||||
|
||||
public void setFightProperty(FightProperty prop, float value) {
|
||||
this.getFightProperties().put(prop.getId(), value);
|
||||
}
|
||||
public void setFightProperty(FightProperty prop, float value) {
|
||||
this.getFightProperties().put(prop.getId(), value);
|
||||
}
|
||||
|
||||
private void setFightProperty(int id, float value) {
|
||||
this.getFightProperties().put(id, value);
|
||||
}
|
||||
private void setFightProperty(int id, float value) {
|
||||
this.getFightProperties().put(id, value);
|
||||
}
|
||||
|
||||
public void addFightProperty(FightProperty prop, float value) {
|
||||
this.getFightProperties().put(prop.getId(), getFightProperty(prop) + value);
|
||||
}
|
||||
public void addFightProperty(FightProperty prop, float value) {
|
||||
this.getFightProperties().put(prop.getId(), getFightProperty(prop) + value);
|
||||
}
|
||||
|
||||
public float getFightProperty(FightProperty prop) {
|
||||
return getFightProperties().getOrDefault(prop.getId(), 0f);
|
||||
}
|
||||
public float getFightProperty(FightProperty prop) {
|
||||
return getFightProperties().getOrDefault(prop.getId(), 0f);
|
||||
}
|
||||
|
||||
public void addAllFightPropsToEntityInfo(SceneEntityInfo.Builder entityInfo) {
|
||||
for (Int2FloatMap.Entry entry : getFightProperties().int2FloatEntrySet()) {
|
||||
if (entry.getIntKey() == 0) {
|
||||
continue;
|
||||
}
|
||||
FightPropPair fightProp = FightPropPair.newBuilder().setPropType(entry.getIntKey()).setPropValue(entry.getFloatValue()).build();
|
||||
entityInfo.addFightPropList(fightProp);
|
||||
}
|
||||
}
|
||||
public void addAllFightPropsToEntityInfo(SceneEntityInfo.Builder entityInfo) {
|
||||
for (Int2FloatMap.Entry entry : getFightProperties().int2FloatEntrySet()) {
|
||||
if (entry.getIntKey() == 0) {
|
||||
continue;
|
||||
}
|
||||
FightPropPair fightProp = FightPropPair.newBuilder().setPropType(entry.getIntKey()).setPropValue(entry.getFloatValue()).build();
|
||||
entityInfo.addFightPropList(fightProp);
|
||||
}
|
||||
}
|
||||
|
||||
public int getBlockId() {
|
||||
return blockId;
|
||||
}
|
||||
public int getBlockId() {
|
||||
return blockId;
|
||||
}
|
||||
|
||||
public void setBlockId(int blockId) {
|
||||
this.blockId = blockId;
|
||||
}
|
||||
public void setBlockId(int blockId) {
|
||||
this.blockId = blockId;
|
||||
}
|
||||
|
||||
public int getConfigId() {
|
||||
return configId;
|
||||
}
|
||||
public int getConfigId() {
|
||||
return configId;
|
||||
}
|
||||
|
||||
public void setConfigId(int configId) {
|
||||
this.configId = configId;
|
||||
}
|
||||
public void setConfigId(int configId) {
|
||||
this.configId = configId;
|
||||
}
|
||||
|
||||
public int getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
public int getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(int groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
public void setGroupId(int groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
protected MotionInfo getMotionInfo() {
|
||||
MotionInfo proto = MotionInfo.newBuilder()
|
||||
.setPos(getPosition().toProto())
|
||||
.setRot(getRotation().toProto())
|
||||
.setSpeed(Vector.newBuilder())
|
||||
.setState(this.getMotionState())
|
||||
.build();
|
||||
protected MotionInfo getMotionInfo() {
|
||||
MotionInfo proto = MotionInfo.newBuilder()
|
||||
.setPos(getPosition().toProto())
|
||||
.setRot(getRotation().toProto())
|
||||
.setSpeed(Vector.newBuilder())
|
||||
.setState(this.getMotionState())
|
||||
.build();
|
||||
|
||||
return proto;
|
||||
}
|
||||
return proto;
|
||||
}
|
||||
|
||||
public SpawnDataEntry getSpawnEntry() {
|
||||
return spawnEntry;
|
||||
}
|
||||
public SpawnDataEntry getSpawnEntry() {
|
||||
return spawnEntry;
|
||||
}
|
||||
|
||||
public void setSpawnEntry(SpawnDataEntry spawnEntry) {
|
||||
this.spawnEntry = spawnEntry;
|
||||
}
|
||||
public void setSpawnEntry(SpawnDataEntry spawnEntry) {
|
||||
this.spawnEntry = spawnEntry;
|
||||
}
|
||||
|
||||
public float heal(float amount) {
|
||||
if (this.getFightProperties() == null) {
|
||||
return 0f;
|
||||
}
|
||||
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);
|
||||
float curHp = getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
||||
float maxHp = getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||
|
||||
if (curHp >= maxHp) {
|
||||
return 0f;
|
||||
}
|
||||
if (curHp >= maxHp) {
|
||||
return 0f;
|
||||
}
|
||||
|
||||
float healed = Math.min(maxHp - curHp, amount);
|
||||
this.addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, healed);
|
||||
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));
|
||||
getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, FightProperty.FIGHT_PROP_CUR_HP));
|
||||
|
||||
return healed;
|
||||
}
|
||||
return healed;
|
||||
}
|
||||
|
||||
public void damage(float amount) {
|
||||
damage(amount, 0);
|
||||
}
|
||||
public void damage(float amount) {
|
||||
damage(amount, 0);
|
||||
}
|
||||
|
||||
public void damage(float amount, int killerId) {
|
||||
// Sanity check
|
||||
if (getFightProperties() == null) {
|
||||
return;
|
||||
}
|
||||
public void damage(float amount, int killerId) {
|
||||
// Sanity check
|
||||
if (getFightProperties() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Lose hp
|
||||
addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, -amount);
|
||||
// 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;
|
||||
}
|
||||
// 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));
|
||||
// Packets
|
||||
this.getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, FightProperty.FIGHT_PROP_CUR_HP));
|
||||
|
||||
// Check if dead
|
||||
if (isDead) {
|
||||
getScene().killEntity(this, killerId);
|
||||
}
|
||||
}
|
||||
// Check if dead
|
||||
if (isDead) {
|
||||
getScene().killEntity(this, killerId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move this entity to a new position.
|
||||
@@ -239,20 +241,29 @@ public abstract class GameEntity {
|
||||
this.getRotation().set(rotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a player interacts with this entity
|
||||
* @param player Player that is interacting with this entity
|
||||
* @param interactReq Interact request protobuf data
|
||||
*/
|
||||
public void onInteract(Player player, GadgetInteractReq interactReq) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this entity is added to the world
|
||||
*/
|
||||
public void onCreate() {
|
||||
public void onCreate() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Called when this entity dies
|
||||
* @param killerId Entity id of the entity that killed this entity
|
||||
*/
|
||||
public void onDeath(int killerId) {
|
||||
public void onDeath(int killerId) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public abstract SceneEntityInfo toProto();
|
||||
public abstract SceneEntityInfo toProto();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package emu.grasscutter.game.entity.gadget;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.game.entity.EntityGadget;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.LifeState;
|
||||
import emu.grasscutter.net.proto.BossChestInfoOuterClass.BossChestInfo;
|
||||
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
||||
import emu.grasscutter.net.proto.InterOpTypeOuterClass.InterOpType;
|
||||
@@ -11,54 +12,54 @@ import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType;
|
||||
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||
import emu.grasscutter.scripts.constants.ScriptGadgetState;
|
||||
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
|
||||
import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify;
|
||||
|
||||
public class GadgetChest extends GadgetContent {
|
||||
|
||||
public GadgetChest(EntityGadget gadget) {
|
||||
super(gadget);
|
||||
}
|
||||
|
||||
public boolean onInteract(Player player, GadgetInteractReq req) {
|
||||
var chestInteractHandlerMap = getGadget().getScene().getWorld().getServer().getWorldDataManager().getChestInteractHandlerMap();
|
||||
var handler = chestInteractHandlerMap.get(getGadget().getGadgetData().getJsonName());
|
||||
if(handler == null){
|
||||
Grasscutter.getLogger().warn("Could not found the handler of this type of Chests {}", getGadget().getGadgetData().getJsonName());
|
||||
return false;
|
||||
}
|
||||
public GadgetChest(EntityGadget gadget) {
|
||||
super(gadget);
|
||||
}
|
||||
|
||||
if(req.getOpType() == InterOpType.INTER_OP_TYPE_START && handler.isTwoStep()){
|
||||
player.sendPacket(new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_TYPE_OPEN_CHEST, InterOpType.INTER_OP_TYPE_START));
|
||||
return false;
|
||||
}else{
|
||||
var success = handler.onInteract(this, player);
|
||||
if (!success){
|
||||
return false;
|
||||
}
|
||||
public boolean onInteract(Player player, GadgetInteractReq req) {
|
||||
var chestInteractHandlerMap = getGadget().getScene().getWorld().getServer().getWorldDataSystem().getChestInteractHandlerMap();
|
||||
var handler = chestInteractHandlerMap.get(getGadget().getGadgetData().getJsonName());
|
||||
if (handler == null) {
|
||||
Grasscutter.getLogger().warn("Could not found the handler of this type of Chests {}", getGadget().getGadgetData().getJsonName());
|
||||
return false;
|
||||
}
|
||||
|
||||
getGadget().updateState(ScriptGadgetState.ChestOpened);
|
||||
player.sendPacket(new PacketGadgetInteractRsp(this.getGadget(), InteractTypeOuterClass.InteractType.INTERACT_TYPE_OPEN_CHEST));
|
||||
// let the chest disappear
|
||||
getGadget().die();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (req.getOpType() == InterOpType.INTER_OP_TYPE_START && handler.isTwoStep()) {
|
||||
player.sendPacket(new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_TYPE_OPEN_CHEST, InterOpType.INTER_OP_TYPE_START));
|
||||
return false;
|
||||
}else {
|
||||
var success = handler.onInteract(this, player);
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void onBuildProto(SceneGadgetInfo.Builder gadgetInfo) {
|
||||
if(getGadget().getMetaGadget() == null){
|
||||
return;
|
||||
}
|
||||
getGadget().updateState(ScriptGadgetState.ChestOpened);
|
||||
player.sendPacket(new PacketGadgetInteractRsp(this.getGadget(), InteractTypeOuterClass.InteractType.INTERACT_TYPE_OPEN_CHEST));
|
||||
|
||||
var bossChest = getGadget().getMetaGadget().boss_chest;
|
||||
if(bossChest != null){
|
||||
var players = getGadget().getScene().getPlayers().stream().map(Player::getUid).toList();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
gadgetInfo.setBossChest(BossChestInfo.newBuilder()
|
||||
.setMonsterConfigId(bossChest.monster_config_id)
|
||||
.setResin(bossChest.resin)
|
||||
.addAllQualifyUidList(players)
|
||||
.addAllRemainUidList(players)
|
||||
.build());
|
||||
}
|
||||
public void onBuildProto(SceneGadgetInfo.Builder gadgetInfo) {
|
||||
if (getGadget().getMetaGadget() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
var bossChest = getGadget().getMetaGadget().boss_chest;
|
||||
if (bossChest != null) {
|
||||
var players = getGadget().getScene().getPlayers().stream().map(Player::getUid).toList();
|
||||
|
||||
gadgetInfo.setBossChest(BossChestInfo.newBuilder()
|
||||
.setMonsterConfigId(bossChest.monster_config_id)
|
||||
.setResin(bossChest.resin)
|
||||
.addAllQualifyUidList(players)
|
||||
.addAllRemainUidList(players)
|
||||
.build());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,11 @@ public class BossChestInteractHandler implements ChestInteractHandler{
|
||||
|
||||
@Override
|
||||
public boolean onInteract(GadgetChest chest, Player player) {
|
||||
var worldDataManager = chest.getGadget().getScene().getWorld().getServer().getWorldDataManager();
|
||||
var worldDataManager = chest.getGadget().getScene().getWorld().getServer().getWorldDataSystem();
|
||||
var monster = chest.getGadget().getMetaGadget().group.monsters.get(chest.getGadget().getMetaGadget().boss_chest.monster_config_id);
|
||||
var reward = worldDataManager.getRewardByBossId(monster.monster_id);
|
||||
|
||||
if(reward == null){
|
||||
if (reward == null) {
|
||||
Grasscutter.getLogger().warn("Could not found the reward of boss monster {}", monster.monster_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user