mirror of
https://github.com/Melledy/Grasscutter.git
synced 2024-11-30 09:32:52 +00:00
Energy: Particle/Orb Drops from Monsters (#1054)
* Generate energy drops for monsters + make sure picking up particles honors their count. * Use drop info from excels instead. * Remove double newline. * Remove commented code.
This commit is contained in:
parent
c45dd92ba5
commit
ef20177a6b
@ -6,6 +6,7 @@ import java.util.Calendar;
|
|||||||
import emu.grasscutter.auth.AuthenticationSystem;
|
import emu.grasscutter.auth.AuthenticationSystem;
|
||||||
import emu.grasscutter.auth.DefaultAuthentication;
|
import emu.grasscutter.auth.DefaultAuthentication;
|
||||||
import emu.grasscutter.command.CommandMap;
|
import emu.grasscutter.command.CommandMap;
|
||||||
|
import emu.grasscutter.game.managers.EnergyManager.EnergyManager;
|
||||||
import emu.grasscutter.game.managers.StaminaManager.StaminaManager;
|
import emu.grasscutter.game.managers.StaminaManager.StaminaManager;
|
||||||
import emu.grasscutter.plugin.PluginManager;
|
import emu.grasscutter.plugin.PluginManager;
|
||||||
import emu.grasscutter.plugin.api.ServerHook;
|
import emu.grasscutter.plugin.api.ServerHook;
|
||||||
@ -106,6 +107,7 @@ public final class Grasscutter {
|
|||||||
Grasscutter.updateDayOfWeek();
|
Grasscutter.updateDayOfWeek();
|
||||||
ResourceLoader.loadAll();
|
ResourceLoader.loadAll();
|
||||||
ScriptLoader.init();
|
ScriptLoader.init();
|
||||||
|
EnergyManager.initialize();
|
||||||
|
|
||||||
// Initialize database.
|
// Initialize database.
|
||||||
DatabaseManager.initialize();
|
DatabaseManager.initialize();
|
||||||
|
@ -5,6 +5,7 @@ import emu.grasscutter.data.common.PropGrowCurve;
|
|||||||
import emu.grasscutter.data.def.MonsterCurveData;
|
import emu.grasscutter.data.def.MonsterCurveData;
|
||||||
import emu.grasscutter.data.def.MonsterData;
|
import emu.grasscutter.data.def.MonsterData;
|
||||||
import emu.grasscutter.game.dungeons.DungeonChallenge;
|
import emu.grasscutter.game.dungeons.DungeonChallenge;
|
||||||
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.props.EntityIdType;
|
import emu.grasscutter.game.props.EntityIdType;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
import emu.grasscutter.game.props.PlayerProperty;
|
import emu.grasscutter.game.props.PlayerProperty;
|
||||||
@ -111,6 +112,23 @@ public class EntityMonster extends GameEntity {
|
|||||||
this.poseId = poseId;
|
this.poseId = poseId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
@Override
|
||||||
public void onDeath(int killerId) {
|
public void onDeath(int killerId) {
|
||||||
if (this.getSpawnEntry() != null) {
|
if (this.getSpawnEntry() != null) {
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package emu.grasscutter.game.managers.EnergyManager;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class EnergyDropEntry {
|
||||||
|
private int dropId;
|
||||||
|
private List<EnergyDropInfo> dropList;
|
||||||
|
|
||||||
|
public int getDropId() {
|
||||||
|
return this.dropId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<EnergyDropInfo> getDropList() {
|
||||||
|
return this.dropList;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package emu.grasscutter.game.managers.EnergyManager;
|
||||||
|
|
||||||
|
public class EnergyDropInfo {
|
||||||
|
private int ballId;
|
||||||
|
private int count;
|
||||||
|
|
||||||
|
public int getBallId() {
|
||||||
|
return this.ballId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCount() {
|
||||||
|
return this.count;
|
||||||
|
}
|
||||||
|
}
|
@ -1,30 +1,43 @@
|
|||||||
package emu.grasscutter.game.managers;
|
package emu.grasscutter.game.managers.EnergyManager;
|
||||||
|
|
||||||
|
import emu.grasscutter.Grasscutter;
|
||||||
|
import emu.grasscutter.data.DataLoader;
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.def.AvatarSkillDepotData;
|
import emu.grasscutter.data.def.AvatarSkillDepotData;
|
||||||
import emu.grasscutter.data.def.ItemData;
|
import emu.grasscutter.data.def.ItemData;
|
||||||
|
import emu.grasscutter.data.def.MonsterData.HpDrops;
|
||||||
import emu.grasscutter.game.avatar.Avatar;
|
import emu.grasscutter.game.avatar.Avatar;
|
||||||
import emu.grasscutter.game.entity.EntityAvatar;
|
import emu.grasscutter.game.entity.EntityAvatar;
|
||||||
import emu.grasscutter.game.entity.EntityClientGadget;
|
import emu.grasscutter.game.entity.EntityClientGadget;
|
||||||
import emu.grasscutter.game.entity.EntityItem;
|
import emu.grasscutter.game.entity.EntityItem;
|
||||||
|
import emu.grasscutter.game.entity.EntityMonster;
|
||||||
import emu.grasscutter.game.entity.GameEntity;
|
import emu.grasscutter.game.entity.GameEntity;
|
||||||
import emu.grasscutter.game.inventory.GameItem;
|
import emu.grasscutter.game.inventory.GameItem;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.props.ElementType;
|
import emu.grasscutter.game.props.ElementType;
|
||||||
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
import emu.grasscutter.net.proto.AbilityActionGenerateElemBallOuterClass.AbilityActionGenerateElemBall;
|
import emu.grasscutter.net.proto.AbilityActionGenerateElemBallOuterClass.AbilityActionGenerateElemBall;
|
||||||
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
|
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
|
||||||
import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason;
|
import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
|
||||||
import static emu.grasscutter.Configuration.GAME_OPTIONS;
|
import static emu.grasscutter.Configuration.GAME_OPTIONS;
|
||||||
|
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
import com.google.protobuf.InvalidProtocolBufferException;
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
|
|
||||||
public class EnergyManager {
|
public class EnergyManager {
|
||||||
private final Player player;
|
private final Player player;
|
||||||
|
private final static Int2ObjectMap<List<EnergyDropInfo>> energyDropData = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
public EnergyManager(Player player) {
|
public EnergyManager(Player player) {
|
||||||
this.player = player;
|
this.player = player;
|
||||||
@ -34,6 +47,22 @@ public class EnergyManager {
|
|||||||
return this.player;
|
return this.player;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void initialize() {
|
||||||
|
// Read the data we need for monster energy drops.
|
||||||
|
try (Reader fileReader = new InputStreamReader(DataLoader.load("EnergyDrop.json"))) {
|
||||||
|
List<EnergyDropEntry> energyDropList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, EnergyDropEntry.class).getType());
|
||||||
|
|
||||||
|
for (EnergyDropEntry entry : energyDropList) {
|
||||||
|
energyDropData.put(entry.getDropId(), entry.getDropList());
|
||||||
|
}
|
||||||
|
|
||||||
|
Grasscutter.getLogger().info("Energy drop data successfully loaded.");
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
Grasscutter.getLogger().error("Unable to load energy drop data.", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**********
|
/**********
|
||||||
Particle creation for elemental skills.
|
Particle creation for elemental skills.
|
||||||
**********/
|
**********/
|
||||||
@ -117,17 +146,8 @@ public class EnergyManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the item data for an energy particle of the correct element.
|
// Generate the particle/orb.
|
||||||
ItemData itemData = GameData.getItemDataMap().get(itemId);
|
generateElemBall(itemId, new Position(action.getPos()), 1);
|
||||||
if (itemData == null) {
|
|
||||||
return; // Should never happen
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate entity.
|
|
||||||
EntityItem energyBall = new EntityItem(getPlayer().getScene(), getPlayer(), itemData, new Position(action.getPos()), 1);
|
|
||||||
energyBall.getRotation().set(action.getRot());
|
|
||||||
|
|
||||||
this.getPlayer().getScene().addEntity(energyBall);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********
|
/**********
|
||||||
@ -183,11 +203,10 @@ public class EnergyManager {
|
|||||||
float elementBonus = (ballElement == null) ? 2.0f : (avatarElement == ballElement) ? 3.0f : 1.0f;
|
float elementBonus = (ballElement == null) ? 2.0f : (avatarElement == ballElement) ? 3.0f : 1.0f;
|
||||||
|
|
||||||
// Add the energy.
|
// Add the energy.
|
||||||
entity.addEnergy(baseEnergy * elementBonus * offFieldPenalty, PropChangeReason.PROP_CHANGE_ENERGY_BALL);
|
entity.addEnergy(baseEnergy * elementBonus * offFieldPenalty * elemBall.getCount(), PropChangeReason.PROP_CHANGE_ENERGY_BALL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**********
|
/**********
|
||||||
Energy logic related to using skills.
|
Energy logic related to using skills.
|
||||||
**********/
|
**********/
|
||||||
@ -218,4 +237,56 @@ public class EnergyManager {
|
|||||||
// Handle elemental burst.
|
// Handle elemental burst.
|
||||||
this.handleBurstCast(avatar, skillId);
|
this.handleBurstCast(avatar, skillId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**********
|
||||||
|
Monster energy drops.
|
||||||
|
**********/
|
||||||
|
private void generateElemBallDrops(EntityMonster monster, int dropId) {
|
||||||
|
// Generate all drops specified for the given drop id.
|
||||||
|
if (!energyDropData.containsKey(dropId)) {
|
||||||
|
Grasscutter.getLogger().warn("No drop data for dropId {} found.", dropId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (EnergyDropInfo info : energyDropData.get(dropId)) {
|
||||||
|
this.generateElemBall(info.getBallId(), monster.getPosition(), info.getCount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void handleMonsterEnergyDrop(EntityMonster monster, float hpBeforeDamage, float hpAfterDamage) {
|
||||||
|
// Calculate the HP tresholds for before and after the damage was taken.
|
||||||
|
float maxHp = monster.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||||
|
float thresholdBefore = hpBeforeDamage / maxHp;
|
||||||
|
float thresholdAfter = hpAfterDamage / maxHp;
|
||||||
|
|
||||||
|
// Determine the thresholds the monster has passed, and generate drops based on that.
|
||||||
|
for (HpDrops drop : monster.getMonsterData().getHpDrops()) {
|
||||||
|
if (drop.getDropId() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float threshold = drop.getHpPercent() / 100.0f;
|
||||||
|
if (threshold < thresholdBefore && threshold >= thresholdAfter) {
|
||||||
|
generateElemBallDrops(monster, drop.getDropId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle kill drops.
|
||||||
|
if (hpAfterDamage <= 0 && monster.getMonsterData().getKillDropId() != 0) {
|
||||||
|
generateElemBallDrops(monster, monster.getMonsterData().getKillDropId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********
|
||||||
|
Utility.
|
||||||
|
**********/
|
||||||
|
private void generateElemBall(int ballId, Position position, int count) {
|
||||||
|
// Generate a particle/orb with the specified parameters.
|
||||||
|
ItemData itemData = GameData.getItemDataMap().get(ballId);
|
||||||
|
if (itemData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityItem energyBall = new EntityItem(this.getPlayer().getScene(), this.getPlayer(), itemData, position, count);
|
||||||
|
this.getPlayer().getScene().addEntity(energyBall);
|
||||||
|
}
|
||||||
}
|
}
|
@ -23,8 +23,8 @@ import emu.grasscutter.game.inventory.Inventory;
|
|||||||
import emu.grasscutter.game.mail.Mail;
|
import emu.grasscutter.game.mail.Mail;
|
||||||
import emu.grasscutter.game.mail.MailHandler;
|
import emu.grasscutter.game.mail.MailHandler;
|
||||||
import emu.grasscutter.game.managers.StaminaManager.StaminaManager;
|
import emu.grasscutter.game.managers.StaminaManager.StaminaManager;
|
||||||
import emu.grasscutter.game.managers.EnergyManager;
|
|
||||||
import emu.grasscutter.game.managers.SotSManager;
|
import emu.grasscutter.game.managers.SotSManager;
|
||||||
|
import emu.grasscutter.game.managers.EnergyManager.EnergyManager;
|
||||||
import emu.grasscutter.game.props.ActionReason;
|
import emu.grasscutter.game.props.ActionReason;
|
||||||
import emu.grasscutter.game.props.EntityType;
|
import emu.grasscutter.game.props.EntityType;
|
||||||
import emu.grasscutter.game.props.PlayerProperty;
|
import emu.grasscutter.game.props.PlayerProperty;
|
||||||
|
160
src/main/resources/defaults/data/EnergyDrop.json
Normal file
160
src/main/resources/defaults/data/EnergyDrop.json
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"dropId": 22010010,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2024, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010030,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2008, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010050,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2024, "count": 3 },
|
||||||
|
{ "ballId": 2008, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010013,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2019, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010033,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2003, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010015,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2021, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010035,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2005, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010034,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2004, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010037,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2007, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010032,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2002, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010022,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2018, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010036,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2006, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010026,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2022, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010031,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2001, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"dropId": 22010014,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2020, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010016,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2022, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010012,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2018, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010024,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2004, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010011,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2017, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010017,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2023, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010021,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2017, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010027,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2007, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010040,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2024, "count": 1 },
|
||||||
|
{ "ballId": 2008, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010025,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2021, "count": 2 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22010020,
|
||||||
|
"dropList": [
|
||||||
|
{ "ballId": 2024, "count": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dropId": 22003100,
|
||||||
|
"dropList": [
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
Loading…
Reference in New Issue
Block a user