修复宠物伤害异常问题
This commit is contained in:
+157
-30
@@ -169,6 +169,7 @@ enum class Mode {
|
||||
Pause,
|
||||
Dialogue,
|
||||
StarterChoice,
|
||||
StarterHealService,
|
||||
MerchantGreeting,
|
||||
Battle,
|
||||
Shop,
|
||||
@@ -257,6 +258,7 @@ struct Runtime {
|
||||
int selectedMapIndex = 0;
|
||||
int selectedInventorySlot = 0;
|
||||
int selectedStarterSlot = 0;
|
||||
int selectedStarterServiceSlot = 0;
|
||||
int selectedQuestSlot = 0;
|
||||
int selectedShopSlot = 0;
|
||||
int selectedPetDexSlot = 0;
|
||||
@@ -309,6 +311,7 @@ struct Runtime {
|
||||
|
||||
bool SaveRuntime(Runtime& rt);
|
||||
std::string VisibleNpcName(const std::string& npcName);
|
||||
void PlayRuntimeSound(Runtime& rt, const std::string& purpose);
|
||||
|
||||
struct StarterPetOption {
|
||||
std::string speciesName;
|
||||
@@ -325,6 +328,8 @@ const std::vector<StarterPetOption>& StarterPetOptions()
|
||||
return options;
|
||||
}
|
||||
|
||||
constexpr int kStarterTeamRestoreCost = 120;
|
||||
|
||||
std::filesystem::path DetectRoot(int argc, char** argv)
|
||||
{
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
@@ -450,11 +455,20 @@ void BindStarterNpc(Runtime& rt)
|
||||
}
|
||||
}
|
||||
|
||||
bool IsStarterNpcIdentity(const Runtime& rt, const Entity& npc)
|
||||
{
|
||||
return !rt.starterNpcName.empty()
|
||||
&& npc.name == rt.starterNpcName;
|
||||
}
|
||||
|
||||
bool IsStarterNpc(const Runtime& rt, const Entity& npc)
|
||||
{
|
||||
return !IsStarterChoiceComplete(rt)
|
||||
&& !rt.starterNpcName.empty()
|
||||
&& npc.name == rt.starterNpcName;
|
||||
return !IsStarterChoiceComplete(rt) && IsStarterNpcIdentity(rt, npc);
|
||||
}
|
||||
|
||||
bool ShouldOfferStarterHealService(const Runtime& rt, const Entity& npc)
|
||||
{
|
||||
return IsStarterChoiceComplete(rt) && IsStarterNpcIdentity(rt, npc);
|
||||
}
|
||||
|
||||
bool ShouldOpenStarterChoiceAfterFunction(const Runtime& rt, const Entity& npc, const std::string& functionName)
|
||||
@@ -469,6 +483,13 @@ void OpenStarterChoice(Runtime& rt, const Entity& npc)
|
||||
rt.message = VisibleNpcName(npc.name) + "让你选择初始宠物";
|
||||
}
|
||||
|
||||
void OpenStarterHealService(Runtime& rt, const Entity& npc)
|
||||
{
|
||||
rt.mode = Mode::StarterHealService;
|
||||
rt.selectedStarterServiceSlot = 0;
|
||||
rt.message = VisibleNpcName(npc.name) + "可以恢复你的出战队伍";
|
||||
}
|
||||
|
||||
void AwardStarterPet(Runtime& rt, const std::string& speciesName)
|
||||
{
|
||||
const EntityPreset starter = LoadEntityPreset(rt.root, speciesName);
|
||||
@@ -491,15 +512,6 @@ const QuestObjectiveProgress* FirstIncompleteObjective(const QuestRuntime& quest
|
||||
return objective == questRuntime.objectives.end() ? nullptr : &*objective;
|
||||
}
|
||||
|
||||
void RestoreActivePetForRetreat(Runtime& rt)
|
||||
{
|
||||
if (rt.team.pets.empty()) {
|
||||
return;
|
||||
}
|
||||
Pet& active = rt.team.pets.front();
|
||||
active.hp = std::max(active.hp, std::max(1, active.maxHp / 2));
|
||||
}
|
||||
|
||||
std::filesystem::path GuiTexture(const std::filesystem::path& root, const std::string& relative)
|
||||
{
|
||||
return root / "assets/ui" / relative;
|
||||
@@ -4094,6 +4106,36 @@ void DrawMerchantGreeting(Runtime& rt, Font font)
|
||||
DrawDialogueButton(rt, font, "继续", {1102.0f, 596.0f});
|
||||
}
|
||||
|
||||
void DrawStarterHealService(Runtime& rt, Font font)
|
||||
{
|
||||
DrawDialogueBox(rt, {96.0f, 498.0f, 1088.0f, 166.0f});
|
||||
const std::string title = rt.nearbyNpc ? VisibleNpcName(rt.nearbyNpc->name) : "队伍恢复";
|
||||
DrawTextCn(font, title.c_str(), {142.0f, 520.0f}, 25.0f, Color{255, 255, 221, 255});
|
||||
DrawWrappedText(
|
||||
font,
|
||||
"巡逻队可以帮你的出战队伍恢复体力。体力为 0 的宠物恢复前不能设为首发。",
|
||||
{142.0f, 552.0f},
|
||||
20.0f,
|
||||
850.0f,
|
||||
Color{238, 216, 161, 255});
|
||||
const std::string options[] = {
|
||||
"恢复出战队伍 " + std::to_string(kStarterTeamRestoreCost) + " 金币",
|
||||
"继续对话",
|
||||
};
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
const bool selected = i == rt.selectedStarterServiceSlot;
|
||||
const std::string marker = selected ? "> " : " ";
|
||||
DrawTextCn(
|
||||
font,
|
||||
(marker + std::to_string(i + 1) + ". " + options[i]).c_str(),
|
||||
{166.0f, 594.0f + static_cast<float>(i) * 22.0f},
|
||||
18.0f,
|
||||
selected ? Color{255, 255, 221, 255} : Color{238, 216, 161, 255});
|
||||
}
|
||||
DrawTextCn(font, ("金币 " + std::to_string(rt.gold)).c_str(), {842.0f, 520.0f}, 18.0f, Color{193, 151, 71, 255});
|
||||
DrawTextCn(font, "上下键切换 确认键选择 关闭键返回", {730.0f, 640.0f}, 17.0f, Color{193, 151, 71, 255});
|
||||
}
|
||||
|
||||
void UpdateStarterChoice(Runtime& rt)
|
||||
{
|
||||
const int count = static_cast<int>(StarterPetOptions().size());
|
||||
@@ -4128,6 +4170,79 @@ void UpdateStarterChoice(Runtime& rt)
|
||||
}
|
||||
}
|
||||
|
||||
int EnterDialogueIndex(Runtime& rt, Entity& npc, int entryIndex, int fallbackIndex);
|
||||
|
||||
void StartNpcDialogue(Runtime& rt, Entity& npc)
|
||||
{
|
||||
std::string startFunction = ResolveDialogueStartFunction(
|
||||
npc.dialogue, rt.questRuntime.states.RawStates(), "OnStart");
|
||||
if (npc.playerScript.ends_with("Kael.gd")) {
|
||||
if (ShouldBlockKaelPetTrialStart(startFunction, rt.team)) {
|
||||
rt.message = "凯尔 请先捕捉一只野外宠物加入队伍 再回来汇报";
|
||||
return;
|
||||
}
|
||||
startFunction = ResolveKaelPetTrialStart(startFunction, rt.team);
|
||||
}
|
||||
ApplyQuestEvent(rt.questRuntime, QuestEvent::TalkedToNpc(npc.name));
|
||||
rt.mode = Mode::Dialogue;
|
||||
rt.dialogueCloseOnMenuReturn = false;
|
||||
auto start = npc.dialogue.functionStart.find(startFunction);
|
||||
if (start == npc.dialogue.functionStart.end()) {
|
||||
start = npc.dialogue.functionStart.find("OnStart");
|
||||
}
|
||||
rt.dialogueIndex = start != npc.dialogue.functionStart.end() ? start->second : 0;
|
||||
rt.dialogueIndex = EnterDialogueIndex(rt, npc, rt.dialogueIndex, rt.dialogueIndex);
|
||||
}
|
||||
|
||||
void UpdateStarterHealService(Runtime& rt)
|
||||
{
|
||||
if (IsKeyPressed(KEY_ESCAPE) || IsKeyPressed(KEY_B)) {
|
||||
rt.mode = Mode::Explore;
|
||||
return;
|
||||
}
|
||||
if (IsKeyPressed(KEY_UP) || IsKeyPressed(KEY_W) || IsKeyPressed(KEY_DOWN) || IsKeyPressed(KEY_S)) {
|
||||
rt.selectedStarterServiceSlot = 1 - std::clamp(rt.selectedStarterServiceSlot, 0, 1);
|
||||
}
|
||||
if (IsKeyPressed(KEY_ONE)) {
|
||||
rt.selectedStarterServiceSlot = 0;
|
||||
}
|
||||
if (IsKeyPressed(KEY_TWO)) {
|
||||
rt.selectedStarterServiceSlot = 1;
|
||||
}
|
||||
if (!IsKeyPressed(KEY_ENTER) && !IsKeyPressed(KEY_SPACE) && !IsKeyPressed(KEY_E)
|
||||
&& !IsKeyPressed(KEY_ONE) && !IsKeyPressed(KEY_TWO)) {
|
||||
return;
|
||||
}
|
||||
rt.selectedStarterServiceSlot = std::clamp(rt.selectedStarterServiceSlot, 0, 1);
|
||||
if (rt.selectedStarterServiceSlot == 1) {
|
||||
if (rt.nearbyNpc) {
|
||||
StartNpcDialogue(rt, *rt.nearbyNpc);
|
||||
} else {
|
||||
rt.mode = Mode::Explore;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (rt.team.pets.empty()) {
|
||||
rt.message = "没有可恢复的出战宠物";
|
||||
PlayRuntimeSound(rt, "hit");
|
||||
return;
|
||||
}
|
||||
if (rt.gold < kStarterTeamRestoreCost) {
|
||||
rt.message = "金币不足 需要 " + std::to_string(kStarterTeamRestoreCost);
|
||||
PlayRuntimeSound(rt, "hit");
|
||||
return;
|
||||
}
|
||||
if (!RestoreTeamToFull(rt.team)) {
|
||||
rt.message = "出战队伍体力已经满了";
|
||||
PlayRuntimeSound(rt, "hit");
|
||||
return;
|
||||
}
|
||||
rt.gold -= kStarterTeamRestoreCost;
|
||||
rt.message = "出战队伍已恢复 消耗 " + std::to_string(kStarterTeamRestoreCost) + " 金币";
|
||||
PlayRuntimeSound(rt, "heal");
|
||||
SaveRuntime(rt);
|
||||
}
|
||||
|
||||
void DrawWarpConfirm(Runtime& rt, Font font)
|
||||
{
|
||||
DrawDialogueBox(rt, {96.0f, 498.0f, 1088.0f, 166.0f});
|
||||
@@ -4462,7 +4577,6 @@ void StartBattle(Runtime& rt, int petIndex, bool playerFirstAction = false)
|
||||
rt.battleMenuIndex = 0;
|
||||
rt.battlePlayerFirstAction = playerFirstAction;
|
||||
rt.battle = {};
|
||||
RestoreActivePetForRetreat(rt);
|
||||
rt.battle.player = rt.team.pets.empty() ? MakePet("Lulea", 30, 7) : rt.team.pets.front();
|
||||
rt.battle.wild = rt.wildPets[petIndex].pet;
|
||||
ScheduleMonsterRespawn(rt, rt.wildPets[petIndex]);
|
||||
@@ -4930,6 +5044,11 @@ bool TryStartPetBattleThrow(Runtime& rt)
|
||||
rt.message = "没有可投出的首发宠物";
|
||||
return false;
|
||||
}
|
||||
if (rt.team.pets.front().hp <= 0) {
|
||||
rt.message = PetDisplayName(rt.team.pets.front().name) + " 体力为0 请先找凯尔恢复";
|
||||
PlayRuntimeSound(rt, "hit");
|
||||
return false;
|
||||
}
|
||||
const int targetIndex = FindCaptureThrowTarget(rt);
|
||||
if (targetIndex < 0) {
|
||||
return false;
|
||||
@@ -6233,24 +6352,11 @@ void UpdateExplore(Runtime& rt, float dt)
|
||||
rt.message = TonoriMerchantName(merchant) + "正在招呼你";
|
||||
return;
|
||||
}
|
||||
std::string startFunction = ResolveDialogueStartFunction(
|
||||
rt.nearbyNpc->dialogue, rt.questRuntime.states.RawStates(), "OnStart");
|
||||
if (rt.nearbyNpc->playerScript.ends_with("Kael.gd")) {
|
||||
if (ShouldBlockKaelPetTrialStart(startFunction, rt.team)) {
|
||||
rt.message = "凯尔 请先捕捉一只野外宠物加入队伍 再回来汇报";
|
||||
return;
|
||||
}
|
||||
startFunction = ResolveKaelPetTrialStart(startFunction, rt.team);
|
||||
if (ShouldOfferStarterHealService(rt, *rt.nearbyNpc)) {
|
||||
OpenStarterHealService(rt, *rt.nearbyNpc);
|
||||
return;
|
||||
}
|
||||
ApplyQuestEvent(rt.questRuntime, QuestEvent::TalkedToNpc(rt.nearbyNpc->name));
|
||||
rt.mode = Mode::Dialogue;
|
||||
rt.dialogueCloseOnMenuReturn = false;
|
||||
auto start = rt.nearbyNpc->dialogue.functionStart.find(startFunction);
|
||||
if (start == rt.nearbyNpc->dialogue.functionStart.end()) {
|
||||
start = rt.nearbyNpc->dialogue.functionStart.find("OnStart");
|
||||
}
|
||||
rt.dialogueIndex = start != rt.nearbyNpc->dialogue.functionStart.end() ? start->second : 0;
|
||||
rt.dialogueIndex = EnterDialogueIndex(rt, *rt.nearbyNpc, rt.dialogueIndex, rt.dialogueIndex);
|
||||
StartNpcDialogue(rt, *rt.nearbyNpc);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6288,6 +6394,11 @@ void UpdateExplore(Runtime& rt, float dt)
|
||||
rt.message = "先找" + ChineseTextOr(VisibleNpcName(rt.starterNpcName), "附近的训练员") + "选择初始宠物";
|
||||
return;
|
||||
}
|
||||
if (!rt.team.pets.empty() && rt.team.pets.front().hp <= 0) {
|
||||
rt.message = PetDisplayName(rt.team.pets.front().name) + " 体力为0 请先找凯尔恢复";
|
||||
PlayRuntimeSound(rt, "hit");
|
||||
return;
|
||||
}
|
||||
StartBattle(rt, i);
|
||||
return;
|
||||
}
|
||||
@@ -6835,6 +6946,12 @@ void UpdateInventory(Runtime& rt)
|
||||
}
|
||||
if (IsKeyPressed(KEY_ENTER)) {
|
||||
if (rt.inventoryPage == InventoryPage::Pets) {
|
||||
const Pet& selectedPet = rt.team.pets[static_cast<std::size_t>(rt.selectedInventorySlot)];
|
||||
if (selectedPet.hp <= 0) {
|
||||
rt.message = PetDisplayName(selectedPet.name) + " 体力为0 不能设为首发";
|
||||
PlayRuntimeSound(rt, "hit");
|
||||
return;
|
||||
}
|
||||
if (rt.selectedInventorySlot > 0) {
|
||||
std::rotate(
|
||||
rt.team.pets.begin(),
|
||||
@@ -6852,6 +6969,9 @@ void UpdateInventory(Runtime& rt)
|
||||
rt.message = PetDisplayName(species) + " 已加入出战队伍";
|
||||
RefreshProgress(rt);
|
||||
SaveRuntime(rt);
|
||||
} else {
|
||||
rt.message = PetDisplayName(species) + " 体力为0 不能加入出战队伍";
|
||||
PlayRuntimeSound(rt, "hit");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6968,6 +7088,9 @@ void UpdatePetDex(Runtime& rt)
|
||||
rt.message = PetDisplayName(selected.speciesName) + " 已设为出战宠物";
|
||||
RefreshProgress(rt);
|
||||
SaveRuntime(rt);
|
||||
} else if (selected.activeCount > 0 || selected.storageCount > 0) {
|
||||
rt.message = PetDisplayName(selected.speciesName) + " 体力为0 不能设为出战宠物";
|
||||
PlayRuntimeSound(rt, "hit");
|
||||
} else {
|
||||
rt.message = "还未拥有这只宠物";
|
||||
}
|
||||
@@ -7073,6 +7196,8 @@ int main(int argc, char** argv)
|
||||
UpdateDialogue(rt);
|
||||
} else if (rt.mode == Mode::StarterChoice) {
|
||||
UpdateStarterChoice(rt);
|
||||
} else if (rt.mode == Mode::StarterHealService) {
|
||||
UpdateStarterHealService(rt);
|
||||
} else if (rt.mode == Mode::MerchantGreeting) {
|
||||
UpdateMerchantGreeting(rt);
|
||||
} else if (rt.mode == Mode::Battle) {
|
||||
@@ -7300,6 +7425,8 @@ int main(int argc, char** argv)
|
||||
DrawDialogue(rt, font);
|
||||
} else if (rt.mode == Mode::StarterChoice) {
|
||||
DrawStarterChoice(rt, font);
|
||||
} else if (rt.mode == Mode::StarterHealService) {
|
||||
DrawStarterHealService(rt, font);
|
||||
} else if (rt.mode == Mode::MerchantGreeting) {
|
||||
DrawMerchantGreeting(rt, font);
|
||||
} else if (rt.mode == Mode::Shop) {
|
||||
|
||||
+16
-2
@@ -471,7 +471,7 @@ bool AddPet(Team& team, const Pet& pet)
|
||||
bool MoveFirstTeamPetToFront(Team& team, const std::string& speciesName)
|
||||
{
|
||||
const auto found = std::find_if(team.pets.begin(), team.pets.end(), [&](const Pet& pet) {
|
||||
return pet.name == speciesName;
|
||||
return pet.name == speciesName && pet.hp > 0;
|
||||
});
|
||||
if (found == team.pets.end()) {
|
||||
return false;
|
||||
@@ -483,7 +483,7 @@ bool MoveFirstTeamPetToFront(Team& team, const std::string& speciesName)
|
||||
bool ActivateStoredPet(Team& team, const std::string& speciesName)
|
||||
{
|
||||
const auto found = std::find_if(team.storage.begin(), team.storage.end(), [&](const Pet& pet) {
|
||||
return pet.name == speciesName;
|
||||
return pet.name == speciesName && pet.hp > 0;
|
||||
});
|
||||
if (found == team.storage.end()) {
|
||||
return false;
|
||||
@@ -501,6 +501,19 @@ bool ActivateStoredPet(Team& team, const std::string& speciesName)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RestoreTeamToFull(Team& team)
|
||||
{
|
||||
bool changed = false;
|
||||
for (Pet& pet : team.pets) {
|
||||
const int fullHp = std::max(1, pet.maxHp);
|
||||
if (pet.hp != fullHp) {
|
||||
pet.hp = fullHp;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
PetCollectionSummary BuildPetCollectionSummary(const Team& team)
|
||||
{
|
||||
std::set<std::string> uniqueSpecies;
|
||||
@@ -662,6 +675,7 @@ CaptureResult TryCapture(BattleState& battle, Team& team, float capturePower, fl
|
||||
if (capturePower >= 1.0f - chance) {
|
||||
const bool activeTeamFull = team.pets.size() >= Team::MaxPets;
|
||||
Pet captured = battle.wild;
|
||||
NormalizePetAfterLoad(captured);
|
||||
captured.hp = captured.maxHp;
|
||||
AddPet(team, captured);
|
||||
battle.finished = true;
|
||||
|
||||
@@ -131,6 +131,7 @@ float CatchChance(const Pet& target);
|
||||
bool AddPet(Team& team, const Pet& pet);
|
||||
bool MoveFirstTeamPetToFront(Team& team, const std::string& speciesName);
|
||||
bool ActivateStoredPet(Team& team, const std::string& speciesName);
|
||||
bool RestoreTeamToFull(Team& team);
|
||||
PetCollectionSummary BuildPetCollectionSummary(const Team& team);
|
||||
void RegisterPetSeen(PetJournal& journal, const std::string& speciesName);
|
||||
void RegisterPetCaught(PetJournal& journal, const std::string& speciesName);
|
||||
|
||||
Reference in New Issue
Block a user