]> git.localhorst.tv Git - l2e.git/blob - src/common/Capsule.cpp
put stat increments in level ladder
[l2e.git] / src / common / Capsule.cpp
1 #include "Capsule.h"
2
3 #include "Item.h"
4 #include "LevelUp.h"
5 #include "Spell.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() - 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                 const LevelUp &lup = levelLadder[level - 1];
96                 int added = NextLevel();
97                 experience += added;
98                 remain -= added;
99                 ++level;
100                 maxHealth += lup.MaxHealth();
101                 stats += lup;
102
103                 info.push_back(Upgrade(name, Upgrade::LEVEL_UP, level));
104
105                 if (lup.MaxHealth() > 0) {
106                         info.push_back(Upgrade(name, Upgrade::MAX_HEALTH, lup.MaxHealth()));
107                 }
108                 if (lup.Attack() > 0) {
109                         info.push_back(Upgrade(name, Upgrade::ATTACK, lup.Attack()));
110                 }
111                 if (lup.Defense() > 0) {
112                         info.push_back(Upgrade(name, Upgrade::DEFENSE, lup.Defense()));
113                 }
114                 if (lup.Strength() > 0) {
115                         info.push_back(Upgrade(name, Upgrade::STRENGTH, lup.Strength()));
116                 }
117                 if (lup.Agility() > 0) {
118                         info.push_back(Upgrade(name, Upgrade::AGILITY, lup.Agility()));
119                 }
120                 if (lup.Intelligence() > 0) {
121                         info.push_back(Upgrade(name, Upgrade::INTELLIGENCE, lup.Intelligence()));
122                 }
123                 if (lup.Gut() > 0) {
124                         info.push_back(Upgrade(name, Upgrade::GUT, lup.Gut()));
125                 }
126                 if (lup.MagicResistance() > 0) {
127                         info.push_back(Upgrade(name, Upgrade::MAGIC_RESISTANCE, lup.MagicResistance()));
128                 }
129
130                 if (level > numLevels) {
131                         info.push_back(Upgrade(
132                                         name, Upgrade::LEVEL_NEXT, NextLevel()));
133                         return;
134                 }
135         }
136         experience += remain;
137         info.push_back(Upgrade(
138                         name, Upgrade::LEVEL_NEXT, NextLevel()));
139 }
140
141
142 void Capsule::UpgradeClass() {
143         ++maxClass;
144         ++curClass;
145 }
146
147 void Capsule::NextClass() {
148         if (maxClass == numClasses) {
149                 return;
150         }
151         ++curClass;
152         if (curClass >= maxClass) {
153                 curClass = 0;
154         }
155 }
156
157 void Capsule::PreviousClass() {
158         if (maxClass == numClasses) {
159                 return;
160         }
161         --curClass;
162         if (curClass < 0) {
163                 curClass = maxClass - 1;
164         }
165 }
166
167 void Capsule::SetClass(int index) {
168         if (maxClass == numClasses) {
169                 return;
170         }
171         curClass = index;
172         if (curClass < 0 ) {
173                 curClass = 0;
174         }
175         if (curClass >= maxClass) {
176                 curClass = maxClass - 1;
177         }
178 }
179
180
181 Sprite *Capsule::BattleSprite() {
182         return GetClass().battleSprite;
183 }
184
185 const Sprite *Capsule::BattleSprite() const {
186         return GetClass().battleSprite;
187 }
188
189 Animation *Capsule::MeleeAnimation() {
190         return GetClass().meleeAnimation;
191 }
192
193 Animation *Capsule::AttackAnimation() {
194         return GetClass().attackAnimation;
195 }
196
197 Animation *Capsule::SpellAnimation() {
198         return GetClass().spellAnimation;
199 }
200
201
202 Capsule::Class &Capsule::GetClass() {
203         assert(classes && curClass < numClasses);
204         return classes[curClass];
205 }
206
207 const Capsule::Class &Capsule::GetClass() const {
208         assert(classes && curClass < numClasses);
209         return classes[curClass];
210 }
211
212
213 int Capsule::HungerEmpty() const {
214         return HungerTotal() - HungerFull();
215 }
216
217 int Capsule::HungerTotal() const {
218         return GetClass().hunger;
219 }
220
221 int Capsule::HungerFull() const {
222         return GetClass().hungerFull;
223 }
224
225 bool Capsule::IsHungry() const {
226         return HungerEmpty();
227 }
228
229 void Capsule::Feed(const common::Item *item) {
230         // TODO: find out how to calculate an item's feed value
231         // TODO: an item the capsule favors (changes on every feed and after every
232         //       battle) doubles the value
233         int value = 1;
234         GetClass().hungerFull += value;
235         if (GetClass().hungerFull >= GetClass().hunger) {
236                 GetClass().hungerFull = GetClass().hunger;
237                 UpgradeClass();
238         }
239 }
240
241 const common::Item *Capsule::UpgradeItem() const {
242         return GetClass().upgradeItem;
243 }
244
245 void Capsule::UpgradeSpecial() {
246         maxClass = GetClass().upgradeClass + 1;
247         curClass = GetClass().upgradeClass;
248 }
249
250
251 Capsule::Class::Class()
252 : name(0)
253 , tribe(0)
254 , battleSprite(0)
255 , meleeAnimation(0)
256 , attackAnimation(0)
257 , spellAnimation(0)
258
259
260 , upgradeItem(0)
261 , upgradeClass(0)
262 , hunger(32)
263 , hungerFull(0)
264
265 , healthBoost(0) {
266         attacks[0] = 0;
267         attacks[1] = 0;
268         attacks[2] = 0;
269 }
270
271
272 void Capsule::CreateTypeDescription() {
273         Capsule c;
274
275         TypeDescription &td(TypeDescription::Create(TYPE_ID, "Capsule"));
276         td.SetConstructor(&Construct);
277         td.SetSize(sizeof(Capsule));
278
279         td.AddField("name", FieldDescription(((char *)&c.name) - ((char *)&c), Interpreter::STRING_ID).SetReferenced());
280         td.AddField("alignment", FieldDescription(((char *)&c.alignment) - ((char *)&c), Interpreter::STRING_ID).SetReferenced());
281
282         td.AddField("alignmentCursor", FieldDescription(((char *)&c.alignmentCursor) - ((char *)&c), Interpreter::VECTOR_ID));
283         td.AddField("alignmentSprite", FieldDescription(((char *)&c.alignmentSprite) - ((char *)&c), Sprite::TYPE_ID).SetReferenced());
284
285         td.AddField("maxHealth", FieldDescription(((char *)&c.maxHealth) - ((char *)&c), Interpreter::NUMBER_ID));
286
287         td.AddField("stats", FieldDescription(((char *)&c.stats) - ((char *)&c), Stats::TYPE_ID));
288
289         td.AddField("level", FieldDescription(((char *)&c.level) - ((char *)&c), Interpreter::NUMBER_ID));
290         td.AddField("experience", FieldDescription(((char *)&c.experience) - ((char *)&c), Interpreter::NUMBER_ID));
291
292         td.AddField("ladder", FieldDescription(((char *)&c.levelLadder) - ((char *)&c), LevelUp::TYPE_ID).SetAggregate());
293
294         td.AddField("classes", FieldDescription(((char *)&c.classes) - ((char *)&c), Class::TYPE_ID).SetAggregate());
295         td.AddField("class", FieldDescription(((char *)&c.curClass) - ((char *)&c), Interpreter::NUMBER_ID));
296         td.AddField("maxClass", FieldDescription(((char *)&c.maxClass) - ((char *)&c), Interpreter::NUMBER_ID));
297
298         Class::CreateTypeDescription();
299 }
300
301 void Capsule::Construct(void *data) {
302         new (data) Capsule;
303 }
304
305
306 void Capsule::Class::CreateTypeDescription() {
307         Class c;
308
309         TypeDescription &td(TypeDescription::Create(TYPE_ID, "CapsuleClass"));
310         td.SetConstructor(&Construct);
311         td.SetSize(sizeof(Class));
312
313         td.AddField("name", FieldDescription(((char *)&c.name) - ((char *)&c), Interpreter::STRING_ID).SetReferenced());
314         td.AddField("tribe", FieldDescription(((char *)&c.tribe) - ((char *)&c), Interpreter::STRING_ID).SetReferenced());
315
316         td.AddField("attack1", FieldDescription(((char *)&c.attacks[0]) - ((char *)&c), Spell::TYPE_ID).SetReferenced());
317         td.AddField("attack2", FieldDescription(((char *)&c.attacks[1]) - ((char *)&c), Spell::TYPE_ID).SetReferenced());
318         td.AddField("attack3", FieldDescription(((char *)&c.attacks[2]) - ((char *)&c), Spell::TYPE_ID).SetReferenced());
319
320         td.AddField("battleSprite", FieldDescription(((char *)&c.battleSprite) - ((char *)&c), Sprite::TYPE_ID).SetReferenced());
321         td.AddField("meleeAnimation", FieldDescription(((char *)&c.meleeAnimation) - ((char *)&c), Animation::TYPE_ID).SetReferenced());
322         td.AddField("attackAnimation", FieldDescription(((char *)&c.attackAnimation) - ((char *)&c), Animation::TYPE_ID).SetReferenced());
323         td.AddField("spellAnimation", FieldDescription(((char *)&c.spellAnimation) - ((char *)&c), Animation::TYPE_ID).SetReferenced());
324
325         td.AddField("upgradeItem", FieldDescription(((char *)&c.upgradeItem) - ((char *)&c), common::Item::TYPE_ID).SetReferenced());
326         td.AddField("upgradeClass", FieldDescription(((char *)&c.upgradeClass) - ((char *)&c), Interpreter::NUMBER_ID));
327         td.AddField("hunger", FieldDescription(((char *)&c.hunger) - ((char *)&c), Interpreter::NUMBER_ID));
328
329         td.AddField("healthBoost", FieldDescription(((char *)&c.healthBoost) - ((char *)&c), Interpreter::NUMBER_ID));
330         td.AddField("statBoost", FieldDescription(((char *)&c.statBoost) - ((char *)&c), Stats::TYPE_ID));
331 }
332
333 void Capsule::Class::Construct(void *data) {
334         new (data) Capsule::Class;
335 }
336
337 }