Commit 13a7f086 authored by GanyusLeftHorn's avatar GanyusLeftHorn Committed by Melledy
Browse files

Add character's specialty food.

parent d95a30a1
...@@ -99,6 +99,7 @@ public class GameData { ...@@ -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 { ...@@ -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;
}
} }
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; ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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.
********************/ ********************/
......
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 { ...@@ -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);
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment