#include "enginecore.h" DObject::DObject(){}; DObject::DObject(string filename, double newx, double newy) { image = NULL; image = loadBMP(filename); if(!image) cout << "Problem loading file!" << endl; x = newx; y = newy; } DObject::DObject(SDL_Surface* newImage, double newx, double newy) { image = NULL; image = copyImage(newImage); if(!image) cout << "Problem loading file!" << endl; x = newx; y = newy; } DObject::DObject(const DObject &o) { image = NULL; image = copyImage(o.image); if(!image) cout << "Problem copying file!" << endl; x = o.x; y = o.y; } DObject::~DObject() { SDL_FreeSurface(image); } void DObject::draw(SDL_Surface* screen) { SDL_Rect position; position.x = x - image->w / 2.0; position.y = y - image->h / 2.0; SDL_BlitSurface(image,NULL,screen,&position); } //checks if DObject is out of Bounds bool ooB(const DObject* o, SDL_Surface* screen) { if(o->x < 0) return true; if(o->y < 0) return true; if(o->x > screen->w) return true; if(o->y > screen->h) return true; return false; } double armorF(double damage, double armor) { if(armor > 0) armor *= armor/(armor+damage); damage *= pow(0.5,armor/50); return damage; } Levelable::Levelable() { exp = 0; level = 1; lin = 30; quad = 10; cube = 2; next = lin; } int Levelable::addExp(double moreExp) { int levelups = 0; exp += moreExp; while(exp > next) { levelups++; level++; next += lin; lin += quad; quad += cube; } return levelups; } int Levelable::getLevel() { return level; } double Levelable::getExp() { return exp; } double* Levelable::getExpPointer() { return &exp; } Projectile::Projectile(SDL_Surface* newimage, double newx, double newy, double newdamage, double newcollisionSize, double newxSpeed, double newySpeed) : DObject(newimage, newx, newy) { damage = newdamage; collisionSize = newcollisionSize; xSpeed = newxSpeed; ySpeed = newySpeed; armorPiercing = 0; } Projectile::Projectile(const Projectile& P) : DObject((DObject) P) { damage = P.damage; armorPiercing = P.armorPiercing; collisionSize = P.collisionSize; xSpeed = P.xSpeed; ySpeed = P.ySpeed; } /*structure of a ProjectileFile data/projectile2.bmp #path of the imagefile data/sounds/spit #path of the soundfile without n.wav for int n 10 #damage 2 #armorPiercing 1.4142 #collisionSize */ Projectile::Projectile(string filename, vector& sounds) { ifstream ins; ins.open(filename.c_str()); if(!ins.is_open()) { cout << "Error: Could not load from file " << filename << endl; } string imageFilename; getline(ins, imageFilename); image = loadBMP(imageFilename); string soundPath; getline(ins, soundPath); bool good = true; long long files = 1; while(good) { string actualPath = soundPath + lltostr(files) + ".wav"; Mix_Chunk* temp = NULL; temp = Mix_LoadWAV(actualPath.c_str()); if(temp == NULL) good = false; else sounds.push_back(temp); ++files; } ins >> damage; ins >> armorPiercing; ins >> collisionSize; } void Projectile::frame(double time) { x += xSpeed*time; y += ySpeed*time; } void Projectile::rotateAccordingly() { double norm = sqrt(xSpeed*xSpeed + ySpeed*ySpeed); if(norm != 0) { double angle = asin(xSpeed / norm); if(ySpeed < 0) { angle = M_PI-angle; } SDL_Surface* temp = image; image = rotozoomSurface(image,angle/M_PI*180,1,0); SDL_FreeSurface(temp); } } Item::Item(const Item& item):DObject((DObject) item) { cost = item.cost; sellable = item.sellable; } Item::Item(const DObject& dObject):DObject(dObject) { } SDL_Surface* Item::getImage() { return image; } Weapon::Weapon(const Weapon& w):Item((Item) w) { playSound = true; for(int i = 0; i < (int) w.prototypes.size(); ++i) { prototypes.push_back(new Projectile(*w.prototypes[i])); } for(int i = 0; i < (int) w.sounds.size(); ++i) { vector temp; for(int j = 0; j < (int) w.sounds[i].size(); ++j) { temp.push_back(w.sounds[i][j]); } sounds.push_back(temp); } sellable = w.sellable; cost = w.cost; active = true; energyUsage = w.energyUsage; name = w.name; cooldown = w.cooldown; startTimer = w.startTimer; currentTimer = startTimer; } /* structure of a Weaponfile: epic imbaweapon of massdestruction #name data/weapon89.bmp #filename of image of weapon 0.5 #energyusage 0 #sellable 10000000 #cost 2 #number of distinguished Projectiles 1 #cooldown 0.5 #startTimer data/projectile11.txt #path 0 #xSpeed 700 #-ySpeed 5 #cooldown 0 #startTimer data/projectile14.txt #path 0 #xSpeed 500 #-ySpeed */ Weapon::Weapon(string filename) { playSound = true; ifstream ins; ins.open(filename.c_str()); if(!ins.is_open()) { cout << "Error: Could not open file " << filename << endl; } getline(ins,name); string imageFilename; getline(ins, imageFilename); // cout << imageFilename << endl; image = loadBMP(imageFilename); active = true; ins >> energyUsage; ins >> sellable; ins >> cost; int Nprojectiles; ins >> Nprojectiles; for(;Nprojectiles;Nprojectiles--) { double temp; ins >> temp; cooldown.push_back(temp); ins >> temp; startTimer.push_back(temp); string projectileFilename; //this workaround discards all \n char workaround; ins >> workaround; getline(ins,projectileFilename); vector projectileSounds; prototypes.push_back(new Projectile(workaround + projectileFilename, projectileSounds)); ins >> prototypes[prototypes.size()-1]->xSpeed; ins >> prototypes[prototypes.size()-1]->ySpeed; prototypes[prototypes.size()-1]->ySpeed *= -1; sounds.push_back(projectileSounds); } currentTimer = startTimer; ins.close(); if(cost == 0) cost = round_beautiful(estimateValue(*this)); } Weapon::~Weapon() { for(int i = 0; i < (int) prototypes.size(); ++i) delete prototypes[i]; } vector Weapon::frame(double time) { vector result; for(int i = 0; i < (int) prototypes.size(); ++i) { currentTimer[i] += time; while(currentTimer[i] > cooldown[i]) { Projectile* tempP = new Projectile(*prototypes[i]); if(sounds[i].size() && playSound) { int temp = Mix_PlayChannel(-1,sounds[i][rand()%sounds[i].size()],0); if(temp == -1) { cout << "there was an error playing sound of projectile" << " from weapon " << name << endl; } } tempP->x = x; tempP->y = y; tempP->rotateAccordingly(); currentTimer[i] -= cooldown[i]; tempP->frame(currentTimer[i]); result.push_back(tempP); } } return result; } void Weapon::mirror() { for(int i = 0; i < (int) prototypes.size(); ++i) prototypes[i]->ySpeed *= -1; } double Weapon::getDPS() const { double result = 0; for(int i = 0; i < (int) prototypes.size(); ++i) result += prototypes[i]->damage/cooldown[i]; return result; } double Weapon::getDPE() const { if(energyUsage == 0) return 0; return getDPS()/energyUsage; } double estimateValue(const Weapon& w) { double result = w.getDPS()*w.getDPS()*5; if(w.getDPE() != 0) result /= 0.3 + 1 / w.getDPE(); else result /= 0.3; return result; } void Upgradeable::setValue(double nvalue) { value = nvalue; } double Upgradeable::getValue() const { return value; } Upgradeable::Upgradeable() { level = 1; cost = 0; maxLevel = 0; } Upgradeable::operator double() const { return value; } Upgradeable& Upgradeable::operator=(const double& d) { value = d; return *this; } Upgradeable::Upgradeable(double nvalue) { level = 1; cost = 0; maxLevel = 0; value = nvalue; } void Upgradeable::upgrade() { if(level == maxLevel) { cout << "Can't Upgrade! Already at max Level." << endl; } level++; cost += cost * (3+level)/10.0; value += 0.3*value; } void Upgradeable::save(ofstream& o) { o << name << endl; o << value << endl; o << cost << endl; o << level << endl; o << maxLevel << endl; } void Upgradeable::load(ifstream& i) { char workaround; i >> workaround; getline(i,name); name = workaround + name; i >> value; i >> cost; i >> level; i >> maxLevel; } ifstream& operator>>(ifstream& ins, Upgradeable& u) { double d; ins >> d; u = d; return ins; } Ship::Ship(string filename,int x, int y):DObject(filename,x,y) { collisionSize = image->w; } Ship::~Ship() { for(int i = 0; i < (int) weapons.size();++i) delete weapons[i]; } vector Ship::frame(double time) { vector result; return result; } int Ship::hit(const Projectile& P) { double tempArmor = 0; if(armor > 0) tempArmor = max(tempArmor,armor-P.armorPiercing); hp -= armorF(P.damage,tempArmor); if(hp < 0) return 1; return 0; } Ship::Ship(const Ship& s):DObject((DObject) s) { name = s.name; maxhp = s.maxhp; hp = maxhp; moveSpeed = s.moveSpeed; collisionSize = s.collisionSize; armor = s.armor; for(int i = 0; i < (int) s.weapons.size(); ++i) { weapons.push_back(new Weapon(*s.weapons[i])); slotPositions.push_back(s.slotPositions[i]); } } EnemyShip::EnemyShip(const EnemyShip& s): Ship((Ship) s) { path = s.path; gold = s.gold; exp = s.exp; score = s.score; current = 0; if(!path.size()) { path.push_back(make_pair(s.x,s.y)); } x = path[0].first; y = path[0].second; } /*structure of an EnemShipfile Tork Spacerocket #name data/images/tork_spacerocket.bmp #path of imagefile 7 #maxhp 5 #armor 50 #moveSpeed 4 #collisionSize 3 #Gold 3 #exp 3 #score 1 #number of weapons 0 -1 #relative Position of weapon data/fireball.txt #path of weapon */ EnemyShip::EnemyShip(string filename) { current = 0; path.push_back(make_pair(0,0)); ifstream ins; ins.open(filename.c_str()); if(!ins.is_open()) cout << "Error: Could not open enemyfile " << filename << endl; getline(ins, name); string imagePath; getline(ins, imagePath); image = loadBMP(imagePath); ins >> maxhp; hp = maxhp; ins >> armor; ins >> moveSpeed; ins >> collisionSize; ins >> gold; ins >> exp; ins >> score; int Nweapons = 0; ins >> Nweapons; for(;Nweapons;Nweapons--) { double temp1, temp2; ins >> temp1; ins >> temp2; slotPositions.push_back(make_pair(temp1,temp2)); //A workaround that helps discarting \n char workaround; ins >> workaround; string weaponpath; getline(ins, weaponpath); weapons.push_back(new Weapon(workaround + weaponpath)); weapons[weapons.size()-1]->mirror(); } if(!(exp || gold || score)) assignValue(); } vector EnemyShip::frame(double time) { //adjusting position while(current != path.size()-1 && path[current] == make_pair(x,y)) current++; if(path[current] != make_pair(x,y)) { double dirx = path[current].first - x; double diry = path[current].second - y; double norm = sqrt(dirx*dirx + diry*diry); dirx /= norm; diry /= norm; if(norm < moveSpeed*time) { x = path[current].first; y = path[current].second; } else { x += dirx * moveSpeed * time; y += diry * moveSpeed * time; } } for(int i = 0; i < (int) weapons.size(); ++i) { weapons[i]->x = x + slotPositions[i].first; weapons[i]->y = y + slotPositions[i].second; // cout << weapons[i]->x << " " << weapons[i]->y << " weapon " << i << endl; } vector result; for(int i = 0; i < (int) weapons.size(); ++i) { vector temp; temp = weapons[i]->frame(time); for(int j = 0; j < (int) temp.size(); ++j) result.push_back(temp[j]); } return result; } void EnemyShip::assignValue() { exp = 0; for(int i = 0; i < (int) weapons.size(); ++i) exp += weapons[i]->getDPS(); // exp *= 4; gold = maxhp * pow(2,armor/(50.0+maxhp/10))*2.5; score = gold * moveSpeed / 140; double sum = (gold + score + exp)/9; exp = (int)(sqrt(exp+sum)+0.5); gold = (int)(sqrt(gold+sum) +0.5); score = (int)(sqrt(score+sum)+0.5); // cout << s.name << '\n'; // cout << "gold: " << s.gold << " -> " << gold << '\n'; // cout << "high: " << s.score << " -> " << high << '\n'; // cout << "exp: " << s.exp << " -> " << exp << '\n'; // cout << "sum: " << sum << '\n'; } vector UserShip::getUpgradeables() { vector result; result.push_back(&maxhp); result.push_back(&armor); result.push_back(&maxEnergy); result.push_back(&energyProduction); result.push_back(&handling); result.push_back(&moveSpeed); return result; } vector UserShip::frame(double time, SDL_Surface* screen) { vector result; //adjust energy energy += energyProduction*time; if(energy > maxEnergy) energy = maxEnergy; if(shooting) { double energyNeed = 0; for(int i = 0; i < (int) weapons.size(); ++i) energyNeed += weapons[i]->energyUsage*time; if(energyNeed < energy) { energy -= energyNeed; for(int i = 0; i < (int) weapons.size(); ++i) { vector temp; temp = weapons[i]->frame(time); for(int j = 0; j < (int) temp.size(); ++j) result.push_back(temp[j]); } } } //adjust speed and position of the ship double norm1 = sqrt(right*right + down*down); double norm2 = sqrt(xSpeed*xSpeed + ySpeed*ySpeed); double handconst = time*handling; double speedconst = norm2/moveSpeed; if(handconst * speedconst > norm2 || norm2 == 0) { xSpeed = 0; ySpeed = 0; } else { xSpeed *= 1 - speedconst * handconst / norm2; ySpeed *= 1 - speedconst * handconst / norm2 ; } norm2 = sqrt(xSpeed*xSpeed + ySpeed*ySpeed); if(norm1 != 0) { xSpeed += handconst*right / norm1; ySpeed += handconst*down / norm1; } else { if(handconst > norm2) { xSpeed = 0; ySpeed = 0; } else { xSpeed -= handconst * xSpeed / norm2; ySpeed -= handconst * ySpeed / norm2; } } // cout << xSpeed << " " << ySpeed << endl; x += xSpeed*time; y += ySpeed*time; if(x - image->w/2.0 < 0) { x = image->w/2.0; xSpeed = 0; } if(y - image->h/2.0 < 0) { y = image->h/2.0; ySpeed = 0; } if(x + image->w/2.0 > screen->w) { x = screen->w - image->w/2.0; xSpeed = 0; } if(y + image->h/2.0 > screen->h) { y = screen->h - image->h/2.0; ySpeed = 0; } for(int i = 0; i < (int) weapons.size(); ++i) { weapons[i]->x = slotPositions[i].first + x; weapons[i]->y = slotPositions[i].second + y; } return result; } /*structure of an UserShipfile small Fighter #name data/images/small_fighter.bmp #path of imagefile 200 #cost 7 #maxhp 50 #armor 200 #moveSpeed 100 #handling 10 #maxEnergy 2 #energyProduction 7 #collisionSize 2 #number of weapons 4 4 #relative Position of weapon 3 #maxSize of attached weapon data/fireball.txt #path of weapon 4 4 #relative Position of weapon 3 #maxSize of attached weapon data/fireball.txt #path of weapon */ UserShip::UserShip(string filename) { xSpeed = 0; ySpeed = 0; down = 0; right = 0; shooting = 0; ifstream ins; ins.open(filename.c_str()); if(!ins.is_open()) cout << "Error: Could not open userShip " << filename << endl; getline(ins, name); string imagePath; getline(ins, imagePath); image = loadBMP(imagePath); ins >> cost; ins >> maxhp; maxhp.name = "Hitpoints"; maxhp.cost = cost/10; hp = maxhp; ins >> armor; armor.name = "Armor"; armor.cost = cost/10; ins >> moveSpeed; moveSpeed.name = "Max Speed"; moveSpeed.cost = cost/10; ins >> handling; handling.name = "Acceleration"; handling.cost = cost/10; ins >> maxEnergy; maxEnergy.name = "Battery"; maxEnergy.cost = cost/10; energy = maxEnergy; ins >> energyProduction; energyProduction.name = "Generator"; energyProduction.cost = cost/10; ins >> collisionSize; ins >> weaponSlots; for(int i = 0; i < weaponSlots;i++) { double temp1, temp2; ins >> temp1; ins >> temp2; slotPositions.push_back(make_pair(temp1,temp2)); ins >> temp1; maxSize.push_back(temp1); //A workaround that helps discarting \n char workaround; ins >> workaround; string weaponpath; getline(ins, weaponpath); weapons.push_back(new Weapon(workaround + weaponpath)); } if(cost == 0) cost = round_beautiful(estimateValue(*this)); ins.close(); } void UserShip::reset() { hp = maxhp; energy = maxEnergy; xSpeed = 0; ySpeed = 0; for(int i = 0; i < (int) weapons.size(); ++i) { weapons[i]->playSound = false; vector dump = weapons[i]->frame((rand()%2000)/1000.0); weapons[i]->playSound = true; for(int j = 0; j < (int) dump.size(); ++j) delete dump[j]; } } void UserShip::draw(SDL_Surface* screen) { DObject::draw(screen); for(int i = 0; i < (int) weapons.size(); ++i) weapons[i]->draw(screen); } SDL_Surface* UserShip::getImage() { return image; } double estimateValue(const UserShip& s) { double result; result = s.maxhp * pow(2,s.armor/(50.0+s.maxhp/10)); result *= result; result += s.maxEnergy*s.maxEnergy + s.energyProduction * s.energyProduction * 50; result *= s.weapons.size(); result *= s.moveSpeed / 300 * s.handling / 300; return result/11; }