summaryrefslogtreecommitdiff
path: root/enginecore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'enginecore.cpp')
-rw-r--r--enginecore.cpp835
1 files changed, 835 insertions, 0 deletions
diff --git a/enginecore.cpp b/enginecore.cpp
new file mode 100644
index 0000000..047511e
--- /dev/null
+++ b/enginecore.cpp
@@ -0,0 +1,835 @@
1#include "enginecore.h"
2
3DObject::DObject(){};
4
5DObject::DObject(string filename, double newx, double newy)
6{
7 image = NULL;
8 image = loadBMP(filename);
9 if(!image)
10 cout << "Problem loading file!" << endl;
11 x = newx;
12 y = newy;
13}
14
15DObject::DObject(SDL_Surface* newImage, double newx, double newy)
16{
17 image = NULL;
18 image = copyImage(newImage);
19 if(!image)
20 cout << "Problem loading file!" << endl;
21 x = newx;
22 y = newy;
23}
24
25DObject::DObject(const DObject &o)
26{
27 image = NULL;
28 image = copyImage(o.image);
29 if(!image)
30 cout << "Problem copying file!" << endl;
31 x = o.x;
32 y = o.y;
33}
34
35DObject::~DObject()
36{
37 SDL_FreeSurface(image);
38}
39
40void DObject::draw(SDL_Surface* screen)
41{
42 SDL_Rect position;
43 position.x = x - image->w / 2.0;
44 position.y = y - image->h / 2.0;
45 SDL_BlitSurface(image,NULL,screen,&position);
46}
47
48//checks if DObject is out of Bounds
49bool ooB(const DObject* o, SDL_Surface* screen)
50{
51 if(o->x < 0)
52 return true;
53 if(o->y < 0)
54 return true;
55 if(o->x > screen->w)
56 return true;
57 if(o->y > screen->h)
58 return true;
59 return false;
60}
61
62double armorF(double damage, double armor)
63{
64 if(armor > 0)
65 armor *= armor/(armor+damage);
66 damage *= pow(0.5,armor/50);
67 return damage;
68}
69
70
71Levelable::Levelable()
72{
73 exp = 0;
74 level = 1;
75 lin = 30;
76 quad = 10;
77 cube = 2;
78 next = lin;
79}
80
81int Levelable::addExp(double moreExp)
82{
83 int levelups = 0;
84 exp += moreExp;
85 while(exp > next)
86 {
87 levelups++;
88 level++;
89 next += lin;
90 lin += quad;
91 quad += cube;
92 }
93 return levelups;
94}
95
96int Levelable::getLevel()
97{
98 return level;
99}
100
101double Levelable::getExp()
102{
103 return exp;
104}
105
106double* Levelable::getExpPointer()
107{
108 return &exp;
109}
110
111
112Projectile::Projectile(SDL_Surface* newimage, double newx, double newy, double newdamage, double newcollisionSize, double newxSpeed, double newySpeed) : DObject(newimage, newx, newy)
113{
114 damage = newdamage;
115 collisionSize = newcollisionSize;
116 xSpeed = newxSpeed;
117 ySpeed = newySpeed;
118 armorPiercing = 0;
119}
120
121Projectile::Projectile(const Projectile& P) : DObject((DObject) P)
122{
123 damage = P.damage;
124 armorPiercing = P.armorPiercing;
125 collisionSize = P.collisionSize;
126 xSpeed = P.xSpeed;
127 ySpeed = P.ySpeed;
128}
129
130/*structure of a ProjectileFile
131data/projectile2.bmp #path of the imagefile
132data/sounds/spit #path of the soundfile without n.wav for int n
13310 #damage
1342 #armorPiercing
1351.4142 #collisionSize
136*/
137Projectile::Projectile(string filename, vector<Mix_Chunk*>& sounds)
138{
139 ifstream ins;
140 ins.open(filename.c_str());
141 if(!ins.is_open())
142 {
143 cout << "Error: Could not load from file " << filename << endl;
144 }
145 string imageFilename;
146 getline(ins, imageFilename);
147 image = loadBMP(imageFilename);
148 string soundPath;
149 getline(ins, soundPath);
150 bool good = true;
151 long long files = 1;
152 while(good)
153 {
154 string actualPath = soundPath + lltostr(files) + ".wav";
155 Mix_Chunk* temp = NULL;
156 temp = Mix_LoadWAV(actualPath.c_str());
157 if(temp == NULL)
158 good = false;
159 else
160 sounds.push_back(temp);
161 ++files;
162 }
163 ins >> damage;
164 ins >> armorPiercing;
165 ins >> collisionSize;
166}
167
168void Projectile::frame(double time)
169{
170 x += xSpeed*time;
171 y += ySpeed*time;
172}
173
174void Projectile::rotateAccordingly()
175{
176 double norm = sqrt(xSpeed*xSpeed + ySpeed*ySpeed);
177 if(norm != 0)
178 {
179 double angle = asin(xSpeed / norm);
180 if(ySpeed < 0)
181 {
182 angle = M_PI-angle;
183 }
184 SDL_Surface* temp = image;
185 image = rotozoomSurface(image,angle/M_PI*180,1,0);
186 SDL_FreeSurface(temp);
187 }
188}
189
190
191
192Item::Item(const Item& item):DObject((DObject) item)
193{
194 cost = item.cost;
195 sellable = item.sellable;
196}
197
198Item::Item(const DObject& dObject):DObject(dObject)
199{
200}
201
202SDL_Surface* Item::getImage()
203{
204 return image;
205}
206
207Weapon::Weapon(const Weapon& w):Item((Item) w)
208{
209 playSound = true;
210 for(int i = 0; i < (int) w.prototypes.size(); ++i)
211 {
212 prototypes.push_back(new Projectile(*w.prototypes[i]));
213 }
214 for(int i = 0; i < (int) w.sounds.size(); ++i)
215 {
216 vector<Mix_Chunk*> temp;
217 for(int j = 0; j < (int) w.sounds[i].size(); ++j)
218 {
219 temp.push_back(w.sounds[i][j]);
220 }
221 sounds.push_back(temp);
222 }
223 sellable = w.sellable;
224 cost = w.cost;
225 active = true;
226 energyUsage = w.energyUsage;
227 name = w.name;
228 cooldown = w.cooldown;
229 startTimer = w.startTimer;
230 currentTimer = startTimer;
231}
232
233/* structure of a Weaponfile:
234epic imbaweapon of massdestruction #name
235data/weapon89.bmp #filename of image of weapon
2360.5 #energyusage
2370 #sellable
23810000000 #cost
2392 #number of distinguished Projectiles
2401 #cooldown
2410.5 #startTimer
242data/projectile11.txt #path
2430 #xSpeed
244700 #-ySpeed
2455 #cooldown
2460 #startTimer
247data/projectile14.txt #path
2480 #xSpeed
249500 #-ySpeed
250*/
251Weapon::Weapon(string filename)
252{
253 playSound = true;
254 ifstream ins;
255 ins.open(filename.c_str());
256 if(!ins.is_open())
257 {
258 cout << "Error: Could not open file " << filename << endl;
259 }
260 getline(ins,name);
261 string imageFilename;
262 getline(ins, imageFilename);
263// cout << imageFilename << endl;
264 image = loadBMP(imageFilename);
265 active = true;
266 ins >> energyUsage;
267 ins >> sellable;
268 ins >> cost;
269 int Nprojectiles;
270 ins >> Nprojectiles;
271 for(;Nprojectiles;Nprojectiles--)
272 {
273 double temp;
274 ins >> temp;
275 cooldown.push_back(temp);
276 ins >> temp;
277 startTimer.push_back(temp);
278 string projectileFilename;
279 //this workaround discards all \n
280 char workaround;
281 ins >> workaround;
282 getline(ins,projectileFilename);
283 vector<Mix_Chunk*> projectileSounds;
284 prototypes.push_back(new Projectile(workaround + projectileFilename, projectileSounds));
285 ins >> prototypes[prototypes.size()-1]->xSpeed;
286 ins >> prototypes[prototypes.size()-1]->ySpeed;
287 prototypes[prototypes.size()-1]->ySpeed *= -1;
288 sounds.push_back(projectileSounds);
289 }
290 currentTimer = startTimer;
291 ins.close();
292 if(cost == 0)
293 cost = round_beautiful(estimateValue(*this));
294}
295
296Weapon::~Weapon()
297{
298 for(int i = 0; i < (int) prototypes.size(); ++i)
299 delete prototypes[i];
300}
301
302vector<Projectile*> Weapon::frame(double time)
303{
304 vector<Projectile*> result;
305 for(int i = 0; i < (int) prototypes.size(); ++i)
306 {
307 currentTimer[i] += time;
308 while(currentTimer[i] > cooldown[i])
309 {
310 Projectile* tempP = new Projectile(*prototypes[i]);
311 if(sounds[i].size() && playSound)
312 {
313 int temp = Mix_PlayChannel(-1,sounds[i][rand()%sounds[i].size()],0);
314 if(temp == -1)
315 {
316 cout << "there was an error playing sound of projectile" << " from weapon " << name << endl;
317 }
318 }
319 tempP->x = x;
320 tempP->y = y;
321 tempP->rotateAccordingly();
322 currentTimer[i] -= cooldown[i];
323 tempP->frame(currentTimer[i]);
324 result.push_back(tempP);
325 }
326 }
327 return result;
328}
329
330void Weapon::mirror()
331{
332 for(int i = 0; i < (int) prototypes.size(); ++i)
333 prototypes[i]->ySpeed *= -1;
334}
335
336double Weapon::getDPS() const
337{
338 double result = 0;
339 for(int i = 0; i < (int) prototypes.size(); ++i)
340 result += prototypes[i]->damage/cooldown[i];
341 return result;
342}
343
344double Weapon::getDPE() const
345{
346 if(energyUsage == 0)
347 return 0;
348 return getDPS()/energyUsage;
349}
350
351double estimateValue(const Weapon& w)
352{
353 double result = w.getDPS()*w.getDPS()*5;
354 if(w.getDPE() != 0)
355 result /= 0.3 + 1 / w.getDPE();
356 else
357 result /= 0.3;
358 return result;
359}
360
361void Upgradeable::setValue(double nvalue)
362{
363 value = nvalue;
364}
365
366double Upgradeable::getValue() const
367{
368 return value;
369}
370
371Upgradeable::Upgradeable()
372{
373 level = 1;
374 cost = 0;
375 maxLevel = 0;
376}
377
378Upgradeable::operator double() const
379{
380 return value;
381}
382
383Upgradeable& Upgradeable::operator=(const double& d)
384{
385 value = d;
386 return *this;
387}
388
389Upgradeable::Upgradeable(double nvalue)
390{
391 level = 1;
392 cost = 0;
393 maxLevel = 0;
394 value = nvalue;
395}
396
397void Upgradeable::upgrade()
398{
399 if(level == maxLevel)
400 {
401 cout << "Can't Upgrade! Already at max Level." << endl;
402 }
403 level++;
404 cost += cost * (3+level)/10.0;
405 value += 0.3*value;
406}
407
408
409void Upgradeable::save(ofstream& o)
410{
411 o << name << endl;
412 o << value << endl;
413 o << cost << endl;
414 o << level << endl;
415 o << maxLevel << endl;
416}
417
418void Upgradeable::load(ifstream& i)
419{
420 char workaround;
421 i >> workaround;
422 getline(i,name);
423 name = workaround + name;
424 i >> value;
425 i >> cost;
426 i >> level;
427 i >> maxLevel;
428}
429
430ifstream& operator>>(ifstream& ins, Upgradeable& u)
431{
432 double d;
433 ins >> d;
434 u = d;
435 return ins;
436}
437
438Ship::Ship(string filename,int x, int y):DObject(filename,x,y)
439{
440 collisionSize = image->w;
441}
442
443Ship::~Ship()
444{
445 for(int i = 0; i < (int) weapons.size();++i)
446 delete weapons[i];
447}
448
449vector<Projectile*> Ship::frame(double time)
450{
451 vector<Projectile*> result;
452 return result;
453}
454
455int Ship::hit(const Projectile& P)
456{
457 double tempArmor = 0;
458 if(armor > 0)
459 tempArmor = max(tempArmor,armor-P.armorPiercing);
460 hp -= armorF(P.damage,tempArmor);
461 if(hp < 0)
462 return 1;
463 return 0;
464}
465
466Ship::Ship(const Ship& s):DObject((DObject) s)
467{
468 name = s.name;
469 maxhp = s.maxhp;
470 hp = maxhp;
471 moveSpeed = s.moveSpeed;
472 collisionSize = s.collisionSize;
473 armor = s.armor;
474 for(int i = 0; i < (int) s.weapons.size(); ++i)
475 {
476 weapons.push_back(new Weapon(*s.weapons[i]));
477 slotPositions.push_back(s.slotPositions[i]);
478 }
479}
480
481
482EnemyShip::EnemyShip(const EnemyShip& s): Ship((Ship) s)
483{
484 path = s.path;
485 gold = s.gold;
486 exp = s.exp;
487 score = s.score;
488 current = 0;
489 if(!path.size())
490 {
491 path.push_back(make_pair(s.x,s.y));
492 }
493 x = path[0].first;
494 y = path[0].second;
495
496}
497
498/*structure of an EnemShipfile
499Tork Spacerocket #name
500data/images/tork_spacerocket.bmp #path of imagefile
5017 #maxhp
5025 #armor
50350 #moveSpeed
5044 #collisionSize
5053 #Gold
5063 #exp
5073 #score
5081 #number of weapons
5090 -1 #relative Position of weapon
510data/fireball.txt #path of weapon
511*/
512EnemyShip::EnemyShip(string filename)
513{
514 current = 0;
515 path.push_back(make_pair(0,0));
516 ifstream ins;
517 ins.open(filename.c_str());
518 if(!ins.is_open())
519 cout << "Error: Could not open enemyfile " << filename << endl;
520 getline(ins, name);
521 string imagePath;
522 getline(ins, imagePath);
523 image = loadBMP(imagePath);
524 ins >> maxhp;
525 hp = maxhp;
526 ins >> armor;
527 ins >> moveSpeed;
528 ins >> collisionSize;
529 ins >> gold;
530 ins >> exp;
531 ins >> score;
532 int Nweapons = 0;
533 ins >> Nweapons;
534 for(;Nweapons;Nweapons--)
535 {
536 double temp1, temp2;
537 ins >> temp1;
538 ins >> temp2;
539 slotPositions.push_back(make_pair(temp1,temp2));
540 //A workaround that helps discarting \n
541 char workaround;
542 ins >> workaround;
543 string weaponpath;
544 getline(ins, weaponpath);
545 weapons.push_back(new Weapon(workaround + weaponpath));
546 weapons[weapons.size()-1]->mirror();
547 }
548 if(!(exp || gold || score))
549 assignValue();
550}
551
552vector<Projectile*> EnemyShip::frame(double time)
553{
554 //adjusting position
555 while(current != path.size()-1 && path[current] == make_pair(x,y))
556 current++;
557 if(path[current] != make_pair(x,y))
558 {
559 double dirx = path[current].first - x;
560 double diry = path[current].second - y;
561 double norm = sqrt(dirx*dirx + diry*diry);
562 dirx /= norm;
563 diry /= norm;
564 if(norm < moveSpeed*time)
565 {
566 x = path[current].first;
567 y = path[current].second;
568 }
569 else
570 {
571 x += dirx * moveSpeed * time;
572 y += diry * moveSpeed * time;
573 }
574 }
575 for(int i = 0; i < (int) weapons.size(); ++i)
576 {
577 weapons[i]->x = x + slotPositions[i].first;
578 weapons[i]->y = y + slotPositions[i].second;
579// cout << weapons[i]->x << " " << weapons[i]->y << " weapon " << i << endl;
580 }
581
582
583 vector<Projectile*> result;
584 for(int i = 0; i < (int) weapons.size(); ++i)
585 {
586 vector<Projectile*> temp;
587 temp = weapons[i]->frame(time);
588 for(int j = 0; j < (int) temp.size(); ++j)
589 result.push_back(temp[j]);
590 }
591 return result;
592}
593
594void EnemyShip::assignValue()
595{
596 exp = 0;
597 for(int i = 0; i < (int) weapons.size(); ++i)
598 exp += weapons[i]->getDPS();
599// exp *= 4;
600 gold = maxhp * pow(2,armor/(50.0+maxhp/10))*2.5;
601 score = gold * moveSpeed / 140;
602 double sum = (gold + score + exp)/9;
603 exp = (int)(sqrt(exp+sum)+0.5);
604 gold = (int)(sqrt(gold+sum) +0.5);
605 score = (int)(sqrt(score+sum)+0.5);
606// cout << s.name << '\n';
607// cout << "gold: " << s.gold << " -> " << gold << '\n';
608// cout << "high: " << s.score << " -> " << high << '\n';
609// cout << "exp: " << s.exp << " -> " << exp << '\n';
610// cout << "sum: " << sum << '\n';
611}
612
613
614vector<Upgradeable*> UserShip::getUpgradeables()
615{
616 vector<Upgradeable*> result;
617 result.push_back(&maxhp);
618 result.push_back(&armor);
619 result.push_back(&maxEnergy);
620 result.push_back(&energyProduction);
621 result.push_back(&handling);
622 result.push_back(&moveSpeed);
623 return result;
624}
625
626vector<Projectile*> UserShip::frame(double time, SDL_Surface* screen)
627{
628 vector<Projectile*> result;
629 //adjust energy
630 energy += energyProduction*time;
631 if(energy > maxEnergy)
632 energy = maxEnergy;
633 if(shooting)
634 {
635 double energyNeed = 0;
636 for(int i = 0; i < (int) weapons.size(); ++i)
637 energyNeed += weapons[i]->energyUsage*time;
638 if(energyNeed < energy)
639 {
640 energy -= energyNeed;
641 for(int i = 0; i < (int) weapons.size(); ++i)
642 {
643 vector<Projectile*> temp;
644 temp = weapons[i]->frame(time);
645 for(int j = 0; j < (int) temp.size(); ++j)
646 result.push_back(temp[j]);
647 }
648 }
649 }
650
651 //adjust speed and position of the ship
652 double norm1 = sqrt(right*right + down*down);
653 double norm2 = sqrt(xSpeed*xSpeed + ySpeed*ySpeed);
654 double handconst = time*handling;
655 double speedconst = norm2/moveSpeed;
656 if(handconst * speedconst > norm2 || norm2 == 0)
657 {
658 xSpeed = 0;
659 ySpeed = 0;
660 }
661 else
662 {
663 xSpeed *= 1 - speedconst * handconst / norm2;
664 ySpeed *= 1 - speedconst * handconst / norm2 ;
665 }
666 norm2 = sqrt(xSpeed*xSpeed + ySpeed*ySpeed);
667 if(norm1 != 0)
668 {
669 xSpeed += handconst*right / norm1;
670 ySpeed += handconst*down / norm1;
671 }
672 else
673 {
674 if(handconst > norm2)
675 {
676 xSpeed = 0;
677 ySpeed = 0;
678 }
679 else
680 {
681 xSpeed -= handconst * xSpeed / norm2;
682 ySpeed -= handconst * ySpeed / norm2;
683 }
684 }
685// cout << xSpeed << " " << ySpeed << endl;
686 x += xSpeed*time;
687 y += ySpeed*time;
688 if(x - image->w/2.0 < 0)
689 {
690 x = image->w/2.0;
691 xSpeed = 0;
692 }
693 if(y - image->h/2.0 < 0)
694 {
695 y = image->h/2.0;
696 ySpeed = 0;
697 }
698 if(x + image->w/2.0 > screen->w)
699 {
700 x = screen->w - image->w/2.0;
701 xSpeed = 0;
702 }
703 if(y + image->h/2.0 > screen->h)
704 {
705 y = screen->h - image->h/2.0;
706 ySpeed = 0;
707 }
708 for(int i = 0; i < (int) weapons.size(); ++i)
709 {
710 weapons[i]->x = slotPositions[i].first + x;
711 weapons[i]->y = slotPositions[i].second + y;
712 }
713 return result;
714}
715
716/*structure of an UserShipfile
717small Fighter #name
718data/images/small_fighter.bmp #path of imagefile
719200 #cost
7207 #maxhp
72150 #armor
722200 #moveSpeed
723100 #handling
72410 #maxEnergy
7252 #energyProduction
7267 #collisionSize
7272 #number of weapons
7284 4 #relative Position of weapon
7293 #maxSize of attached weapon
730data/fireball.txt #path of weapon
7314 4 #relative Position of weapon
7323 #maxSize of attached weapon
733data/fireball.txt #path of weapon
734*/
735UserShip::UserShip(string filename)
736{
737 xSpeed = 0;
738 ySpeed = 0;
739 down = 0;
740 right = 0;
741 shooting = 0;
742 ifstream ins;
743 ins.open(filename.c_str());
744 if(!ins.is_open())
745 cout << "Error: Could not open userShip " << filename << endl;
746 getline(ins, name);
747 string imagePath;
748 getline(ins, imagePath);
749 image = loadBMP(imagePath);
750 ins >> cost;
751 ins >> maxhp;
752 maxhp.name = "Hitpoints";
753 maxhp.cost = cost/10;
754 hp = maxhp;
755 ins >> armor;
756 armor.name = "Armor";
757 armor.cost = cost/10;
758 ins >> moveSpeed;
759 moveSpeed.name = "Max Speed";
760 moveSpeed.cost = cost/10;
761 ins >> handling;
762 handling.name = "Acceleration";
763 handling.cost = cost/10;
764 ins >> maxEnergy;
765 maxEnergy.name = "Battery";
766 maxEnergy.cost = cost/10;
767 energy = maxEnergy;
768 ins >> energyProduction;
769 energyProduction.name = "Generator";
770 energyProduction.cost = cost/10;
771 ins >> collisionSize;
772 ins >> weaponSlots;
773 for(int i = 0; i < weaponSlots;i++)
774 {
775 double temp1, temp2;
776 ins >> temp1;
777 ins >> temp2;
778 slotPositions.push_back(make_pair(temp1,temp2));
779 ins >> temp1;
780 maxSize.push_back(temp1);
781 //A workaround that helps discarting \n
782 char workaround;
783 ins >> workaround;
784 string weaponpath;
785 getline(ins, weaponpath);
786 weapons.push_back(new Weapon(workaround + weaponpath));
787 }
788 if(cost == 0)
789 cost = round_beautiful(estimateValue(*this));
790 ins.close();
791}
792
793void UserShip::reset()
794{
795 hp = maxhp;
796 energy = maxEnergy;
797 xSpeed = 0;
798 ySpeed = 0;
799 for(int i = 0; i < (int) weapons.size(); ++i)
800 {
801 weapons[i]->playSound = false;
802 vector<Projectile*> dump = weapons[i]->frame((rand()%2000)/1000.0);
803 weapons[i]->playSound = true;
804 for(int j = 0; j < (int) dump.size(); ++j)
805 delete dump[j];
806 }
807}
808
809void UserShip::draw(SDL_Surface* screen)
810{
811 DObject::draw(screen);
812 for(int i = 0; i < (int) weapons.size(); ++i)
813 weapons[i]->draw(screen);
814}
815
816SDL_Surface* UserShip::getImage()
817{
818 return image;
819}
820
821double estimateValue(const UserShip& s)
822{
823 double result;
824 result = s.maxhp * pow(2,s.armor/(50.0+s.maxhp/10));
825 result *= result;
826 result += s.maxEnergy*s.maxEnergy + s.energyProduction * s.energyProduction * 50;
827 result *= s.weapons.size();
828 result *= s.moveSpeed / 300 * s.handling / 300;
829
830 return result/11;
831}
832
833
834
835