1 /*
2  * This file is part of EasyRPG Player.
3  *
4  * EasyRPG Player is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * EasyRPG Player is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 // Headers
19 #include "scene_equip.h"
20 #include "game_actors.h"
21 #include "game_party.h"
22 #include "game_system.h"
23 #include "game_screen.h"
24 #include "input.h"
25 #include "player.h"
26 #include <lcf/reader_util.h>
27 #include "scene_menu.h"
28 #include <lcf/rpg/item.h>
29 
Scene_Equip(Game_Actor & actor,int equip_index)30 Scene_Equip::Scene_Equip(Game_Actor& actor, int equip_index) :
31 	actor(actor),
32 	equip_index(equip_index) {
33 	type = Scene::Equip;
34 }
35 
Start()36 void Scene_Equip::Start() {
37 	// Create the windows
38 	help_window.reset(new Window_Help(0, 0, SCREEN_TARGET_WIDTH, 32));
39 	equipstatus_window.reset(new Window_EquipStatus(0, 32, 124, 96, actor.GetId()));
40 	equip_window.reset(new Window_Equip(124, 32, (SCREEN_TARGET_WIDTH-124),96, actor.GetId()));
41 
42 	equip_window->SetIndex(equip_index);
43 
44 	for (int i = 0; i < 5; ++i) {
45 		item_windows.push_back(std::make_shared<Window_EquipItem>(actor.GetId(), i));
46 	}
47 
48 	// Assign the help windows
49 	for (size_t i = 0; i < item_windows.size(); ++i) {
50 		item_windows[i]->SetVisible((unsigned)equip_window->GetIndex() == i);
51 		item_windows[i]->SetHelpWindow(help_window.get());
52 		item_windows[i]->SetActive(false);
53 		item_windows[i]->Refresh();
54 	}
55 	equip_window->SetHelpWindow(help_window.get());
56 }
57 
Update()58 void Scene_Equip::Update() {
59 	help_window->Update();
60 
61 	UpdateEquipWindow();
62 	UpdateStatusWindow();
63 	UpdateItemWindows();
64 
65 	if (equip_window->GetActive()) {
66 		UpdateEquipSelection();
67 	} else if (item_window->GetActive()) {
68 		UpdateItemSelection();
69 	}
70 }
71 
UpdateItemWindows()72 void Scene_Equip::UpdateItemWindows() {
73 	for (size_t i = 0; i < item_windows.size(); ++i) {
74 		item_windows[i]->SetVisible((unsigned)equip_window->GetIndex() == i);
75 		item_windows[i]->Update();
76 	}
77 
78 	item_window = item_windows[equip_window->GetIndex()];
79 }
80 
UpdateEquipWindow()81 void Scene_Equip::UpdateEquipWindow() {
82 	equip_window->Update();
83 }
84 
UpdateStatusWindow()85 void Scene_Equip::UpdateStatusWindow() {
86 	if (equip_window->GetActive()) {
87 		equipstatus_window->ClearParameters();
88 	} else if (item_window->GetActive()) {
89 		const lcf::rpg::Item* current_item = item_window->GetItem();
90 
91 		const auto eidx = equip_window->GetIndex();
92 
93 		auto atk = actor.GetBaseAtk(Game_Battler::WeaponAll, true, false);
94 		auto def = actor.GetBaseDef(Game_Battler::WeaponAll, true, false);
95 		auto spi = actor.GetBaseSpi(Game_Battler::WeaponAll, true, false);
96 		auto agi = actor.GetBaseAgi(Game_Battler::WeaponAll, true, false);
97 
98 		auto add_item = [&](const lcf::rpg::Item* item, int mod = 1) {
99 			if (item) {
100 				atk += item->atk_points1 * mod;
101 				def += item->def_points1 * mod;
102 				spi += item->spi_points1 * mod;
103 				agi += item->agi_points1 * mod;
104 			}
105 		};
106 
107 		for (int i = 1; i <= 5; i++) {
108 			auto* count_item = actor.GetEquipment(i);
109 			add_item(count_item, 1);
110 		}
111 
112 		auto* old_item = actor.GetEquipment(eidx + 1);
113 		// If its a weapon or shield, get the other hand
114 		const lcf::rpg::Item* other_old_item = nullptr;
115 		if (eidx == 0) {
116 			other_old_item = actor.GetEquipment(eidx + 2);
117 		} else if (eidx == 1) {
118 			other_old_item = actor.GetEquipment(eidx);
119 		}
120 
121 		add_item(old_item, -1);
122 		// If other hand had a two handed weapon, or we considering a 2 handed weapon, remove the other hand.
123 		if (current_item && other_old_item &&
124 				(other_old_item->two_handed || current_item->two_handed)) {
125 			add_item(other_old_item, -1);
126 		}
127 		add_item(current_item, 1);
128 
129 		int limit = actor.MaxStatBaseValue();
130 
131 		atk = Utils::Clamp(atk, 1, limit);
132 		def = Utils::Clamp(def, 1, limit);
133 		spi = Utils::Clamp(spi, 1, limit);
134 		agi = Utils::Clamp(agi, 1, limit);
135 
136 		atk = actor.CalcValueAfterAtkStates(atk);
137 		def = actor.CalcValueAfterDefStates(def);
138 		spi = actor.CalcValueAfterSpiStates(spi);
139 		agi = actor.CalcValueAfterAgiStates(agi);
140 
141 		equipstatus_window->SetNewParameters(atk, def, spi, agi);
142 
143 		equipstatus_window->Refresh();
144 	}
145 
146 	equipstatus_window->Update();
147 }
148 
CanRemoveEquipment(const Game_Actor & actor,int index)149 static bool CanRemoveEquipment(const Game_Actor& actor, int index) {
150 	if (actor.IsEquipmentFixed(true)) {
151 		return false;
152 	}
153 	auto* item = actor.GetEquipment(index + 1);
154 	if (item && item->cursed) {
155 		return false;
156 	}
157 	return true;
158 }
159 
UpdateEquipSelection()160 void Scene_Equip::UpdateEquipSelection() {
161 	if (Input::IsTriggered(Input::CANCEL)) {
162 		Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Cancel));
163 		Scene::Pop();
164 	} else if (Input::IsTriggered(Input::DECISION)) {
165 		if (!CanRemoveEquipment(actor, equip_window->GetIndex())) {
166 			Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Buzzer));
167 			return;
168 		}
169 
170 		Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision));
171 		equip_window->SetActive(false);
172 		item_window->SetActive(true);
173 		item_window->SetIndex(0);
174 	} else if (Main_Data::game_party->GetActors().size() > 1 && Input::IsTriggered(Input::RIGHT)) {
175 		Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Cursor));
176 		int actor_index = Main_Data::game_party->GetActorPositionInParty(actor.GetId());
177 		actor_index = (actor_index + 1) % Main_Data::game_party->GetActors().size();
178 		Scene::Push(std::make_shared<Scene_Equip>((*Main_Data::game_party)[actor_index], equip_window->GetIndex()), true);
179 	} else if (Main_Data::game_party->GetActors().size() > 1 && Input::IsTriggered(Input::LEFT)) {
180 		Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Cursor));
181 		int actor_index = Main_Data::game_party->GetActorPositionInParty(actor.GetId());
182 		actor_index = (actor_index + Main_Data::game_party->GetActors().size() - 1) % Main_Data::game_party->GetActors().size();
183 		Scene::Push(std::make_shared<Scene_Equip>((*Main_Data::game_party)[actor_index], equip_window->GetIndex()), true);
184 	}
185 }
186 
UpdateItemSelection()187 void Scene_Equip::UpdateItemSelection() {
188 	if (Input::IsTriggered(Input::CANCEL)) {
189 		Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Cancel));
190 		equip_window->SetActive(true);
191 		item_window->SetActive(false);
192 		item_window->SetIndex(-1);
193 	} else if (Input::IsTriggered(Input::DECISION)) {
194 		Main_Data::game_system->SePlay(Main_Data::game_system->GetSystemSE(Main_Data::game_system->SFX_Decision));
195 
196 		const lcf::rpg::Item* current_item = item_window->GetItem();
197 		int current_item_id = current_item ? current_item->ID : 0;
198 
199 		actor.ChangeEquipment(
200 			equip_window->GetIndex() + 1, current_item_id);
201 
202 		equip_window->SetActive(true);
203 		item_window->SetActive(false);
204 		item_window->SetIndex(-1);
205 
206 		equip_window->Refresh();
207 
208 		for (size_t i = 0; i < item_windows.size(); ++i) {
209 			item_windows[i]->Refresh();
210 		}
211 	}
212 }
213