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