]> git.localhorst.tv Git - l2e.git/blob - src/common/Capsule.cpp
moved upgrade process to battle class
[l2e.git] / src / common / Capsule.cpp
1 #include "Capsule.h"
2
3 #include "Item.h"
4 #include "Spell.h"
5 #include "Stats.h"
6 #include "Upgrade.h"
7 #include "../graphics/Animation.h"
8 #include "../graphics/Sprite.h"
9 #include "../loader/Interpreter.h"
10 #include "../loader/TypeDescription.h"
11
12 #include <cassert>
13
14 using common::Spell;
15 using common::Stats;
16 using graphics::Animation;
17 using graphics::Sprite;
18 using loader::FieldDescription;
19 using loader::Interpreter;
20 using loader::TypeDescription;
21 using std::vector;
22
23 namespace common {
24
25 Capsule::Capsule()
26 : name("")
27 , alignment("")
28
29 , alignmentSprite(0)
30
31 , maxHealth(0)
32
33 , level(1)
34 , experience(0)
35
36 , levelLadder(0)
37 , numLevels(0)
38
39 , classes(0)
40 , numClasses(0)
41 , curClass(-1)
42 , maxClass(0) {
43
44 }
45
46
47 const char *Capsule::ClassName() const {
48         return GetClass().name;
49 }
50
51 const char *Capsule::Tribe() const {
52         return GetClass().tribe;
53 }
54
55 const Spell *Capsule::Attack1() const {
56         return GetClass().attacks[0];
57 }
58
59 const Spell *Capsule::Attack2() const {
60         return GetClass().attacks[1];
61 }
62
63 const Spell *Capsule::Attack3() const {
64         return GetClass().attacks[2];
65 }
66
67
68 Uint16 Capsule::MaxHealth() const {
69         return maxHealth + GetClass().healthBoost;
70 }
71
72
73 Stats Capsule::GetStats() const {
74         return stats + GetClass().statBoost;
75 }
76
77 int Capsule::NextLevel() const {
78         int levelOffset(Level() - 1);
79         if (levelOffset < numLevels) {
80                 return levelLadder[levelOffset] - Experience();
81         } else {
82                 return 0;
83         }
84 }
85
86 void Capsule::AddExperience(int exp, vector<Upgrade> &info) {
87         if (level > numLevels) {
88                 // don't award any experience if at highest level
89                 info.push_back(Upgrade(
90                                 name, Upgrade::LEVEL_NEXT, NextLevel()));
91                 return;
92         }
93         int remain = exp;
94         while (remain >= NextLevel()) {
95                 int added = NextLevel();
96                 experience += added;
97                 remain -= added;
98                 ++level;
99
100                 info.push_back(Upgrade(name, Upgrade::LEVEL_UP, level));
101
102                 // TODO: upgrade attributes and push info
103
104                 if (level > numLevels) {
105                         info.push_back(Upgrade(
106                                         name, Upgrade::LEVEL_NEXT, NextLevel()));
107                         return;
108                 }
109         }
110         experience += remain;
111         info.push_back(Upgrade(
112                         name, Upgrade::LEVEL_NEXT, NextLevel()));
113 }
114
115
116 void Capsule::UpgradeClass() {
117         ++maxClass;
118         ++curClass;
119 }
120
121 void Capsule::NextClass() {
122         if (maxClass == numClasses) {
123                 return;
124         }
125         ++curClass;
126         if (curClass >= maxClass) {
127                 curClass = 0;
128         }
129 }
130
131 void Capsule::PreviousClass() {
132         if (maxClass == numClasses) {
133                 return;
134         }
135         --curClass;
136         if (curClass < 0) {
137                 curClass = maxClass - 1;
138         }
139 }
140
141 void Capsule::SetClass(int index) {
142         if (maxClass == numClasses) {
143                 return;
144         }
145         curClass = index;
146         if (curClass < 0 ) {
147                 curClass = 0;
148         }
149         if (curClass >= maxClass) {
150                 curClass = maxClass - 1;
151         }
152 }
153
154
155 Sprite *Capsule::BattleSprite() {
156         return GetClass().battleSprite;
157 }
158
159 const Sprite *Capsule::BattleSprite() const {
160         return GetClass().battleSprite;
161 }
162
163 Animation *Capsule::MeleeAnimation() {
164         return GetClass().meleeAnimation;
165 }
166
167 Animation *Capsule::AttackAnimation() {
168         return GetClass().attackAnimation;
169 }
170
171 Animation *Capsule::SpellAnimation() {
172         return GetClass().spellAnimation;
173 }
174
175
176 Capsule::Class &Capsule::GetClass() {
177         assert(classes && curClass < numClasses);
178         return classes[curClass];
179 }
180
181 const Capsule::Class &Capsule::GetClass() const {
182         assert(classes && curClass < numClasses);
183         return classes[curClass];
184 }
185
186
187 int Capsule::HungerEmpty() const {
188         return HungerTotal() - HungerFull();
189 }
190
191 int Capsule::HungerTotal() const {
192         return GetClass().hunger;
193 }
194
195 int Capsule::HungerFull() const {
196         return GetClass().hungerFull;
197 }
198
199 bool Capsule::IsHungry() const {
200         return HungerEmpty();
201 }
202
203 void Capsule::Feed(const common::Item *item) {
204         // TODO: find out how to calculate an item's feed value
205         // TODO: an item the capsule favors (changes on every feed and after every
206         //       battle) doubles the value
207         int value = 1;
208         GetClass().hungerFull += value;
209         if (GetClass().hungerFull >= GetClass().hunger) {
210                 GetClass().hungerFull = GetClass().hunger;
211                 UpgradeClass();
212         }
213 }
214
215 const common::Item *Capsule::UpgradeItem() const {
216         return GetClass().upgradeItem;
217 }
218
219 void Capsule::UpgradeSpecial() {
220         maxClass = GetClass().upgradeClass + 1;
221         curClass = GetClass().upgradeClass;
222 }
223
224
225 Capsule::Class::Class()
226 : name(0)
227 , tribe(0)
228 , battleSprite(0)
229 , meleeAnimation(0)
230 , attackAnimation(0)
231 , spellAnimation(0)
232
233
234 , upgradeItem(0)
235 , upgradeClass(0)
236 , hunger(32)
237 , hungerFull(0)
238
239 , healthBoost(0) {
240         attacks[0] = 0;
241         attacks[1] = 0;
242         attacks[2] = 0;
243 }
244
245
246 void Capsule::CreateTypeDescription() {
247         Capsule c;
248
249         TypeDescription &td(TypeDescription::Create(TYPE_ID, "Capsule"));
250         td.SetConstructor(&Construct);
251         td.SetSize(sizeof(Capsule));
252
253         td.AddField("name", FieldDescription(((char *)&c.name) - ((char *)&c), Interpreter::STRING_ID).SetReferenced());
254         td.AddField("alignment", FieldDescription(((char *)&c.alignment) - ((char *)&c), Interpreter::STRING_ID).SetReferenced());
255
256         td.AddField("alignmentCursor", FieldDescription(((char *)&c.alignmentCursor) - ((char *)&c), Interpreter::VECTOR_ID));
257         td.AddField("alignmentSprite", FieldDescription(((char *)&c.alignmentSprite) - ((char *)&c), Sprite::TYPE_ID).SetReferenced());
258
259         td.AddField("maxHealth", FieldDescription(((char *)&c.maxHealth) - ((char *)&c), Interpreter::NUMBER_ID));
260
261         td.AddField("stats", FieldDescription(((char *)&c.stats) - ((char *)&c), Stats::TYPE_ID));
262
263         td.AddField("level", FieldDescription(((char *)&c.level) - ((char *)&c), Interpreter::NUMBER_ID));
264         td.AddField("experience", FieldDescription(((char *)&c.experience) - ((char *)&c), Interpreter::NUMBER_ID));
265
266         td.AddField("ladder", FieldDescription(((char *)&c.levelLadder) - ((char *)&c), Interpreter::NUMBER_ID).SetAggregate());
267
268         td.AddField("classes", FieldDescription(((char *)&c.classes) - ((char *)&c), Class::TYPE_ID).SetAggregate());
269         td.AddField("class", FieldDescription(((char *)&c.curClass) - ((char *)&c), Interpreter::NUMBER_ID));
270         td.AddField("maxClass", FieldDescription(((char *)&c.maxClass) - ((char *)&c), Interpreter::NUMBER_ID));
271
272         Class::CreateTypeDescription();
273 }
274
275 void Capsule::Construct(void *data) {
276         new (data) Capsule;
277 }
278
279
280 void Capsule::Class::CreateTypeDescription() {
281         Class c;
282
283         TypeDescription &td(TypeDescription::Create(TYPE_ID, "CapsuleClass"));
284         td.SetConstructor(&Construct);
285         td.SetSize(sizeof(Class));
286
287         td.AddField("name", FieldDescription(((char *)&c.name) - ((char *)&c), Interpreter::STRING_ID).SetReferenced());
288         td.AddField("tribe", FieldDescription(((char *)&c.tribe) - ((char *)&c), Interpreter::STRING_ID).SetReferenced());
289
290         td.AddField("attack1", FieldDescription(((char *)&c.attacks[0]) - ((char *)&c), Spell::TYPE_ID).SetReferenced());
291         td.AddField("attack2", FieldDescription(((char *)&c.attacks[1]) - ((char *)&c), Spell::TYPE_ID).SetReferenced());
292         td.AddField("attack3", FieldDescription(((char *)&c.attacks[2]) - ((char *)&c), Spell::TYPE_ID).SetReferenced());
293
294         td.AddField("battleSprite", FieldDescription(((char *)&c.battleSprite) - ((char *)&c), Sprite::TYPE_ID).SetReferenced());
295         td.AddField("meleeAnimation", FieldDescription(((char *)&c.meleeAnimation) - ((char *)&c), Animation::TYPE_ID).SetReferenced());
296         td.AddField("attackAnimation", FieldDescription(((char *)&c.attackAnimation) - ((char *)&c), Animation::TYPE_ID).SetReferenced());
297         td.AddField("spellAnimation", FieldDescription(((char *)&c.spellAnimation) - ((char *)&c), Animation::TYPE_ID).SetReferenced());
298
299         td.AddField("upgradeItem", FieldDescription(((char *)&c.upgradeItem) - ((char *)&c), common::Item::TYPE_ID).SetReferenced());
300         td.AddField("upgradeClass", FieldDescription(((char *)&c.upgradeClass) - ((char *)&c), Interpreter::NUMBER_ID));
301         td.AddField("hunger", FieldDescription(((char *)&c.hunger) - ((char *)&c), Interpreter::NUMBER_ID));
302
303         td.AddField("healthBoost", FieldDescription(((char *)&c.healthBoost) - ((char *)&c), Interpreter::NUMBER_ID));
304         td.AddField("statBoost", FieldDescription(((char *)&c.statBoost) - ((char *)&c), Stats::TYPE_ID));
305 }
306
307 void Capsule::Class::Construct(void *data) {
308         new (data) Capsule::Class;
309 }
310
311 }