mirror of
https://github.com/Melledy/Grasscutter.git
synced 2024-11-29 13:17:21 +00:00
Add character's specialty food.
This commit is contained in:
parent
d95a30a1a5
commit
13a7f08665
@ -99,6 +99,7 @@ public class GameData {
|
|||||||
private static final Int2ObjectMap<BattlePassMissionData> battlePassMissionDataMap = new Int2ObjectOpenHashMap<>();
|
private static final Int2ObjectMap<BattlePassMissionData> battlePassMissionDataMap = new Int2ObjectOpenHashMap<>();
|
||||||
private static final Int2ObjectMap<BattlePassRewardData> battlePassRewardDataMap = new Int2ObjectOpenHashMap<>();
|
private static final Int2ObjectMap<BattlePassRewardData> battlePassRewardDataMap = new Int2ObjectOpenHashMap<>();
|
||||||
private static final Int2ObjectMap<CookRecipeData> cookRecipeDataMap = new Int2ObjectOpenHashMap<>();
|
private static final Int2ObjectMap<CookRecipeData> cookRecipeDataMap = new Int2ObjectOpenHashMap<>();
|
||||||
|
private static final Int2ObjectMap<CookBonusData> cookBonusDataMap = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
@Getter private static final Int2ObjectMap<ActivityData> activityDataMap = new Int2ObjectOpenHashMap<>();
|
@Getter private static final Int2ObjectMap<ActivityData> activityDataMap = new Int2ObjectOpenHashMap<>();
|
||||||
@Getter private static final Int2ObjectMap<ActivityWatcherData> activityWatcherDataMap = new Int2ObjectOpenHashMap<>();
|
@Getter private static final Int2ObjectMap<ActivityWatcherData> activityWatcherDataMap = new Int2ObjectOpenHashMap<>();
|
||||||
@ -441,4 +442,8 @@ public class GameData {
|
|||||||
public static Int2ObjectMap<CookRecipeData> getCookRecipeDataMap() {
|
public static Int2ObjectMap<CookRecipeData> getCookRecipeDataMap() {
|
||||||
return cookRecipeDataMap;
|
return cookRecipeDataMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Int2ObjectMap<CookBonusData> getCookBonusDataMap() {
|
||||||
|
return cookBonusDataMap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
45
src/main/java/emu/grasscutter/data/excels/CookBonusData.java
Normal file
45
src/main/java/emu/grasscutter/data/excels/CookBonusData.java
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package emu.grasscutter.data.excels;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import emu.grasscutter.data.GameResource;
|
||||||
|
import emu.grasscutter.data.ResourceType;
|
||||||
|
import emu.grasscutter.data.ResourceType.LoadPriority;
|
||||||
|
import emu.grasscutter.data.common.ItemParamData;
|
||||||
|
|
||||||
|
@ResourceType(name = {"CookBonusExcelConfigData.json"}, loadPriority = LoadPriority.LOW)
|
||||||
|
public class CookBonusData extends GameResource {
|
||||||
|
private int avatarId;
|
||||||
|
private int recipeId;
|
||||||
|
private int[] paramVec;
|
||||||
|
private int[] complexParamVec;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return this.avatarId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAvatarId() {
|
||||||
|
return avatarId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRecipeId() {
|
||||||
|
return recipeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getParamVec() {
|
||||||
|
return paramVec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getComplexParamVec() {
|
||||||
|
return complexParamVec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getReplacementItemId() {
|
||||||
|
return this.paramVec[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
}
|
||||||
|
}
|
@ -20,6 +20,7 @@ import emu.grasscutter.server.packet.send.PacketCookDataNotify;
|
|||||||
import emu.grasscutter.server.packet.send.PacketCookRecipeDataNotify;
|
import emu.grasscutter.server.packet.send.PacketCookRecipeDataNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketPlayerCookArgsRsp;
|
import emu.grasscutter.server.packet.send.PacketPlayerCookArgsRsp;
|
||||||
import emu.grasscutter.server.packet.send.PacketPlayerCookRsp;
|
import emu.grasscutter.server.packet.send.PacketPlayerCookRsp;
|
||||||
|
import io.netty.util.internal.ThreadLocalRandom;
|
||||||
|
|
||||||
public class CookingManager {
|
public class CookingManager {
|
||||||
private static final int MANUAL_PERFECT_COOK_QUALITY = 3;
|
private static final int MANUAL_PERFECT_COOK_QUALITY = 3;
|
||||||
@ -46,33 +47,44 @@ public class CookingManager {
|
|||||||
* Unlocking for recipies.
|
* Unlocking for recipies.
|
||||||
********************/
|
********************/
|
||||||
public synchronized boolean unlockRecipe(GameItem recipeItem) {
|
public synchronized boolean unlockRecipe(GameItem recipeItem) {
|
||||||
// Make sure this is actually a cooking recipe.
|
// Make sure this is actually a cooking recipe.
|
||||||
if (!recipeItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_COOK_RECIPE")) {
|
if (!recipeItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_COOK_RECIPE")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the recipe we should unlock.
|
// Determine the recipe we should unlock.
|
||||||
int recipeId = Integer.parseInt(recipeItem.getItemData().getItemUse().get(0).getUseParam().get(0));
|
int recipeId = Integer.parseInt(recipeItem.getItemData().getItemUse().get(0).getUseParam().get(0));
|
||||||
|
|
||||||
// Remove the item from the player's inventory.
|
// Remove the item from the player's inventory.
|
||||||
// We need to do this here, before sending CookRecipeDataNotify, or the the UI won't correctly update.
|
// We need to do this here, before sending CookRecipeDataNotify, or the the UI won't correctly update.
|
||||||
player.getInventory().removeItem(recipeItem, 1);
|
player.getInventory().removeItem(recipeItem, 1);
|
||||||
|
|
||||||
// Tell the client that this blueprint is now unlocked and add the unlocked item to the player.
|
// Tell the client that this blueprint is now unlocked and add the unlocked item to the player.
|
||||||
this.player.getUnlockedRecipies().put(recipeId, 0);
|
this.player.getUnlockedRecipies().put(recipeId, 0);
|
||||||
this.player.sendPacket(new PacketCookRecipeDataNotify(recipeId));
|
this.player.sendPacket(new PacketCookRecipeDataNotify(recipeId));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************
|
/********************
|
||||||
* Perform cooking.
|
* Perform cooking.
|
||||||
********************/
|
********************/
|
||||||
|
private double getSpecialtyChance(ItemData cookedItem) {
|
||||||
|
// Chances taken from the Wiki.
|
||||||
|
return switch (cookedItem.getRankLevel()) {
|
||||||
|
case 1 -> 0.25;
|
||||||
|
case 2 -> 0.2;
|
||||||
|
case 3 -> 0.15;
|
||||||
|
default -> 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public void handlePlayerCookReq(PlayerCookReq req) {
|
public void handlePlayerCookReq(PlayerCookReq req) {
|
||||||
// Get info from the request.
|
// Get info from the request.
|
||||||
int recipeId = req.getRecipeId();
|
int recipeId = req.getRecipeId();
|
||||||
int quality = req.getQteQuality();
|
int quality = req.getQteQuality();
|
||||||
int count = req.getCookCount();
|
int count = req.getCookCount();
|
||||||
|
int avatar = req.getAssistAvatar();
|
||||||
|
|
||||||
// Get recipe data.
|
// Get recipe data.
|
||||||
var recipeData = GameData.getCookRecipeDataMap().get(recipeId);
|
var recipeData = GameData.getCookRecipeDataMap().get(recipeId);
|
||||||
@ -85,12 +97,12 @@ public class CookingManager {
|
|||||||
int proficiency = this.player.getUnlockedRecipies().getOrDefault(recipeId, 0);
|
int proficiency = this.player.getUnlockedRecipies().getOrDefault(recipeId, 0);
|
||||||
|
|
||||||
// Try consuming materials.
|
// Try consuming materials.
|
||||||
boolean success = player.getInventory().payItems(recipeData.getInputVec().toArray(new ItemParamData[0]), count, ActionReason.Cook);
|
boolean success = player.getInventory().payItems(recipeData.getInputVec().toArray(new ItemParamData[0]), count, ActionReason.Cook);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
this.player.sendPacket(new PacketPlayerCookRsp(Retcode.RET_FAIL)); //ToDo: Probably the wrong return code.
|
this.player.sendPacket(new PacketPlayerCookRsp(Retcode.RET_FAIL));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtain results.
|
// Get result item information.
|
||||||
int qualityIndex =
|
int qualityIndex =
|
||||||
quality == 0
|
quality == 0
|
||||||
? 2
|
? 2
|
||||||
@ -99,8 +111,34 @@ public class CookingManager {
|
|||||||
ItemParamData resultParam = recipeData.getQualityOutputVec().get(qualityIndex);
|
ItemParamData resultParam = recipeData.getQualityOutputVec().get(qualityIndex);
|
||||||
ItemData resultItemData = GameData.getItemDataMap().get(resultParam.getItemId());
|
ItemData resultItemData = GameData.getItemDataMap().get(resultParam.getItemId());
|
||||||
|
|
||||||
GameItem cookResult = new GameItem(resultItemData, resultParam.getCount() * count);
|
// Handle character's specialties.
|
||||||
this.player.getInventory().addItem(cookResult);
|
int specialtyCount = 0;
|
||||||
|
double specialtyChance = this.getSpecialtyChance(resultItemData);
|
||||||
|
|
||||||
|
var bonusData = GameData.getCookBonusDataMap().get(avatar);
|
||||||
|
if (bonusData != null && recipeId == bonusData.getRecipeId()) {
|
||||||
|
// Roll for specialy replacements.
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if (ThreadLocalRandom.current().nextDouble() <= specialtyChance) {
|
||||||
|
specialtyCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtain results.
|
||||||
|
List<GameItem> cookResults = new ArrayList<>();
|
||||||
|
|
||||||
|
int normalCount = count - specialtyCount;
|
||||||
|
GameItem cookResultNormal = new GameItem(resultItemData, resultParam.getCount() * normalCount);
|
||||||
|
cookResults.add(cookResultNormal);
|
||||||
|
this.player.getInventory().addItem(cookResultNormal);
|
||||||
|
|
||||||
|
if (specialtyCount > 0) {
|
||||||
|
ItemData specialtyItemData = GameData.getItemDataMap().get(bonusData.getReplacementItemId());
|
||||||
|
GameItem cookResultSpecialty = new GameItem(specialtyItemData, resultParam.getCount() * specialtyCount);
|
||||||
|
cookResults.add(cookResultSpecialty);
|
||||||
|
this.player.getInventory().addItem(cookResultSpecialty);
|
||||||
|
}
|
||||||
|
|
||||||
// Increase player proficiency, if this was a manual perfect cook.
|
// Increase player proficiency, if this was a manual perfect cook.
|
||||||
if (quality == MANUAL_PERFECT_COOK_QUALITY) {
|
if (quality == MANUAL_PERFECT_COOK_QUALITY) {
|
||||||
@ -109,10 +147,9 @@ public class CookingManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send response.
|
// Send response.
|
||||||
this.player.sendPacket(new PacketPlayerCookRsp(cookResult, quality, count, recipeId, proficiency));
|
this.player.sendPacket(new PacketPlayerCookRsp(cookResults, quality, count, recipeId, proficiency));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/********************
|
/********************
|
||||||
* Cooking arguments.
|
* Cooking arguments.
|
||||||
********************/
|
********************/
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package emu.grasscutter.server.packet.send;
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import emu.grasscutter.game.inventory.GameItem;
|
import emu.grasscutter.game.inventory.GameItem;
|
||||||
import emu.grasscutter.net.packet.BasePacket;
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
@ -19,23 +21,25 @@ public class PacketPlayerCookRsp extends BasePacket {
|
|||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PacketPlayerCookRsp(GameItem output, int quality, int count, int recipeId, int proficiency) {
|
public PacketPlayerCookRsp(List<GameItem> output, int quality, int count, int recipeId, int proficiency) {
|
||||||
super(PacketOpcodes.PlayerCookRsp);
|
super(PacketOpcodes.PlayerCookRsp);
|
||||||
|
|
||||||
PlayerCookRsp proto = PlayerCookRsp.newBuilder()
|
PlayerCookRsp.Builder proto = PlayerCookRsp.newBuilder()
|
||||||
.setRecipeData(
|
.setRecipeData(
|
||||||
CookRecipeData.newBuilder()
|
CookRecipeData.newBuilder()
|
||||||
.setRecipeId(recipeId)
|
.setRecipeId(recipeId)
|
||||||
.setProficiency(proficiency)
|
.setProficiency(proficiency)
|
||||||
)
|
)
|
||||||
.setQteQuality(quality)
|
.setQteQuality(quality)
|
||||||
.addItemList(
|
.setCookCount(count);
|
||||||
|
|
||||||
|
for (var item : output) {
|
||||||
|
proto.addItemList(
|
||||||
ItemParam.newBuilder()
|
ItemParam.newBuilder()
|
||||||
.setItemId(output.getItemId())
|
.setItemId(item.getItemId())
|
||||||
.setCount(output.getCount())
|
.setCount(item.getCount())
|
||||||
)
|
);
|
||||||
.setCookCount(count)
|
}
|
||||||
.build();
|
|
||||||
|
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user