diff --git a/.mailmap b/.mailmap index 6944bd2ba..5538f76d5 100644 --- a/.mailmap +++ b/.mailmap @@ -1,5 +1,7 @@ # Proper Name Commit Name Clint Bellanger clintbellanger +Clint Bellanger unknown +Clint Bellanger unknown Thane Brimhall Thane Brimhall Thane Brimhall Thane Brimhall Thane Brimhall Thane Brimhall @@ -13,3 +15,4 @@ Manuel A. Fernandez Montecelo Manuel A. Fernandez M Andrzej Adamczyk Akasei Adrián Chaves Fernández (Gallaecio) Adrian Chaves Fernandez Christian Kirchberger Gonzo +Henrik Andersson Henrik Andersson diff --git a/CMakeLists.txt b/CMakeLists.txt index 19c69734f..cd0597d77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,6 +97,7 @@ Set (FLARE_SOURCES ./src/FontEngine.cpp ./src/GameState.cpp ./src/GameStateConfig.cpp + ./src/GameStateCutscene.cpp ./src/GameStateTitle.cpp ./src/GameStateLoad.cpp ./src/GameStatePlay.cpp diff --git a/astyle_flare.sh b/astyle_flare.sh new file mode 100755 index 000000000..24abd2d88 --- /dev/null +++ b/astyle_flare.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +astyle -S -T4 --style=kr -y src/*.cpp + diff --git a/mods/default/cutscenes/intro.txt b/mods/default/cutscenes/intro.txt new file mode 100644 index 000000000..e21ffd608 --- /dev/null +++ b/mods/default/cutscenes/intro.txt @@ -0,0 +1,11 @@ +#this scales art to width of flare window +#scale_gfx=true + +[scene] +image=menus/logo.png +caption=Flare, the... +soundfx=soundfx/level_up.ogg +pause=60 +caption=Free Libre Action Roleplaying Engine +pause=120 + diff --git a/mods/default/engine/font_settings.txt b/mods/default/engine/font_settings.txt index 9f28c41e2..d06d440df 100644 --- a/mods/default/engine/font_settings.txt +++ b/mods/default/engine/font_settings.txt @@ -3,3 +3,6 @@ [font_regular] default=LiberationSans-Regular.ttf,12,1 + +[font_captions] +default=LiberationSans-Regular.ttf,24,1 diff --git a/src/Animation.cpp b/src/Animation.cpp index 9d5a872cd..15cbd7f02 100644 --- a/src/Animation.cpp +++ b/src/Animation.cpp @@ -203,9 +203,6 @@ Renderable Animation::getCurrentFrame(int kind) { r.offset.y = render_offset[index].y; r.sprite = sprite; } - else { - memset(&r, 0, sizeof(Renderable)); - } return r; } @@ -226,9 +223,10 @@ void Animation::syncTo(const Animation *other) { } void Animation::setActiveFrames(const std::vector &_active_frames) { - if (_active_frames.size() == 1 && _active_frames[0] == -1) - for (short i=0; i < number_frames; ++i) + if (_active_frames.size() == 1 && _active_frames[0] == -1) { + for (short i = 0; i < number_frames; ++i) active_frames.push_back(i); + } else active_frames = std::vector(_active_frames); } diff --git a/src/AnimationSet.cpp b/src/AnimationSet.cpp index b95215470..33506b087 100644 --- a/src/AnimationSet.cpp +++ b/src/AnimationSet.cpp @@ -66,10 +66,8 @@ void AnimationSet::load() { FileParser parser; const string filename = mods->locate(name); - if (!parser.open(filename.c_str())) { - cout << "Error loading animation definition file: " << name << endl; + if (!parser.open(filename, "Error loading animation definition: " + name)) return; - } string _name = ""; int position = 0; diff --git a/src/Avatar.cpp b/src/Avatar.cpp index 6303e87a9..63f52cead 100644 --- a/src/Avatar.cpp +++ b/src/Avatar.cpp @@ -35,6 +35,7 @@ FLARE. If not, see http://www.gnu.org/licenses/ #include "MapRenderer.h" #include "PowerManager.h" #include "SharedResources.h" +#include "Utils.h" #include "UtilsParsing.h" #include "UtilsMath.h" @@ -170,7 +171,7 @@ void Avatar::loadLayerDefinitions() { } } infile.close(); - } else fprintf(stderr, "Unable to open engine/hero_options.txt!\n"); + } // There are the positions of the items relative to layer_reference_order // so if layer_reference_order=main,body,head,off @@ -276,7 +277,7 @@ void Avatar::set_direction() { target = path.back(); } } - stats.direction = face(target.x, target.y); + stats.direction = calcDirection(stats.pos, target); } else { if (inpt->pressing[UP] && inpt->pressing[LEFT]) stats.direction = 1; else if (inpt->pressing[UP] && inpt->pressing[RIGHT]) stats.direction = 3; @@ -327,7 +328,7 @@ void Avatar::handlePower(int actionbar_power) { // is this a power that requires changing direction? if (power.face) { - stats.direction = face(target.x, target.y); + stats.direction = calcDirection(stats.pos, target); } switch (power.new_state) { @@ -776,7 +777,7 @@ bool Avatar::takeHit(const Hazard &h) { if (!stats.effects.immunity) { if (stats.effects.forced_move) { - float theta = powers->calcTheta(h.src_stats->pos.x, h.src_stats->pos.y, stats.pos.x, stats.pos.y); + float theta = calcTheta(h.src_stats->pos.x, h.src_stats->pos.y, stats.pos.x, stats.pos.y); stats.forced_speed.x = static_cast(ceil(stats.effects.forced_speed * cos(theta))); stats.forced_speed.y = static_cast(ceil(stats.effects.forced_speed * sin(theta))); } diff --git a/src/BehaviorStandard.cpp b/src/BehaviorStandard.cpp index f05addc41..0fef1afba 100644 --- a/src/BehaviorStandard.cpp +++ b/src/BehaviorStandard.cpp @@ -315,7 +315,7 @@ void BehaviorStandard::checkMove() { } } - e->stats.direction = e->face(pursue_pos.x, pursue_pos.y); + e->stats.direction = calcDirection(e->stats.pos, pursue_pos); e->stats.turn_ticks = 0; } } diff --git a/src/CombatText.cpp b/src/CombatText.cpp index 3c970d760..ec76ab575 100644 --- a/src/CombatText.cpp +++ b/src/CombatText.cpp @@ -54,7 +54,7 @@ CombatText::CombatText() { } } infile.close(); - } else fprintf(stderr, "Unable to open engine/combat_text.txt!\n"); + } } void CombatText::setCam(Point location) { diff --git a/src/Enemy.cpp b/src/Enemy.cpp index 10ef7d15f..cee85b8e4 100644 --- a/src/Enemy.cpp +++ b/src/Enemy.cpp @@ -240,7 +240,7 @@ bool Enemy::takeHit(const Hazard &h) { powers->effect(&stats, h.power_index); if (stats.effects.forced_move) { - float theta = powers->calcTheta(stats.hero_pos.x, stats.hero_pos.y, stats.pos.x, stats.pos.y); + float theta = calcTheta(stats.hero_pos.x, stats.hero_pos.y, stats.pos.x, stats.pos.y); stats.forced_speed.x = static_cast(ceil(stats.effects.forced_speed * cos(theta))); stats.forced_speed.y = static_cast(ceil(stats.effects.forced_speed * sin(theta))); } diff --git a/src/EnemyGroupManager.cpp b/src/EnemyGroupManager.cpp index 622de26dd..224b7294c 100644 --- a/src/EnemyGroupManager.cpp +++ b/src/EnemyGroupManager.cpp @@ -77,7 +77,7 @@ void EnemyGroupManager::parseEnemyFileAndStore(const string& filename) { } } infile.close(); - } else fprintf(stderr, "Unable to open enemies/%s!\n", filename.c_str()); + } } Enemy_Level EnemyGroupManager::getRandomEnemy(const std::string& category, int minlevel, int maxlevel) const { diff --git a/src/EnemyManager.cpp b/src/EnemyManager.cpp index 7b5592434..f92947af9 100644 --- a/src/EnemyManager.cpp +++ b/src/EnemyManager.cpp @@ -201,45 +201,45 @@ void EnemyManager::logic() { handleSpawn(); - for (unsigned int i=0; i < enemies.size(); i++) { - + vector::iterator it; + for (it = enemies.begin(); it != enemies.end(); ++it) { // hazards are processed after Avatar and Enemy[] // so process and clear sound effects from previous frames // check sound effects if (AUDIO) { - vector::iterator found = find (sfx_prefixes.begin(), sfx_prefixes.end(), enemies[i]->stats.sfx_prefix); + vector::iterator found = find (sfx_prefixes.begin(), sfx_prefixes.end(), (*it)->stats.sfx_prefix); unsigned pref_id = distance(sfx_prefixes.begin(), found); if (pref_id >= sfx_prefixes.size()) { cerr << "ERROR: enemy sfx_prefix doesn't match registered prefixes (enemy: '" - << enemies[i]->stats.name << "', sfx_prefix: '" - << enemies[i]->stats.sfx_prefix << "')" << endl; + << (*it)->stats.name << "', sfx_prefix: '" + << (*it)->stats.sfx_prefix << "')" << endl; } else { - if (enemies[i]->sfx_phys) - snd->play(sound_phys[pref_id], GLOBAL_VIRTUAL_CHANNEL, enemies[i]->stats.pos, false); - if (enemies[i]->sfx_ment) - snd->play(sound_ment[pref_id], GLOBAL_VIRTUAL_CHANNEL, enemies[i]->stats.pos, false); - if (enemies[i]->sfx_hit) - snd->play(sound_hit[pref_id], GLOBAL_VIRTUAL_CHANNEL, enemies[i]->stats.pos, false); - if (enemies[i]->sfx_die) - snd->play(sound_die[pref_id], GLOBAL_VIRTUAL_CHANNEL, enemies[i]->stats.pos, false); - if (enemies[i]->sfx_critdie) - snd->play(sound_critdie[pref_id], GLOBAL_VIRTUAL_CHANNEL, enemies[i]->stats.pos, false); + if ((*it)->sfx_phys) + snd->play(sound_phys[pref_id], GLOBAL_VIRTUAL_CHANNEL, (*it)->stats.pos, false); + if ((*it)->sfx_ment) + snd->play(sound_ment[pref_id], GLOBAL_VIRTUAL_CHANNEL, (*it)->stats.pos, false); + if ((*it)->sfx_hit) + snd->play(sound_hit[pref_id], GLOBAL_VIRTUAL_CHANNEL, (*it)->stats.pos, false); + if ((*it)->sfx_die) + snd->play(sound_die[pref_id], GLOBAL_VIRTUAL_CHANNEL, (*it)->stats.pos, false); + if ((*it)->sfx_critdie) + snd->play(sound_critdie[pref_id], GLOBAL_VIRTUAL_CHANNEL, (*it)->stats.pos, false); } // clear sound flags - enemies[i]->sfx_hit = false; - enemies[i]->sfx_phys = false; - enemies[i]->sfx_ment = false; - enemies[i]->sfx_die = false; - enemies[i]->sfx_critdie = false; + (*it)->sfx_hit = false; + (*it)->sfx_phys = false; + (*it)->sfx_ment = false; + (*it)->sfx_die = false; + (*it)->sfx_critdie = false; } // new actions this round - enemies[i]->stats.hero_pos = hero_pos; - enemies[i]->stats.hero_alive = hero_alive; - enemies[i]->stats.hero_stealth = hero_stealth; - enemies[i]->logic(); + (*it)->stats.hero_pos = hero_pos; + (*it)->stats.hero_alive = hero_alive; + (*it)->stats.hero_stealth = hero_stealth; + (*it)->logic(); } } diff --git a/src/Entity.cpp b/src/Entity.cpp index c58b12f58..ddc53ad8b 100644 --- a/src/Entity.cpp +++ b/src/Entity.cpp @@ -103,40 +103,6 @@ bool Entity::move() { return full_move; } -/** - * Change direction to face the target map location - */ -int Entity::face(int mapx, int mapy) { - // inverting Y to convert map coordinates to standard cartesian coordinates - int dx = mapx - stats.pos.x; - int dy = stats.pos.y - mapy; - - // avoid div by zero - if (dx == 0) { - if (dy > 0) return 3; - else return 7; - } - - float slope = ((float)dy)/((float)dx); - if (0.5 <= slope && slope <= 2.0) { - if (dy > 0) return 4; - else return 0; - } - if (-0.5 <= slope && slope <= 0.5) { - if (dx > 0) return 5; - else return 1; - } - if (-2.0 <= slope && slope <= -0.5) { - if (dx > 0) return 6; - else return 2; - } - if (2.0 <= slope || -2.0 >= slope) { - if (dy > 0) return 3; - else return 7; - } - return stats.direction; -} - /** * Set the entity's current animation by name */ diff --git a/src/Entity.h b/src/Entity.h index 56be6845a..87d7c94eb 100644 --- a/src/Entity.h +++ b/src/Entity.h @@ -44,7 +44,6 @@ class Entity { virtual ~Entity(); bool move(); - int face(int, int); // Each child of Entity defines its own rendering method virtual Renderable getRender() = 0; diff --git a/src/FileParser.cpp b/src/FileParser.cpp index f39ab1f37..6e08e1ca0 100644 --- a/src/FileParser.cpp +++ b/src/FileParser.cpp @@ -33,9 +33,13 @@ FileParser::FileParser() , val("") {} -bool FileParser::open(const string& filename) { +bool FileParser::open(const string& filename, const string &errormessage) { + this->filename = filename; infile.open(filename.c_str(), ios::in); - return infile.is_open(); + bool ret = infile.is_open(); + if (!ret && !errormessage.empty()) + fprintf(stderr, "%s: %s\n", errormessage.c_str(), filename.c_str()); + return ret; } void FileParser::close() { @@ -105,7 +109,7 @@ string FileParser::nextValue() { size_t seppos = val.find_first_of(','); size_t alt_seppos = val.find_first_of(';'); if (alt_seppos != string::npos && alt_seppos < seppos) - seppos = alt_seppos; // return the first ',' or ';' + seppos = alt_seppos; // return the first ',' or ';' if (seppos == string::npos) { s = val; @@ -118,6 +122,11 @@ string FileParser::nextValue() { return s; } +std::string FileParser::getFileName() +{ + return filename; +} + FileParser::~FileParser() { close(); } diff --git a/src/FileParser.h b/src/FileParser.h index 2de4cf151..d12bf2e4f 100644 --- a/src/FileParser.h +++ b/src/FileParser.h @@ -31,6 +31,7 @@ FLARE. If not, see http://www.gnu.org/licenses/ class FileParser { private: + std::string filename; std::ifstream infile; std::string line; @@ -38,11 +39,21 @@ class FileParser { FileParser(); ~FileParser(); - bool open(const std::string& filename); + /** + * @brief open + * @param filename The file to be opened + * @param errormessage + * Optional parameter, will be printed to stderr together with the filename + * if an error occurs. If errormessage is empty, there will be no output to + * stderr in any case. + * @return true if file could be opened successfully for reading. + */ + bool open(const std::string& filename, const std::string &errormessage = "Could not open text file"); void close(); bool next(); std::string nextValue(); // next value inside one line. std::string getRawLine(); + std::string getFileName(); bool new_section; std::string section; diff --git a/src/FontEngine.cpp b/src/FontEngine.cpp index f153210c8..213bbe79d 100644 --- a/src/FontEngine.cpp +++ b/src/FontEngine.cpp @@ -77,7 +77,7 @@ FontEngine::FontEngine() } } infile.close(); - } else fprintf(stderr, "Unable to open engine/font_settings.txt!\n"); + } // set the font colors // RGB values, the last value is 'unused'. For info, @@ -92,7 +92,7 @@ FontEngine::FontEngine() color_map[infile.key] = color; } infile.close(); - } else fprintf(stderr, "Unable to open engine/font_colors.txt!\n"); + } // Attempt to set the default active font setFont("font_regular"); diff --git a/src/GameStateConfig.cpp b/src/GameStateConfig.cpp index 031831cca..038167dd6 100644 --- a/src/GameStateConfig.cpp +++ b/src/GameStateConfig.cpp @@ -50,19 +50,11 @@ GameStateConfig::GameStateConfig () , ok_button(NULL) , defaults_button(NULL) , cancel_button(NULL) - , imgFileName(mods->locate("images/menus/config.png")) , tip_buf() , input_key(0) , check_resolution(true) { - // Load background image - SDL_Surface * tmp = IMG_Load(imgFileName.c_str()); - if (!tmp) { - fprintf(stderr, "Could not load image \"%s\"\n", imgFileName.c_str()); - } else { - background = SDL_DisplayFormatAlpha(tmp); - SDL_FreeSurface(tmp); - } + background = loadGraphicSurface("images/menus/config.png"); init(); update(); @@ -215,11 +207,7 @@ void GameStateConfig::init() { void GameStateConfig::readConfig () { //Load the menu configuration from file - int x1 = 0; - int y1 = 0; - int x2 = 0; - int y2 = 0; - int setting_num = 0; + int offset_x = 0; int offset_y = 0; @@ -228,12 +216,12 @@ void GameStateConfig::readConfig () { while (infile.next()) { infile.val = infile.val + ','; - x1 = eatFirstInt(infile.val, ','); - y1 = eatFirstInt(infile.val, ','); - x2 = eatFirstInt(infile.val, ','); - y2 = eatFirstInt(infile.val, ','); + int x1 = eatFirstInt(infile.val, ','); + int y1 = eatFirstInt(infile.val, ','); + int x2 = eatFirstInt(infile.val, ','); + int y2 = eatFirstInt(infile.val, ','); - setting_num = -1; + int setting_num = -1; if (infile.key == "listbox_scrollbar_offset") { activemods_lstb->scrollbar_offset = x1; @@ -607,7 +595,7 @@ void GameStateConfig::readConfig () { } infile.close(); - } else fprintf(stderr, "Unable to open menus/config.txt!\n"); + } // Load the MenuConfirm positions and alignments from menus/menus.txt if (infile.open(mods->locate("menus/menus.txt"))) { @@ -634,7 +622,7 @@ void GameStateConfig::readConfig () { } } infile.close(); - } else fprintf(stderr, "Unable to open menus/menus.txt!\n"); + } defaults_confirm->window_area = menuConfirm_area; defaults_confirm->alignment = menuConfirm_align; @@ -789,7 +777,7 @@ void GameStateConfig::logic () delete requestedGameState; requestedGameState = new GameStateTitle(); } else if (resolution_confirm->cancelClicked || resolution_confirm_ticks == 0) { - applyVideoSettings(screen, old_view_w, old_view_h); + applyVideoSettings(old_view_w, old_view_h); saveSettings(); delete requestedGameState; requestedGameState = new GameStateConfig(); @@ -815,7 +803,7 @@ void GameStateConfig::logic () SDL_JoystickClose(joy); joy = SDL_JoystickOpen(JOYSTICK_DEVICE); } - applyVideoSettings(screen, width, height); + applyVideoSettings(width, height); if (width != old_view_w || height != old_view_h) { resolution_confirm->window_area = menuConfirm_area; resolution_confirm->align(); @@ -1175,7 +1163,7 @@ bool GameStateConfig::getLanguagesList() i += 1; } infile.close(); - } else fprintf(stderr, "Unable to open engine/languages.txt!\n"); + } return true; } @@ -1189,7 +1177,7 @@ int GameStateConfig::getLanguagesNumber() languages_num += 1; } infile.close(); - } else fprintf(stderr, "Unable to open engine/languages.txt!\n"); + } return languages_num; } @@ -1202,44 +1190,22 @@ void GameStateConfig::refreshFont() { /** * Tries to apply the selected video settings, reverting back to the old settings upon failure */ -bool GameStateConfig::applyVideoSettings(SDL_Surface *src, int width, int height) { +bool GameStateConfig::applyVideoSettings(int width, int height) { if (MIN_VIEW_W > width && MIN_VIEW_H > height) { fprintf (stderr, "A mod is requiring a minimum resolution of %dx%d\n", MIN_VIEW_W, MIN_VIEW_H); if (width < MIN_VIEW_W) width = MIN_VIEW_W; if (height < MIN_VIEW_H) height = MIN_VIEW_H; } - // Temporarily save previous settings - int tmp_fs = FULLSCREEN; - int tmp_w = VIEW_W; - int tmp_h = VIEW_H; - // Attempt to apply the new settings - Uint32 flags = 0; - if (FULLSCREEN) flags = flags | SDL_FULLSCREEN; - if (DOUBLEBUF) flags = flags | SDL_DOUBLEBUF; - if (HWSURFACE) - flags = flags | SDL_HWSURFACE | SDL_HWACCEL; - else - flags = flags | SDL_SWSURFACE; - - src = SDL_SetVideoMode (width, height, 0, flags); + setupSDLVideoMode(width, height); // If the new settings fail, revert to the old ones - if (src == NULL) { + if (!screen) { fprintf (stderr, "Error during SDL_SetVideoMode: %s\n", SDL_GetError()); - - flags = 0; - if (tmp_fs) flags = flags | SDL_FULLSCREEN; - if (DOUBLEBUF) flags = flags | SDL_DOUBLEBUF; - if (HWSURFACE) - flags = flags | SDL_HWSURFACE | SDL_HWACCEL; - else - flags = flags | SDL_SWSURFACE; - - SDL_SetVideoMode (tmp_w, tmp_h, 0, flags); - + setupSDLVideoMode(VIEW_W, VIEW_H); return false; + } else { // If the new settings succeed, adjust the view area diff --git a/src/GameStateConfig.h b/src/GameStateConfig.h index c97eae16a..eba3956ff 100644 --- a/src/GameStateConfig.h +++ b/src/GameStateConfig.h @@ -72,7 +72,7 @@ class GameStateConfig : public GameState { void update(); void setDefaultResolution(); void refreshFont(); - bool applyVideoSettings(SDL_Surface *src, int width, int height); + bool applyVideoSettings(int width, int height); void enableMods(); void disableMods(); bool setMods(); @@ -84,7 +84,6 @@ class GameStateConfig : public GameState { WidgetButton * defaults_button; WidgetButton * cancel_button; SDL_Surface * background; - std::string imgFileName; WidgetCheckBox * fullscreen_cb; WidgetLabel * fullscreen_lb; diff --git a/src/GameStateCutscene.cpp b/src/GameStateCutscene.cpp new file mode 100644 index 000000000..ed064b0c6 --- /dev/null +++ b/src/GameStateCutscene.cpp @@ -0,0 +1,232 @@ +/* +Copyright © 2012-2013 Henrik Andersson + +This file is part of FLARE. + +FLARE is free software: you can redistribute it and/or modify it under the terms +of the GNU General Public License as published by the Free Software Foundation, +either version 3 of the License, or (at your option) any later version. + +FLARE is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +FLARE. If not, see http://www.gnu.org/licenses/ +*/ + +#include "GameStateCutscene.h" +#include "GameStatePlay.h" +#include "FileParser.h" + +#include +using namespace std; + +Scene::Scene() : frame_counter(0) + , pause_frames(0) + , caption("") + , caption_size(0,0) + , art(NULL) + , sid(-1) +{ +} + +Scene::~Scene() { + + while(!components.empty()) + components.pop(); + +} + +bool Scene::logic() { + + /* TODO: handle cancel input to skip scene */ + bool skip = false; + if (inpt->pressing[MAIN1] && !inpt->lock[MAIN1]) { + inpt->lock[MAIN1] = true; + skip = true; + } + + /* Pause until specified frame */ + if (!skip && pause_frames != 0 && frame_counter < pause_frames) { + ++frame_counter; + return true; + } + + /* parse scene components until next pause */ + while (!components.empty() && components.front().type != "pause") { + + if (components.front().type == "caption") { + + font->setFont("font_captions"); + caption = components.front().s; + caption_size = font->calc_size(caption, VIEW_W * 0.8f); + + } else if (components.front().type == "image") { + + if (art) + SDL_FreeSurface(art); + + art = components.front().i; + + art_dest.x = (VIEW_W/2) - (art->w/2); + art_dest.y = (VIEW_H/2) - (art->h/2); + art_dest.w = art->w; + art_dest.h = art->h; + + } else if (components.front().type == "soundfx") { + if (sid != 0) + snd->unload(sid); + + sid = snd->load(components.front().s, "Cutscenes"); + snd->play(sid); + } + + components.pop(); + } + + /* check if current scene has reached the end */ + if (components.empty()) + return false; + + /* setup frame pausing */ + frame_counter = 0; + pause_frames = components.front().x; + components.pop(); + + return true; +} + +void Scene::render() { + SDL_Rect r = art_dest; + if (art != NULL) + SDL_BlitSurface(art, NULL, screen, &r); + + if (caption != "") { + font->setFont("font_captions"); + font->renderShadowed(caption, screen->w / 2, screen->h - (caption_size.y*2), + JUSTIFY_CENTER, + screen, FONT_WHITE); + } +} + +GameStateCutscene::GameStateCutscene(GameState *game_state) : previous_gamestate(game_state) + , game_slot(-1) +{ + scale_graphics = false; +} + +GameStateCutscene::~GameStateCutscene() { +} + +void GameStateCutscene::logic() { + + if (scenes.empty()) + { + if (game_slot != -1) { + GameStatePlay *gsp = new GameStatePlay(); + gsp->resetGame(); + gsp->game_slot = game_slot; + gsp->loadGame(); + + previous_gamestate = gsp; + } + + /* return to previous gamestate */ + delete requestedGameState; + requestedGameState = previous_gamestate; + return; + } + + while (!scenes.empty() && !scenes.front().logic()) + scenes.pop(); +} + +void GameStateCutscene::render() { + if (!scenes.empty()) + scenes.front().render(); +} + +bool GameStateCutscene::load(std::string filename) { + FileParser infile; + + if (!infile.open(mods->locate("cutscenes/" + filename))) { + cerr << "Unable to open cutscenes/" << filename << endl; + return false; + } + + // parse the cutscene file + while (infile.next()) { + + if (infile.new_section) { + if (infile.section == "scene") + scenes.push(Scene()); + } + + if (infile.section == "scene") { + SceneComponent sc; + sc.type = ""; + + if (infile.key == "caption") { + sc.type = infile.key; + sc.s = msg->get(infile.val); + } + else if (infile.key == "image") { + sc.type = infile.key; + sc.i = loadImage(infile.val); + if (sc.i == NULL) + sc.type = ""; + } + else if (infile.key == "pause") { + sc.type = infile.key; + sc.x = toInt(infile.val); + } + else if (infile.key == "soundfx") { + sc.type = infile.key; + sc.s = infile.val; + } + + if (sc.type != "") + scenes.back().components.push(sc); + + } else { + + if (infile.key == "scale_gfx") { + scale_graphics = toBool(infile.val); + } + + } + } + + if (scenes.empty()) + { + cerr << "No scenes defined in cutscene file " << filename << endl; + return false; + } + + return true; +} + +SDL_Surface *GameStateCutscene::loadImage(std::string filename) { + + std::string image_file = (mods->locate("images/"+ filename)); + SDL_Surface *image = IMG_Load(image_file.c_str()); + if (!image) { + std::cerr << "Missing cutscene art reference: " << image_file << std::endl; + return NULL; + } + + /* scale image to fit height */ + if (scale_graphics) { + float ratio = image->h/(float)image->w; + SDL_Surface *art = scaleSurface(image, VIEW_W, VIEW_W*ratio); + if (art == NULL) + return image; + + SDL_FreeSurface(image); + image = art; + } + + return image; +} + diff --git a/src/GameStateCutscene.h b/src/GameStateCutscene.h new file mode 100644 index 000000000..e349e8240 --- /dev/null +++ b/src/GameStateCutscene.h @@ -0,0 +1,87 @@ +/* +Copyright © 2012-2013 Henrik Andersson + +This file is part of FLARE. + +FLARE is free software: you can redistribute it and/or modify it under the terms +of the GNU General Public License as published by the Free Software Foundation, +either version 3 of the License, or (at your option) any later version. + +FLARE is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +FLARE. If not, see http://www.gnu.org/licenses/ +*/ + +#include +#include +#include +#include +#include +#include + +#include "Settings.h" +#include "SharedResources.h" +#include "Utils.h" +#include "UtilsParsing.h" +#include "WidgetLabel.h" + +#ifndef GAMESTATECUTSCENE_H +#define GAMESTATECUTSCENE_H + +#include "GameState.h" + +class SceneComponent { +public: + std::string type; + SDL_Surface *i; + std::string s; + int x,y,z; +}; + +class Scene { +private: + int frame_counter; + int pause_frames; + std::string caption; + Point caption_size; + SDL_Surface *art; + SDL_Rect art_dest; + SoundManager::SoundID sid; + +public: + Scene(); + ~Scene(); + bool logic(); + void render(); + + std::queue components; + +}; + +class GameStateCutscene : public GameState { +private: + GameState *previous_gamestate; + std::string dest_map; + Point dest_pos; + bool scale_graphics; + + std::queue scenes; + + SDL_Surface *loadImage(std::string filename); + +public: + GameStateCutscene(GameState *game_state); + ~GameStateCutscene(); + + bool load(std::string filename); + void logic(); + void render(); + + int game_slot; +}; + +#endif + diff --git a/src/GameStateLoad.cpp b/src/GameStateLoad.cpp index 5683d34a3..d1517185f 100644 --- a/src/GameStateLoad.cpp +++ b/src/GameStateLoad.cpp @@ -113,7 +113,7 @@ GameStateLoad::GameStateLoad() : GameState() { } } infile.close(); - } else fprintf(stderr, "Unable to open menus/gameload.txt!\n"); + } // Load the MenuConfirm positions and alignments from menus/menus.txt if (infile.open(mods->locate("menus/menus.txt"))) { @@ -140,7 +140,7 @@ GameStateLoad::GameStateLoad() : GameState() { } } infile.close(); - } else fprintf(stderr, "Unable to open menus/menus.txt!\n"); + } confirm->align(); confirm->update(); @@ -164,7 +164,7 @@ GameStateLoad::GameStateLoad() : GameState() { } } infile.close(); - } else fprintf(stderr, "Unable to open engine/hero_options.txt!\n"); + } if (!found_layer) fprintf(stderr, "Warning: Could not find layers for direction 6\n"); button_action->pos.x += (VIEW_W - FRAME_W)/2; @@ -201,35 +201,9 @@ GameStateLoad::GameStateLoad() : GameState() { } void GameStateLoad::loadGraphics() { - background = IMG_Load(mods->locate("images/menus/game_slots.png").c_str()); - selection = IMG_Load(mods->locate("images/menus/game_slot_select.png").c_str()); - portrait_border = IMG_Load(mods->locate("images/menus/portrait_border.png").c_str()); - if (!background || !selection || !portrait_border) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - } - - // optimize - SDL_Surface *cleanup; - - if (background) { - cleanup = background; - background = SDL_DisplayFormatAlpha(background); - SDL_FreeSurface(cleanup); - } - - if (selection) { - SDL_SetColorKey( selection, SDL_SRCCOLORKEY, SDL_MapRGB(selection->format, 255, 0, 255)); - cleanup = selection; - selection = SDL_DisplayFormatAlpha(selection); - SDL_FreeSurface(cleanup); - } - - if (portrait_border) { - SDL_SetColorKey( portrait_border, SDL_SRCCOLORKEY, SDL_MapRGB(portrait_border->format, 255, 0, 255)); - cleanup = portrait_border; - portrait_border = SDL_DisplayFormatAlpha(portrait_border); - SDL_FreeSurface(cleanup); - } + background = loadGraphicSurface("images/menus/game_slots.png"); + selection = loadGraphicSurface("images/menus/game_slot_select.png", "Couldn't load image", false, true); + portrait_border = loadGraphicSurface("images/menus/portrait_border.png", "Couldn't load image", false, true); } void GameStateLoad::loadPortrait(int slot) { @@ -240,13 +214,7 @@ void GameStateLoad::loadPortrait(int slot) { if (stats[slot].name == "") return; - portrait = IMG_Load(mods->locate("images/portraits/" + stats[slot].portrait + ".png").c_str()); - if (!portrait) return; - - // optimize - SDL_Surface *cleanup = portrait; - portrait = SDL_DisplayFormatAlpha(portrait); - SDL_FreeSurface(cleanup); + portrait = loadGraphicSurface("images/portraits/" + stats[slot].portrait + ".png"); } void GameStateLoad::readGameSlots() { @@ -257,7 +225,7 @@ void GameStateLoad::readGameSlots() { string GameStateLoad::getMapName(const string& map_filename) { FileParser infile; - if (!infile.open(mods->locate("maps/" + map_filename))) return ""; + if (!infile.open(mods->locate("maps/" + map_filename), "")) return ""; string map_name = ""; while (map_name == "" && infile.next()) { @@ -283,7 +251,7 @@ void GameStateLoad::readGameSlot(int slot) { filename << GAME_PREFIX << "_"; filename << "save" << (slot+1) << ".txt"; - if (!infile.open(filename.str())) return; + if (!infile.open(filename.str(), "")) return; while (infile.next()) { @@ -358,26 +326,17 @@ void GameStateLoad::loadPreview(int slot) { // composite the hero graphic for (unsigned int i=0; ilocate("images/avatar/" + stats[slot].base + "/preview/noalpha/" + img_gfx[i] + ".png").c_str()); + if (!TEXTURE_QUALITY) { + string fname = "images/avatar/" + stats[slot].base + "/preview/noalpha/" + img_gfx[i] + ".png"; + sprites[slot].back() = loadGraphicSurface(fname, "Falling back to alpha version", false, true); } if (!sprites[slot].back()) { - sprites[slot].back() = IMG_Load(mods->locate("images/avatar/" + stats[slot].base + "/preview/" + img_gfx[i] + ".png").c_str()); - } else { - SDL_SetColorKey(sprites[slot].back(), SDL_SRCCOLORKEY, SDL_MapRGB(sprites[slot].back()->format, 255, 0, 255)); - } - if (!sprites[slot].back()) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - } - - // optimize - if (sprites[slot].back()) { - SDL_Surface *cleanup = sprites[slot].back(); - sprites[slot].back() = SDL_DisplayFormatAlpha(sprites[slot].back()); - SDL_FreeSurface(cleanup); + sprites[slot].back() = loadGraphicSurface("images/avatar/" + stats[slot].base + "/preview/" + img_gfx[i] + ".png"); } } diff --git a/src/GameStateNew.cpp b/src/GameStateNew.cpp index 9a122f9a7..5a8acf0fa 100644 --- a/src/GameStateNew.cpp +++ b/src/GameStateNew.cpp @@ -121,7 +121,7 @@ GameStateNew::GameStateNew() : GameState() { } } infile.close(); - } else fprintf(stderr, "Unable to open menus/gamenew.txt!\n"); + } button_prev->pos.x += (VIEW_W - FRAME_W)/2; button_prev->pos.y += (VIEW_H - FRAME_H)/2; @@ -175,27 +175,12 @@ GameStateNew::GameStateNew() : GameState() { } void GameStateNew::loadGraphics() { - portrait_border = IMG_Load(mods->locate("images/menus/portrait_border.png").c_str()); - if(!portrait_border) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - } else { - // optimize - SDL_SetColorKey( portrait_border, SDL_SRCCOLORKEY, SDL_MapRGB(portrait_border->format, 255, 0, 255) ); - SDL_Surface *cleanup = portrait_border; - portrait_border = SDL_DisplayFormatAlpha(portrait_border); - SDL_FreeSurface(cleanup); - } + portrait_border = loadGraphicSurface("images/menus/portrait_border.png", "Couldn't load portrait border image", false, true); } void GameStateNew::loadPortrait(const string& portrait_filename) { SDL_FreeSurface(portrait_image); - portrait_image = IMG_Load(mods->locate("images/portraits/" + portrait_filename + ".png").c_str()); - if (!portrait_image) return; - - // optimize - SDL_Surface *cleanup = portrait_image; - portrait_image = SDL_DisplayFormatAlpha(portrait_image); - SDL_FreeSurface(cleanup); + portrait_image = loadGraphicSurface("images/portraits/" + portrait_filename + ".png"); } /** diff --git a/src/GameStatePlay.cpp b/src/GameStatePlay.cpp index 3e76e5cb0..19a515289 100644 --- a/src/GameStatePlay.cpp +++ b/src/GameStatePlay.cpp @@ -31,6 +31,7 @@ FLARE. If not, see http://www.gnu.org/licenses/ #include "GameStatePlay.h" #include "GameState.h" #include "GameStateTitle.h" +#include "GameStateCutscene.h" #include "Hazard.h" #include "HazardManager.h" #include "LootManager.h" @@ -79,7 +80,8 @@ GameStatePlay::GameStatePlay() , npcs(new NPCManager(map, loot, items, &pc->stats)) , quests(new QuestLog(camp, menu->log)) , loading(new WidgetLabel()) - , loading_bg(IMG_Load(mods->locate("images/menus/confirm_bg.png").c_str())) + // Load the loading screen image (we currently use the confirm dialog background): + , loading_bg(loadGraphicSurface("images/menus/confirm_bg.png")) , npc_id(-1) , eventDialogOngoing(false) , eventPendingDialog(false) @@ -98,16 +100,6 @@ GameStatePlay::GameStatePlay() loading->set(VIEW_W_HALF, VIEW_H_HALF, JUSTIFY_CENTER, VALIGN_CENTER, msg->get("Loading..."), color_normal); - // Load the loading screen image (we currently use the confirm dialog background) - - if(!loading_bg) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - } else { - SDL_Surface *cleanup = loading_bg; - loading_bg = SDL_DisplayFormatAlpha(loading_bg); - SDL_FreeSurface(cleanup); - } - // load the config file for character titles loadTitles(); } @@ -387,10 +379,10 @@ void GameStatePlay::loadTitles() { else if (infile.key == "requires_status") titles.back().requires_status = infile.val; else if (infile.key == "requires_not") titles.back().requires_not = infile.val; else if (infile.key == "primary_stat") titles.back().primary_stat = infile.val; + else fprintf(stderr, "Unknown key value in title definitons: %s in file %s in section %s\n", infile.key.c_str(), infile.getFileName().c_str(), infile.section.c_str()); } infile.close(); } - else fprintf(stderr, "Unable to open engine/titles.txt!\n"); } void GameStatePlay::checkTitle() { @@ -704,12 +696,47 @@ void GameStatePlay::checkStash() { } } +void GameStatePlay::checkCutscene() { + if (!map->cutscene) + return; + + GameStateCutscene *cutscene = new GameStateCutscene(NULL); + + if (!cutscene->load(map->cutscene_file)) { + delete cutscene; + map->cutscene = false; + return; + } + + // handle respawn point and set game play game_slot + cutscene->game_slot = game_slot; + + if (map->teleportation) { + + if (map->teleport_mapname != "") + map->respawn_map = map->teleport_mapname; + + map->respawn_point = map->teleport_destination; + + } else { + map->respawn_point = pc->stats.pos; + } + + saveGame(); + + delete requestedGameState; + requestedGameState = cutscene; +} + + /** * Process all actions for a single frame * This includes some message passing between child object */ void GameStatePlay::logic() { + checkCutscene(); + // check menus first (top layer gets mouse click priority) menu->logic(); diff --git a/src/GameStatePlay.h b/src/GameStatePlay.h index 8f918c6b3..43a01a064 100644 --- a/src/GameStatePlay.h +++ b/src/GameStatePlay.h @@ -101,6 +101,7 @@ class GameStatePlay : public GameState { void checkNotifications(); void checkNPCInteraction(); void checkStash(); + void checkCutscene(); void showLoading(); void loadTitles(); @@ -116,6 +117,8 @@ class GameStatePlay : public GameState { GameStatePlay(); ~GameStatePlay(); + void initialize(); + void logic(); void render(); void showFPS(int fps); diff --git a/src/GameStateTitle.cpp b/src/GameStateTitle.cpp index ea01f5fef..8e31ae7e5 100644 --- a/src/GameStateTitle.cpp +++ b/src/GameStateTitle.cpp @@ -30,7 +30,7 @@ GameStateTitle::GameStateTitle() : GameState() { exit_game = false; load_game = false; - loadGraphics(); + logo = loadGraphicSurface("images/menus/logo.png"); // set up buttons button_play = new WidgetButton(mods->locate("images/menus/buttons/button_default.png")); @@ -63,19 +63,6 @@ GameStateTitle::GameStateTitle() : GameState() { inpt->enableMouseEmulation(); } -void GameStateTitle::loadGraphics() { - - SDL_Surface *cleanup = IMG_Load(mods->locate("images/menus/logo.png").c_str()); - - if(!cleanup) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - } else { - // optimize - logo = SDL_DisplayFormatAlpha(cleanup); - SDL_FreeSurface(cleanup); - } -} - void GameStateTitle::logic() { button_play->enabled = ENABLE_PLAYGAME; diff --git a/src/GameStateTitle.h b/src/GameStateTitle.h index e47f335db..12bcbaceb 100644 --- a/src/GameStateTitle.h +++ b/src/GameStateTitle.h @@ -30,13 +30,12 @@ class GameStateTitle : public GameState { SDL_Surface *logo; WidgetButton *button_play; WidgetButton *button_exit; - WidgetButton *button_cfg; + WidgetButton *button_cfg; WidgetLabel *label_version; public: GameStateTitle(); ~GameStateTitle(); - void loadGraphics(); void logic(); void render(); diff --git a/src/GameSwitcher.cpp b/src/GameSwitcher.cpp index c760a3c67..c958f2d95 100644 --- a/src/GameSwitcher.cpp +++ b/src/GameSwitcher.cpp @@ -2,6 +2,7 @@ Copyright © 2011-2012 Clint Bellanger Copyright © 2012 Igor Paliychuk Copyright © 2012 Stefan Beller +Copyright © 2013 Henrik Andersson This file is part of FLARE. @@ -32,6 +33,7 @@ FLARE. If not, see http://www.gnu.org/licenses/ #include "GameSwitcher.h" #include "GameStateTitle.h" +#include "GameStateCutscene.h" #include "SharedResources.h" #include "Settings.h" #include "FileParser.h" @@ -41,8 +43,16 @@ using namespace std; GameSwitcher::GameSwitcher() { - // The initial state is the title screen - currentState = new GameStateTitle(); + // The initial state is the intro cutscene and then title screen + GameStateTitle *title=new GameStateTitle(); + GameStateCutscene *intro = new GameStateCutscene(title); + + currentState = intro; + + if (!intro->load("intro.txt")) { + delete intro; + currentState = title; + } label_fps = new WidgetLabel(); done = false; @@ -118,7 +128,7 @@ void GameSwitcher::loadFPS() { } } infile.close(); - } else fprintf(stderr, "Unable to open menus/fps.txt!\n"); + } // this is a dummy string used to approximate the fps position when aligned to the right font->setFont("font_regular"); diff --git a/src/GetText.cpp b/src/GetText.cpp index eb32c80a5..90e6ae98c 100644 --- a/src/GetText.cpp +++ b/src/GetText.cpp @@ -23,10 +23,12 @@ FLARE. If not, see http://www.gnu.org/licenses/ using namespace std; -GetText::GetText() { - line = ""; - key = ""; - val = ""; +GetText::GetText() + : line("") + , key("") + , val("") + , fuzzy(false) +{ } bool GetText::open(const string& filename) { diff --git a/src/ImageManager.cpp b/src/ImageManager.cpp index f3c6b9f49..59d0229b2 100644 --- a/src/ImageManager.cpp +++ b/src/ImageManager.cpp @@ -52,31 +52,14 @@ SDL_Surface *ImageManager::getSurface(const std::string &name) { vector::iterator found = find(names.begin(), names.end(), name); if (found != names.end()) { int index = distance(names.begin(), found); - if (sprites[index] == 0) { - SDL_Surface *cleanup = NULL; - - if (TEXTURE_QUALITY == false) { - string path = mods->locate(name); - const char * pch = strrchr(path.c_str(), '/' ); - path.insert(pch-path.c_str(), "/noalpha"); - cleanup = IMG_Load(path.c_str()); - if (!cleanup) - printf("failed to load %s\n", path.c_str()); - else - SDL_SetColorKey(cleanup, SDL_SRCCOLORKEY, SDL_MapRGB(cleanup->format, 255, 0, 255)); - } - - if (!cleanup) { - cleanup = IMG_Load(mods->locate(name).c_str()); - } - - if (!cleanup) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - } else { - SDL_Surface *sprite = SDL_DisplayFormatAlpha(cleanup); - SDL_FreeSurface(cleanup); - sprites[index] = sprite; + if (!sprites[index]) { + if (!TEXTURE_QUALITY) { + string newname = string(name); + newname.replace(name.rfind("/"), 0, "/noalpha"); + sprites[index] = loadGraphicSurface(newname, "Falling back to alpha version", false, true); } + if (!sprites[index]) + sprites[index] = loadGraphicSurface(name); } return sprites[index]; } diff --git a/src/InputState.cpp b/src/InputState.cpp index e50aea961..fef0f01cb 100644 --- a/src/InputState.cpp +++ b/src/InputState.cpp @@ -125,12 +125,9 @@ void InputState::defaultJoystickBindings () void InputState::loadKeyBindings() { FileParser infile; - int key1; - int key2; - int cursor; - if (!infile.open(PATH_CONF + FILE_KEYBINDINGS)) { - if (!infile.open(mods->locate("engine/default_keybindings.txt").c_str())) { + if (!infile.open(PATH_CONF + FILE_KEYBINDINGS, "")) { + if (!infile.open(mods->locate("engine/default_keybindings.txt"), "")) { saveKeyBindings(); return; } else saveKeyBindings(); @@ -138,10 +135,10 @@ void InputState::loadKeyBindings() { while (infile.next()) { - key1 = eatFirstInt(infile.val, ','); - key2 = toInt(infile.val); + int key1 = eatFirstInt(infile.val, ','); + int key2 = toInt(infile.val); - cursor = -1; + int cursor = -1; if (infile.key == "cancel") cursor = CANCEL; else if (infile.key == "accept") cursor = ACCEPT; diff --git a/src/ItemManager.cpp b/src/ItemManager.cpp index b57186d17..62310a7bb 100644 --- a/src/ItemManager.cpp +++ b/src/ItemManager.cpp @@ -126,10 +126,7 @@ void ItemManager::loadAll() { shrinkVecToFit(item_sets); if (items.empty()) fprintf(stderr, "No items were found.\n"); - - // TODO: disabled for 0.18, enable again - // we had no item sets in that release. - //if (item_sets.empty()) printf("No item sets were found.\n"); + if (item_sets.empty()) printf("No item sets were found.\n"); } /** @@ -139,10 +136,8 @@ void ItemManager::loadAll() { */ void ItemManager::load(const string& filename) { FileParser infile; - if (!infile.open(filename)) { - fprintf(stderr, "Unable to open %s!\n", filename.c_str()); + if (!infile.open(filename)) return; - } int id = 0; bool id_line = false; @@ -296,7 +291,7 @@ void ItemManager::loadTypes(const string& filename) { } } infile.close(); - } else fprintf(stderr, "Unable to open %s!\n", filename.c_str()); + } } string ItemManager::getItemType(std::string _type) { @@ -310,10 +305,8 @@ string ItemManager::getItemType(std::string _type) { void ItemManager::loadSets(const string& filename) { FileParser infile; - if (!infile.open(filename)) { - fprintf(stderr, "Unable to open %s!\n", filename.c_str()); + if (!infile.open(filename)) return; - } int id = 0; bool id_line; @@ -369,18 +362,9 @@ void ItemManager::loadSets(const string& filename) { /** * Icon sets */ -void ItemManager::loadIcons() { - - icons = IMG_Load(mods->locate("images/icons/icons.png").c_str()); - - if (!icons) { - fprintf(stderr, "Couldn't load icons: %s\n", IMG_GetError()); - } else { - // optimize - SDL_Surface *cleanup = icons; - icons = SDL_DisplayFormatAlpha(icons); - SDL_FreeSurface(cleanup); - } +void ItemManager::loadIcons() +{ + icons = loadGraphicSurface("images/icons/icons.png", "Couldn't load icons"); } /** @@ -390,6 +374,7 @@ void ItemManager::loadIcons() { void ItemManager::renderIcon(ItemStack stack, int x, int y, int size) { if (!icons) return; + SDL_Rect src, dest; dest.x = x; dest.y = y; src.w = src.h = dest.w = dest.h = size; diff --git a/src/ItemManager.h b/src/ItemManager.h index e2cdcc9c4..8a5438b94 100644 --- a/src/ItemManager.h +++ b/src/ItemManager.h @@ -175,8 +175,6 @@ class ItemStack { class ItemManager { private: SDL_Surface *icons; - SDL_Rect src; - SDL_Rect dest; void load(const std::string& filename); void loadTypes(const std::string& filename); diff --git a/src/LootManager.cpp b/src/LootManager.cpp index fefb54983..f01ed2385 100644 --- a/src/LootManager.cpp +++ b/src/LootManager.cpp @@ -57,7 +57,7 @@ LootManager::LootManager(ItemManager *_items, MapRenderer *_map, StatBlock *_her FileParser infile; // load loot animation settings from engine config file - if (infile.open(mods->locate("engine/loot.txt").c_str())) { + if (infile.open(mods->locate("engine/loot.txt"))) { while (infile.next()) { infile.val = infile.val + ','; @@ -96,7 +96,7 @@ LootManager::LootManager(ItemManager *_items, MapRenderer *_map, StatBlock *_her } } infile.close(); - } else fprintf(stderr, "Unable to open engine/loot.txt!\n"); + } // reset current map loot loot.clear(); diff --git a/src/MapRenderer.cpp b/src/MapRenderer.cpp index b5d350c6f..1431929ee 100644 --- a/src/MapRenderer.cpp +++ b/src/MapRenderer.cpp @@ -48,7 +48,6 @@ MapRenderer::MapRenderer(CampaignManager *_camp) , foreground(NULL) , collision(NULL) , shakycam(Point()) - , new_music(false) , backgroundsurface(NULL) , backgroundsurfaceoffset() , repaint_background(false) @@ -64,6 +63,8 @@ MapRenderer::MapRenderer(CampaignManager *_camp) , teleportation(false) , teleport_destination() , respawn_point() + , cutscene(false) + , cutscene_file("") , log_msg("") , shaky_cam_ticks(0) , stash(false) @@ -119,19 +120,14 @@ void MapRenderer::push_enemy_group(Map_Group g) { int MapRenderer::load(string filename) { FileParser infile; - string val; - maprow *cur_layer; - Map_Enemy new_enemy; - Map_Group new_group; - bool enemy_awaiting_queue = false; - bool group_awaiting_queue = false; - bool npc_awaiting_queue = false; - Map_NPC new_npc; + maprow *cur_layer = NULL; clearEvents(); clearLayers(); clearQueues(); + std::queue enemy_groups; + /* unload sounds */ snd->reset(); while (!sids.empty()) { @@ -139,459 +135,451 @@ int MapRenderer::load(string filename) { sids.pop_back(); } - cur_layer = NULL; show_tooltip = false; - if (!infile.open(mods->locate("maps/" + filename))) { - cerr << "Unable to open maps/" << filename << endl; + if (!infile.open(mods->locate("maps/" + filename))) return 0; - } while (infile.next()) { if (infile.new_section) { - if (enemy_awaiting_queue) { - enemies.push(new_enemy); - enemy_awaiting_queue = false; - } - if (npc_awaiting_queue) { - npcs.push(new_npc); - npc_awaiting_queue = false; - } - if (group_awaiting_queue) { - push_enemy_group(new_group); - group_awaiting_queue = false; - } - // for sections that are stored in collections, add a new object here - if (infile.section == "enemy") { - new_enemy = Map_Enemy(); - enemy_awaiting_queue = true; - } - else if (infile.section == "enemygroup") { - new_group.clear(); - group_awaiting_queue = true; - } - else if (infile.section == "npc") { - new_npc.clear(); - npc_awaiting_queue = true; - } - else if (infile.section == "event") { + if (infile.section == "enemy") + enemies.push(Map_Enemy()); + else if (infile.section == "enemygroup") + enemy_groups.push(Map_Group()); + else if (infile.section == "npc") + npcs.push(Map_NPC()); + else if (infile.section == "event") events.push_back(Map_Event()); - } } - if (infile.section == "header") { - if (infile.key == "title") { - this->title = msg->get(infile.val); - } - else if (infile.key == "width") { - this->w = toInt(infile.val); - } - else if (infile.key == "height") { - this->h = toInt(infile.val); - } - else if (infile.key == "tileset") { - this->tileset = infile.val; - } - else if (infile.key == "music") { - if (this->music_filename == infile.val) { - this->new_music = false; - } - else { - this->music_filename = infile.val; - this->new_music = true; - } - } - else if (infile.key == "location") { - spawn.x = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; - spawn.y = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; - spawn_dir = toInt(infile.nextValue()); - } - } - else if (infile.section == "layer") { - if (infile.key == "type") { - cur_layer = new maprow[w]; - if (infile.val == "background") background = cur_layer; - else if (infile.val == "fringe") fringe = cur_layer; - else if (infile.val == "object") object = cur_layer; - else if (infile.val == "foreground") foreground = cur_layer; - else if (infile.val == "collision") collision = cur_layer; - } - else if (infile.key == "format") { - if (infile.val != "dec") { - fprintf(stderr, "ERROR: maploading: The format of a layer must be \"dec\"!\n"); - SDL_Quit(); - exit(1); - } - } - else if (infile.key == "data") { - // layer map data handled as a special case - // The next h lines must contain layer data. TODO: err - for (int j=0; j 1.0f) { - new_group.chance = 1.0f; - } - if (new_group.chance < 0.0f) { - new_group.chance = 0.0f; - } - } - } - else if (infile.section == "npc") { - if (infile.key == "type") { - new_npc.id = infile.val; - } - else if (infile.key == "location") { - new_npc.pos.x = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; - new_npc.pos.y = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; - } - } - else if (infile.section == "event") { - if (infile.key == "type") { - events.back().type = infile.val; - } - else if (infile.key == "location") { - events.back().location.x = toInt(infile.nextValue()); - events.back().location.y = toInt(infile.nextValue()); - events.back().location.w = toInt(infile.nextValue()); - events.back().location.h = toInt(infile.nextValue()); - } - else if (infile.key == "hotspot") { - if (infile.val == "location") { - events.back().hotspot.x = events.back().location.x; - events.back().hotspot.y = events.back().location.y; - events.back().hotspot.w = events.back().location.w; - events.back().hotspot.h = events.back().location.h; - } - else { - events.back().hotspot.x = toInt(infile.nextValue()); - events.back().hotspot.y = toInt(infile.nextValue()); - events.back().hotspot.w = toInt(infile.nextValue()); - events.back().hotspot.h = toInt(infile.nextValue()); - } - } - else if (infile.key == "tooltip") { - events.back().tooltip = msg->get(infile.val); - } - else if (infile.key == "power_path") { - events.back().power_src.x = toInt(infile.nextValue()); - events.back().power_src.y = toInt(infile.nextValue()); - string dest = infile.nextValue(); - if (dest == "hero") { - events.back().targetHero = true; - } - else { - events.back().power_dest.x = toInt(dest); - events.back().power_dest.y = toInt(infile.nextValue()); - } - } - else if (infile.key == "power_damage") { - events.back().damagemin = toInt(infile.nextValue()); - events.back().damagemax = toInt(infile.nextValue()); - } - else if (infile.key == "cooldown") { - events.back().cooldown = parse_duration(infile.val); - } - else { - // new event component - events.back().components.push_back(Event_Component()); - Event_Component *e = &events.back().components.back(); - e->type = infile.key; - - if (infile.key == "intermap") { - e->s = infile.nextValue(); - e->x = toInt(infile.nextValue()); - e->y = toInt(infile.nextValue()); - } - else if (infile.key == "intramap") { - e->x = toInt(infile.nextValue()); - e->y = toInt(infile.nextValue()); - } - else if (infile.key == "mapmod") { - e->s = infile.nextValue(); - e->x = toInt(infile.nextValue()); - e->y = toInt(infile.nextValue()); - e->z = toInt(infile.nextValue()); - - // add repeating mapmods - string repeat_val = infile.nextValue(); - while (repeat_val != "") { - events.back().components.push_back(Event_Component()); - e = &events.back().components.back(); - e->type = infile.key; - e->s = repeat_val; - e->x = toInt(infile.nextValue()); - e->y = toInt(infile.nextValue()); - e->z = toInt(infile.nextValue()); - - repeat_val = infile.nextValue(); - } - } - else if (infile.key == "soundfx") { - e->s = infile.nextValue(); - e->x = e->y = -1; + if (infile.section == "header") + loadHeader(infile); + else if (infile.section == "layer") + loadLayer(infile, &cur_layer); + else if (infile.section == "enemy") + loadEnemy(infile); + else if (infile.section == "enemygroup") + loadEnemyGroup(infile, &enemy_groups.back()); + else if (infile.section == "npc") + loadNPC(infile); + else if (infile.section == "event") + loadEvent(infile); + } - std::string s = infile.nextValue(); - if (s != "") e->x = toInt(s); + infile.close(); - s = infile.nextValue(); - if (s != "") e->y = toInt(s); + while (!enemy_groups.empty()) { + push_enemy_group(enemy_groups.front()); + enemy_groups.pop(); + } - } - else if (infile.key == "loot") { - e->s = infile.nextValue(); - e->x = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; - e->y = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; - - // drop chance - string chance = infile.nextValue(); - if (chance == "fixed") e->z = 0; - else e->z = toInt(chance); - - // quantity min/max - e->a = toInt(infile.nextValue()); - if (e->a < 1) e->a = 1; - e->b = toInt(infile.nextValue()); - if (e->b < e->a) e->b = e->a; - - // add repeating loot - string repeat_val = infile.nextValue(); - while (repeat_val != "") { - events.back().components.push_back(Event_Component()); - e = &events.back().components.back(); - e->type = infile.key; - e->s = repeat_val; - e->x = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; - e->y = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; - - string chance = infile.nextValue(); - if (chance == "fixed") e->z = 0; - else e->z = toInt(chance); - - e->a = toInt(infile.nextValue()); - if (e->a < 1) e->a = 1; - e->b = toInt(infile.nextValue()); - if (e->b < e->a) e->b = e->a; - - repeat_val = infile.nextValue(); - } - } - else if (infile.key == "msg") { - e->s = msg->get(infile.val); - } - else if (infile.key == "shakycam") { - e->x = toInt(infile.val); - } - else if (infile.key == "requires_status") { - e->s = infile.nextValue(); - - // add repeating requires_status - string repeat_val = infile.nextValue(); - while (repeat_val != "") { - events.back().components.push_back(Event_Component()); - e = &events.back().components.back(); - e->type = infile.key; - e->s = repeat_val; - - repeat_val = infile.nextValue(); - } - } - else if (infile.key == "requires_not") { - e->s = infile.nextValue(); - - // add repeating requires_not - string repeat_val = infile.nextValue(); - while (repeat_val != "") { - events.back().components.push_back(Event_Component()); - e = &events.back().components.back(); - e->type = infile.key; - e->s = repeat_val; - - repeat_val = infile.nextValue(); - } - } - else if (infile.key == "requires_level") { - e->x = toInt(infile.nextValue()); - } - else if (infile.key == "requires_not_level") { - e->x = toInt(infile.nextValue()); - } - else if (infile.key == "requires_item") { - e->x = toInt(infile.nextValue()); - - // add repeating requires_item - string repeat_val = infile.nextValue(); - while (repeat_val != "") { - events.back().components.push_back(Event_Component()); - e = &events.back().components.back(); - e->type = infile.key; - e->x = toInt(repeat_val); - - repeat_val = infile.nextValue(); - } - } - else if (infile.key == "set_status") { - e->s = infile.nextValue(); - - // add repeating set_status - string repeat_val = infile.nextValue(); - while (repeat_val != "") { - events.back().components.push_back(Event_Component()); - e = &events.back().components.back(); - e->type = infile.key; - e->s = repeat_val; - - repeat_val = infile.nextValue(); - } - } - else if (infile.key == "unset_status") { - e->s = infile.nextValue(); - - // add repeating unset_status - string repeat_val = infile.nextValue(); - while (repeat_val != "") { - events.back().components.push_back(Event_Component()); - e = &events.back().components.back(); - e->type = infile.key; - e->s = repeat_val; - - repeat_val = infile.nextValue(); - } - } - else if (infile.key == "remove_item") { - e->x = toInt(infile.nextValue()); - - // add repeating remove_item - string repeat_val = infile.nextValue(); - while (repeat_val != "") { - events.back().components.push_back(Event_Component()); - e = &events.back().components.back(); - e->type = infile.key; - e->x = toInt(repeat_val); - - repeat_val = infile.nextValue(); - } - } - else if (infile.key == "reward_xp") { - e->x = toInt(infile.val); - } - else if (infile.key == "power") { - e->x = toInt(infile.val); - } - else if (infile.key == "spawn") { + tset.load(this->tileset); - e->s = infile.nextValue(); - e->x = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; - e->y = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; + // some events automatically trigger when the map loads + // e.g. change map state based on campaign status + executeOnLoadEvents(); - // add repeating spawn - string repeat_val = infile.nextValue(); - while (repeat_val != "") { - events.back().components.push_back(Event_Component()); - e = &events.back().components.back(); - e->type = infile.key; + return 0; +} - e->s = repeat_val; - e->x = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; - e->y = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; +void MapRenderer::loadHeader(FileParser &infile) +{ + if (infile.key == "title") { + this->title = msg->get(infile.val); + } + else if (infile.key == "width") { + this->w = toInt(infile.val); + } + else if (infile.key == "height") { + this->h = toInt(infile.val); + } + else if (infile.key == "tileset") { + this->tileset = infile.val; + } + else if (infile.key == "music") { + loadMusic(infile.val); + } + else if (infile.key == "location") { + spawn.x = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; + spawn.y = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; + spawn_dir = toInt(infile.nextValue()); + } +} - repeat_val = infile.nextValue(); - } - } - else if (infile.key == "npc") { - new_npc.id = infile.val; - e->s = infile.val; - } - else if (infile.key == "music") { - e->s = infile.val; - } - } +void MapRenderer::loadLayer(FileParser &infile, maprow **current_layer) +{ + if (infile.key == "type") { + *current_layer = new maprow[w]; + if (infile.val == "background") background = *current_layer; + else if (infile.val == "fringe") fringe = *current_layer; + else if (infile.val == "object") object = *current_layer; + else if (infile.val == "foreground") foreground = *current_layer; + else if (infile.val == "collision") collision = *current_layer; + } + else if (infile.key == "format") { + if (infile.val != "dec") { + fprintf(stderr, "ERROR: maploading: The format of a layer must be \"dec\"!\n"); + SDL_Quit(); + exit(1); } } + else if (infile.key == "data") { + // layer map data handled as a special case + // The next h lines must contain layer data. TODO: err + for (int j=0; jcategory = infile.val; + } + else if (infile.key == "level") { + group->levelmin = toInt(infile.nextValue()); + group->levelmax = toInt(infile.nextValue()); + } + else if (infile.key == "location") { + group->pos.x = toInt(infile.nextValue()); + group->pos.y = toInt(infile.nextValue()); + group->area.x = toInt(infile.nextValue()); + group->area.y = toInt(infile.nextValue()); + } + else if (infile.key == "number") { + group->numbermin = toInt(infile.nextValue()); + group->numbermax = toInt(infile.nextValue()); + } + else if (infile.key == "chance") { + float n = toInt(infile.nextValue()) / 100.0f; + group->chance = min(1.0f, max(0.0f, n)); + } +} - if (npc_awaiting_queue) - npcs.push(new_npc); +void MapRenderer::loadNPC(FileParser &infile) +{ + if (infile.key == "type") { + npcs.back().id = infile.val; + } + else if (infile.key == "location") { + npcs.back().pos.x = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; + npcs.back().pos.y = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; + } +} - if (group_awaiting_queue) - push_enemy_group(new_group); +void MapRenderer::loadEvent(FileParser &infile) +{ + if (infile.key == "type") { + events.back().type = infile.val; + } + else if (infile.key == "location") { + events.back().location.x = toInt(infile.nextValue()); + events.back().location.y = toInt(infile.nextValue()); + events.back().location.w = toInt(infile.nextValue()); + events.back().location.h = toInt(infile.nextValue()); + } + else if (infile.key == "hotspot") { + if (infile.val == "location") { + events.back().hotspot.x = events.back().location.x; + events.back().hotspot.y = events.back().location.y; + events.back().hotspot.w = events.back().location.w; + events.back().hotspot.h = events.back().location.h; + } + else { + events.back().hotspot.x = toInt(infile.nextValue()); + events.back().hotspot.y = toInt(infile.nextValue()); + events.back().hotspot.w = toInt(infile.nextValue()); + events.back().hotspot.h = toInt(infile.nextValue()); + } + } + else if (infile.key == "tooltip") { + events.back().tooltip = msg->get(infile.val); + } + else if (infile.key == "power_path") { + events.back().power_src.x = toInt(infile.nextValue()); + events.back().power_src.y = toInt(infile.nextValue()); + string dest = infile.nextValue(); + if (dest == "hero") { + events.back().targetHero = true; + } + else { + events.back().power_dest.x = toInt(dest); + events.back().power_dest.y = toInt(infile.nextValue()); + } + } + else if (infile.key == "power_damage") { + events.back().damagemin = toInt(infile.nextValue()); + events.back().damagemax = toInt(infile.nextValue()); + } + else if (infile.key == "cooldown") { + events.back().cooldown = parse_duration(infile.val); + } + else { + loadEventComponent(infile); + } +} - if (this->new_music) { - loadMusic(); - this->new_music = false; +void MapRenderer::loadEventComponent(FileParser &infile) +{ + // new event component + events.back().components.push_back(Event_Component()); + Event_Component *e = &events.back().components.back(); + e->type = infile.key; + + if (infile.key == "intermap") { + e->s = infile.nextValue(); + e->x = toInt(infile.nextValue()); + e->y = toInt(infile.nextValue()); } - tset.load(this->tileset); + else if (infile.key == "intramap") { + e->x = toInt(infile.nextValue()); + e->y = toInt(infile.nextValue()); + } + else if (infile.key == "mapmod") { + e->s = infile.nextValue(); + e->x = toInt(infile.nextValue()); + e->y = toInt(infile.nextValue()); + e->z = toInt(infile.nextValue()); + + // add repeating mapmods + string repeat_val = infile.nextValue(); + while (repeat_val != "") { + events.back().components.push_back(Event_Component()); + e = &events.back().components.back(); + e->type = infile.key; + e->s = repeat_val; + e->x = toInt(infile.nextValue()); + e->y = toInt(infile.nextValue()); + e->z = toInt(infile.nextValue()); + + repeat_val = infile.nextValue(); + } + } + else if (infile.key == "soundfx") { + e->s = infile.nextValue(); + e->x = e->y = -1; - // some events automatically trigger when the map loads - // e.g. change map state based on campaign status - executeOnLoadEvents(); + std::string s = infile.nextValue(); + if (s != "") e->x = toInt(s); - return 0; + s = infile.nextValue(); + if (s != "") e->y = toInt(s); + + } + else if (infile.key == "loot") { + e->s = infile.nextValue(); + e->x = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; + e->y = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; + + // drop chance + string chance = infile.nextValue(); + if (chance == "fixed") e->z = 0; + else e->z = toInt(chance); + + // quantity min/max + e->a = toInt(infile.nextValue()); + if (e->a < 1) e->a = 1; + e->b = toInt(infile.nextValue()); + if (e->b < e->a) e->b = e->a; + + // add repeating loot + string repeat_val = infile.nextValue(); + while (repeat_val != "") { + events.back().components.push_back(Event_Component()); + e = &events.back().components.back(); + e->type = infile.key; + e->s = repeat_val; + e->x = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; + e->y = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; + + string chance = infile.nextValue(); + if (chance == "fixed") e->z = 0; + else e->z = toInt(chance); + + e->a = toInt(infile.nextValue()); + if (e->a < 1) e->a = 1; + e->b = toInt(infile.nextValue()); + if (e->b < e->a) e->b = e->a; + + repeat_val = infile.nextValue(); + } + } + else if (infile.key == "msg") { + e->s = msg->get(infile.val); + } + else if (infile.key == "shakycam") { + e->x = toInt(infile.val); + } + else if (infile.key == "requires_status") { + e->s = infile.nextValue(); + + // add repeating requires_status + string repeat_val = infile.nextValue(); + while (repeat_val != "") { + events.back().components.push_back(Event_Component()); + e = &events.back().components.back(); + e->type = infile.key; + e->s = repeat_val; + + repeat_val = infile.nextValue(); + } + } + else if (infile.key == "requires_not") { + e->s = infile.nextValue(); + + // add repeating requires_not + string repeat_val = infile.nextValue(); + while (repeat_val != "") { + events.back().components.push_back(Event_Component()); + e = &events.back().components.back(); + e->type = infile.key; + e->s = repeat_val; + + repeat_val = infile.nextValue(); + } + } + else if (infile.key == "requires_level") { + e->x = toInt(infile.nextValue()); + } + else if (infile.key == "requires_not_level") { + e->x = toInt(infile.nextValue()); + } + else if (infile.key == "requires_item") { + e->x = toInt(infile.nextValue()); + + // add repeating requires_item + string repeat_val = infile.nextValue(); + while (repeat_val != "") { + events.back().components.push_back(Event_Component()); + e = &events.back().components.back(); + e->type = infile.key; + e->x = toInt(repeat_val); + + repeat_val = infile.nextValue(); + } + } + else if (infile.key == "set_status") { + e->s = infile.nextValue(); + + // add repeating set_status + string repeat_val = infile.nextValue(); + while (repeat_val != "") { + events.back().components.push_back(Event_Component()); + e = &events.back().components.back(); + e->type = infile.key; + e->s = repeat_val; + + repeat_val = infile.nextValue(); + } + } + else if (infile.key == "unset_status") { + e->s = infile.nextValue(); + + // add repeating unset_status + string repeat_val = infile.nextValue(); + while (repeat_val != "") { + events.back().components.push_back(Event_Component()); + e = &events.back().components.back(); + e->type = infile.key; + e->s = repeat_val; + + repeat_val = infile.nextValue(); + } + } + else if (infile.key == "remove_item") { + e->x = toInt(infile.nextValue()); + + // add repeating remove_item + string repeat_val = infile.nextValue(); + while (repeat_val != "") { + events.back().components.push_back(Event_Component()); + e = &events.back().components.back(); + e->type = infile.key; + e->x = toInt(repeat_val); + + repeat_val = infile.nextValue(); + } + } + else if (infile.key == "reward_xp") { + e->x = toInt(infile.val); + } + else if (infile.key == "power") { + e->x = toInt(infile.val); + } + else if (infile.key == "spawn") { + + e->s = infile.nextValue(); + e->x = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; + e->y = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; + + // add repeating spawn + string repeat_val = infile.nextValue(); + while (repeat_val != "") { + events.back().components.push_back(Event_Component()); + e = &events.back().components.back(); + e->type = infile.key; + + e->s = repeat_val; + e->x = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; + e->y = toInt(infile.nextValue()) * UNITS_PER_TILE + UNITS_PER_TILE/2; + + repeat_val = infile.nextValue(); + } + } + else if (infile.key == "npc") { + npcs.back().id = infile.val; + e->s = infile.val; + } + else if (infile.key == "music") { + e->s = infile.val; + } + else if (infile.key == "cutscene") { + e->s = infile.val; + } + else { + fprintf(stderr, "Unknown key value: %s in file %s in section %s\n", infile.key.c_str(), infile.getFileName().c_str(), infile.section.c_str()); + } } void MapRenderer::clearQueues() { @@ -621,7 +609,13 @@ void MapRenderer::clearLayers() { backgroundsurface = 0; } -void MapRenderer::loadMusic() { +void MapRenderer::loadMusic(const std::string &new_music_filename) { + + // keep playing if already the correct track + if (music_filename == new_music_filename) + return; + + music_filename = new_music_filename; if (music) { Mix_HaltMusic(); @@ -726,34 +720,39 @@ void MapRenderer::drawRenderable(vector::iterator r_cursor) { } void MapRenderer::renderIsoLayer(SDL_Surface *wheretorender, Point offset, const unsigned short layerdata[256][256]) { - short int i; - short int j; + int_fast16_t i; // first index of the map array + int_fast16_t j; // second index of the map array SDL_Rect dest; const Point upperright = screen_to_map(0, 0, shakycam.x, shakycam.y); - const short max_tiles_width = (VIEW_W / TILE_W) + 2 * tset.max_size_x; - const short max_tiles_height = ((2 * VIEW_H / TILE_H) + 2 * tset.max_size_y) * 2; + const int_fast16_t max_tiles_width = (VIEW_W / TILE_W) + 2 * tset.max_size_x; + const int_fast16_t max_tiles_height = ((2 * VIEW_H / TILE_H) + 2 * tset.max_size_y) * 2; j = upperright.y / UNITS_PER_TILE - tset.max_size_y + tset.max_size_x; i = upperright.x / UNITS_PER_TILE - tset.max_size_y - tset.max_size_x; - for (unsigned short y = max_tiles_height ; y; --y) { - short tiles_width = 0; + for (uint_fast16_t y = max_tiles_height ; y; --y) { + int_fast16_t tiles_width = 0; // make sure the isometric corners are not rendered: + // corner north west, upper left (i < 0) if (i < -1) { j += i + 1; tiles_width -= i + 1; i = -1; } - const short d = j - h; + // corner north east, upper right (j > mapheight) + const int_fast16_t d = j - h; if (d >= 0) { j -= d; tiles_width += d; i += d; } - const short j_end = std::max((j+i-w+1), std::max(j - max_tiles_width, 0)); + // lower right (south east) corner is covered by (j+i-w+1) + // lower left (south west) corner is caught by having 0 in there, so j>0 + const int_fast16_t j_end = std::max((j+i-w+1), std::max(j - max_tiles_width, static_cast(0))); Point p = map_to_screen(i * UNITS_PER_TILE, j * UNITS_PER_TILE, shakycam.x, shakycam.y); p = center_tile(p); + // draw one horizontal line while (j > j_end) { --j; @@ -761,9 +760,7 @@ void MapRenderer::renderIsoLayer(SDL_Surface *wheretorender, Point offset, const ++tiles_width; p.x += TILE_W; - const unsigned short current_tile = layerdata[i][j]; - - if (current_tile) { + if (const uint_fast16_t current_tile = layerdata[i][j]) { dest.x = p.x - tset.tiles[current_tile].offset.x + offset.x; dest.y = p.y - tset.tiles[current_tile].offset.y + offset.y; // no need to set w and h in dest, as it is ignored @@ -773,6 +770,7 @@ void MapRenderer::renderIsoLayer(SDL_Surface *wheretorender, Point offset, const } j += tiles_width; i -= tiles_width; + // Go one line deeper, the starting position goes zig-zag if (y % 2) i++; else @@ -787,12 +785,12 @@ void MapRenderer::renderIsoBackObjects(vector &r) { } void MapRenderer::renderIsoFrontObjects(vector &r) { - short int i; - short int j; + int_fast16_t i; + int_fast16_t j; SDL_Rect dest; const Point upperright = screen_to_map(0, 0, shakycam.x, shakycam.y); - const short max_tiles_width = (VIEW_W / TILE_W) + 2 * tset.max_size_x; - const short max_tiles_height = ((VIEW_H / TILE_H) + 2 * tset.max_size_y)*2; + const int_fast16_t max_tiles_width = (VIEW_W / TILE_W) + 2 * tset.max_size_x; + const int_fast16_t max_tiles_height = ((VIEW_H / TILE_H) + 2 * tset.max_size_y)*2; vector::iterator r_cursor = r.begin(); vector::iterator r_end = r.end(); @@ -804,8 +802,8 @@ void MapRenderer::renderIsoFrontObjects(vector &r) { while (r_cursor != r_end && ((r_cursor->map_pos.x>>TILE_SHIFT) + (r_cursor->map_pos.y>>TILE_SHIFT) < i + j || (r_cursor->map_pos.x>>TILE_SHIFT) < i)) ++r_cursor; - for (unsigned short y = max_tiles_height ; y; --y) { - short tiles_width = 0; + for (uint_fast16_t y = max_tiles_height ; y; --y) { + int_fast16_t tiles_width = 0; // make sure the isometric corners are not rendered: if (i < -1) { @@ -813,11 +811,11 @@ void MapRenderer::renderIsoFrontObjects(vector &r) { tiles_width -= i + 1; i = -1; } - const short d = j - h; + const int_fast16_t d = j - h; if (d >= 0) { j -= d; tiles_width += d; i += d; } - const short j_end = std::max((j+i-w+1), std::max(j - max_tiles_width, 0)); + const int_fast16_t j_end = std::max((j+i-w+1), std::max(j - max_tiles_width, static_cast(0))); // draw one horizontal line Point p = map_to_screen(i * UNITS_PER_TILE, j * UNITS_PER_TILE, shakycam.x, shakycam.y); @@ -828,9 +826,7 @@ void MapRenderer::renderIsoFrontObjects(vector &r) { ++tiles_width; p.x += TILE_W; - const unsigned short current_tile = object[i][j]; - - if (current_tile) { + if (const uint_fast16_t current_tile = object[i][j]) { dest.x = p.x - tset.tiles[current_tile].offset.x; dest.y = p.y - tset.tiles[current_tile].offset.y; @@ -849,6 +845,7 @@ void MapRenderer::renderIsoFrontObjects(vector &r) { i++; else j++; + while (r_cursor != r_end && ((r_cursor->map_pos.x>>TILE_SHIFT) + (r_cursor->map_pos.y>>TILE_SHIFT) < i + j || (r_cursor->map_pos.x>>TILE_SHIFT) <= i)) ++r_cursor; } @@ -1371,9 +1368,13 @@ bool MapRenderer::executeEvent(Map_Event &ev) { else if (ec->type == "music") { if (this->music_filename != ec->s) { this->music_filename = ec->s; - loadMusic(); + loadMusic(ec->s); } } + else if (ec->type == "cutscene") { + cutscene = true; + cutscene_file = ec->s; + } } if (ev.type == "run_once" || ev.type == "on_load" || ev.type == "on_clear" || destroy_event) return true; diff --git a/src/MapRenderer.h b/src/MapRenderer.h index fb24b17e3..96280a99e 100644 --- a/src/MapRenderer.h +++ b/src/MapRenderer.h @@ -48,6 +48,8 @@ FLARE. If not, see http://www.gnu.org/licenses/ class CampaignManager; class PowerManager; +class FileParser; + // TODO: Move these Map_* classes to its own file. class Map_Group { @@ -60,29 +62,26 @@ class Map_Group { int numbermin; int numbermax; float chance; - void clear() { - category = ""; - pos.x = 0; - pos.y = 0; - area.x = 0; - area.y = 0; - levelmin = 0; - levelmax = 0; - numbermin = 0; - numbermax = 0; - chance = 1.0f; - } + Map_Group() + : category("") + , pos() + , area() + , levelmin(0) + , levelmax(0) + , numbermin(0) + , numbermax(0) + , chance(1.0f) + {} }; class Map_NPC { public: std::string id; Point pos; - void clear() { - id = ""; - pos.x = 0; - pos.y = 0; - } + Map_NPC() + : id("") + , pos() + {} }; class Map_Event { @@ -109,6 +108,8 @@ class Map_Event { , components(std::vector()) , tooltip("") , cooldown(0) + , power_src() + , power_dest() , targetHero(false) , damagemin(0) , damagemax(0) @@ -117,8 +118,6 @@ class Map_Event { { location.x = location.y = location.w = location.h = 0; hotspot.x = hotspot.y = hotspot.w = hotspot.h = 0; - power_src.x = power_src.y = 0; - power_dest.x = power_dest.y = 0; } ~Map_Event() @@ -163,7 +162,17 @@ class MapRenderer { void push_enemy_group(Map_Group g); bool isActive(const Map_Event &e); - void loadMusic(); + void loadMusic(const std::string &new_music_filename); + + typedef unsigned short maprow[256]; + + void loadHeader(FileParser &infile); + void loadLayer(FileParser &infile, maprow **cur_layer); + void loadEnemy(FileParser &infile); + void loadEnemyGroup(FileParser &infile, Map_Group *group); + void loadNPC(FileParser &infile); + void loadEvent(FileParser &infile); + void loadEventComponent(FileParser &infile); // map events std::vector events; @@ -171,8 +180,6 @@ class MapRenderer { // map soundids std::vector sids; - typedef unsigned short maprow[256]; - maprow *background; maprow *fringe; maprow *object; // must exist in each map! @@ -211,7 +218,6 @@ class MapRenderer { void clearQueues(); Point shakycam; - bool new_music; TileSet tset; std::string tileset; std::string music_filename; @@ -236,6 +242,8 @@ class MapRenderer { MapRenderer(CampaignManager *_camp); ~MapRenderer(); + MapRenderer(const MapRenderer ©); // not implemented + int load(std::string filename); void logic(); void render(std::vector &r, std::vector &r_dead); @@ -280,6 +288,10 @@ class MapRenderer { std::string respawn_map; Point respawn_point; + // cutscene handling + bool cutscene; + std::string cutscene_file; + // message handling std::string log_msg; diff --git a/src/MenuActionBar.cpp b/src/MenuActionBar.cpp index a5f221bb1..0a11a4691 100644 --- a/src/MenuActionBar.cpp +++ b/src/MenuActionBar.cpp @@ -168,7 +168,7 @@ void MenuActionBar::update() { } infile.close(); - } else fprintf(stderr, "Unable to open menus/actionbar.txt!\n"); + } // screen areas occupied by the three main sections numberArea.y = mouseArea.y = menuArea.y = window_area.y; @@ -212,40 +212,10 @@ void MenuActionBar::clear() { void MenuActionBar::loadGraphics() { - emptyslot = IMG_Load(mods->locate("images/menus/slot_empty.png").c_str()); - background = IMG_Load(mods->locate("images/menus/actionbar_trim.png").c_str()); - disabled = IMG_Load(mods->locate("images/menus/disabled.png").c_str()); - attention = IMG_Load(mods->locate("images/menus/attention_glow.png").c_str()); - if(!emptyslot || !background || !disabled || !attention) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - } - - // optimize - SDL_Surface *cleanup; - - if (background) { - cleanup = background; - background = SDL_DisplayFormatAlpha(background); - SDL_FreeSurface(cleanup); - } - - if (emptyslot) { - cleanup = emptyslot; - emptyslot = SDL_DisplayFormatAlpha(emptyslot); - SDL_FreeSurface(cleanup); - } - - if (disabled) { - cleanup = disabled; - disabled = SDL_DisplayFormatAlpha(disabled); - SDL_FreeSurface(cleanup); - } - - if (attention) { - cleanup = attention; - attention = SDL_DisplayFormatAlpha(attention); - SDL_FreeSurface(cleanup); - } + emptyslot = loadGraphicSurface("images/menus/slot_empty.png"); + background = loadGraphicSurface("images/menus/actionbar_trim.png"); + disabled = loadGraphicSurface("images/menus/disabled.png"); + attention = loadGraphicSurface("images/menus/attention_glow.png"); } /** diff --git a/src/MenuActiveEffects.cpp b/src/MenuActiveEffects.cpp index 560d1b1fd..0f113f4e1 100644 --- a/src/MenuActiveEffects.cpp +++ b/src/MenuActiveEffects.cpp @@ -59,22 +59,14 @@ MenuActiveEffects::MenuActiveEffects(SDL_Surface *_icons) { } } infile.close(); - } else fprintf(stderr, "Unable to open menus/activeeffects.txt!\n"); + } loadGraphics(); } void MenuActiveEffects::loadGraphics() { - timer = IMG_Load(mods->locate("images/menus/disabled.png").c_str()); - if(!timer) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - } else { - // optimize - SDL_Surface *cleanup = timer; - timer = SDL_DisplayFormatAlpha(timer); - SDL_FreeSurface(cleanup); - } + timer = loadGraphicSurface("images/menus/disabled.png"); } void MenuActiveEffects::renderIcon(int icon_id, int index, int current, int max){ @@ -87,7 +79,7 @@ void MenuActiveEffects::renderIcon(int icon_id, int index, int current, int max) pos.x = window_area.x; pos.y = window_area.y + (index * ICON_SIZE); } - + int columns = icons->w / ICON_SIZE; src.x = (icon_id % columns) * ICON_SIZE; src.y = (icon_id / columns) * ICON_SIZE; diff --git a/src/MenuCharacter.cpp b/src/MenuCharacter.cpp index 259d86c32..5bb1144be 100644 --- a/src/MenuCharacter.cpp +++ b/src/MenuCharacter.cpp @@ -199,14 +199,14 @@ MenuCharacter::MenuCharacter(StatBlock *_stats) { } } infile.close(); - } else fprintf(stderr, "Unable to open menus/character.txt!\n"); + } // stat list statList = new WidgetListBox(STATLIST_COUNT-1+stats->vulnerable.size(), statlist_rows, mods->locate("images/menus/buttons/listbox_char.png")); statList->can_select = false; statList->scrollbar_offset = statlist_scrollbar_offset; - loadGraphics(); + background = loadGraphicSurface("images/menus/character.png"); } void MenuCharacter::update() { @@ -245,20 +245,6 @@ void MenuCharacter::update() { cstat[CSTAT_DEFENSE].setHover(window_area.x+value_pos[5].x, window_area.y+value_pos[5].y, value_pos[5].w, value_pos[5].h); } -void MenuCharacter::loadGraphics() { - - background = IMG_Load(mods->locate("images/menus/character.png").c_str()); - if(!background) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - } else { - // optimize - SDL_Surface *cleanup = background; - background = SDL_DisplayFormatAlpha(background); - SDL_FreeSurface(cleanup); - } - -} - /** * Rebuild all stat values and tooltip info */ diff --git a/src/MenuConfirm.cpp b/src/MenuConfirm.cpp index 1c91773a0..23f129aa7 100644 --- a/src/MenuConfirm.cpp +++ b/src/MenuConfirm.cpp @@ -38,19 +38,7 @@ MenuConfirm::MenuConfirm(const string& _buttonMsg, const string& _boxMsg) : Menu buttonClose = new WidgetButton(mods->locate("images/menus/buttons/button_x.png")); - loadGraphics(); -} - -void MenuConfirm::loadGraphics() { - background = IMG_Load(mods->locate("images/menus/confirm_bg.png").c_str()); - if(!background) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - } else { - // optimize - SDL_Surface *cleanup = background; - background = SDL_DisplayFormatAlpha(background); - SDL_FreeSurface(cleanup); - } + background = loadGraphicSurface("images/menus/confirm_bg.png"); } void MenuConfirm::update() { diff --git a/src/MenuConfirm.h b/src/MenuConfirm.h index 7120a44e3..8cdbff86c 100644 --- a/src/MenuConfirm.h +++ b/src/MenuConfirm.h @@ -27,7 +27,6 @@ FLARE. If not, see http://www.gnu.org/licenses/ class MenuConfirm : public Menu { protected: - void loadGraphics(); WidgetButton *buttonConfirm; WidgetButton *buttonClose; diff --git a/src/MenuEnemy.cpp b/src/MenuEnemy.cpp index ea4999790..6c67d6e83 100644 --- a/src/MenuEnemy.cpp +++ b/src/MenuEnemy.cpp @@ -55,7 +55,7 @@ MenuEnemy::MenuEnemy() { } } infile.close(); - } else fprintf(stderr, "Unable to open menus/enemy.txt!\n"); + } loadGraphics(); enemy = NULL; @@ -64,29 +64,10 @@ MenuEnemy::MenuEnemy() { color_normal = font->getColor("menu_normal"); } -void MenuEnemy::loadGraphics() { - - background = IMG_Load(mods->locate("images/menus/enemy_bar.png").c_str()); - bar_hp = IMG_Load(mods->locate("images/menus/enemy_bar_hp.png").c_str()); - - if(!background || !bar_hp) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - } - - // optimize - SDL_Surface *cleanup; - - if (background) { - cleanup = background; - background = SDL_DisplayFormatAlpha(background); - SDL_FreeSurface(cleanup); - } - - if (bar_hp) { - cleanup = bar_hp; - bar_hp = SDL_DisplayFormatAlpha(bar_hp); - SDL_FreeSurface(cleanup); - } +void MenuEnemy::loadGraphics() +{ + background = loadGraphicSurface("images/menus/enemy_bar.png"); + bar_hp = loadGraphicSurface("images/menus/enemy_bar_hp.png"); } void MenuEnemy::handleNewMap() { diff --git a/src/MenuExit.cpp b/src/MenuExit.cpp index 3ae2f1c53..37a346e05 100644 --- a/src/MenuExit.cpp +++ b/src/MenuExit.cpp @@ -32,19 +32,7 @@ MenuExit::MenuExit() : Menu() { buttonClose = new WidgetButton(mods->locate("images/menus/buttons/button_x.png")); - loadGraphics(); -} - -void MenuExit::loadGraphics() { - background = IMG_Load(mods->locate("images/menus/confirm_bg.png").c_str()); - if(!background) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - } else { - // optimize - SDL_Surface *cleanup = background; - background = SDL_DisplayFormatAlpha(background); - SDL_FreeSurface(cleanup); - } + background = loadGraphicSurface("images/menus/confirm_bg.png"); } void MenuExit::update() { diff --git a/src/MenuInventory.cpp b/src/MenuInventory.cpp index 9c6c29429..79a9c0132 100644 --- a/src/MenuInventory.cpp +++ b/src/MenuInventory.cpp @@ -45,7 +45,7 @@ MenuInventory::MenuInventory(ItemManager *_items, StatBlock *_stats, PowerManage MAX_EQUIPPED = 4; MAX_CARRIED = 64; visible = false; - loadGraphics(); + background = loadGraphicSurface("images/menus/inventory.png"); currency = 0; @@ -93,7 +93,7 @@ MenuInventory::MenuInventory(ItemManager *_items, StatBlock *_stats, PowerManage } } infile.close(); - } else fprintf(stderr, "Unable to open menus/inventory.txt!\n"); + } MAX_EQUIPPED = equipped_area.size(); MAX_CARRIED = carried_cols * carried_rows; @@ -102,19 +102,6 @@ MenuInventory::MenuInventory(ItemManager *_items, StatBlock *_stats, PowerManage color_high = font->getColor("menu_bonus"); } -void MenuInventory::loadGraphics() { - - background = IMG_Load(mods->locate("images/menus/inventory.png").c_str()); - if(!background) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - } else { - // optimize - SDL_Surface *cleanup = background; - background = SDL_DisplayFormatAlpha(background); - SDL_FreeSurface(cleanup); - } -} - void MenuInventory::update() { for (int i=0; ilocate("images/menus/attention_glow.png").c_str()); - - if (!highlight_image) { - fprintf(stderr, "Couldn't load icon highlight image: %s\n", IMG_GetError()); - } else { - // optimize - SDL_Surface *cleanup = highlight_image; - highlight_image = SDL_DisplayFormatAlpha(highlight_image); - SDL_FreeSurface(cleanup); - } +void MenuItemStorage::loadGraphics() +{ + highlight_image = loadGraphicSurface("images/menus/attention_glow.png", "Couldn't load icon highlight image"); } void MenuItemStorage::render() { diff --git a/src/MenuLog.cpp b/src/MenuLog.cpp index d198dd916..4954fc287 100644 --- a/src/MenuLog.cpp +++ b/src/MenuLog.cpp @@ -61,7 +61,7 @@ MenuLog::MenuLog() { } } infile.close(); - } else fprintf(stderr, "Unable to open menus/log.txt!\n"); + } // Store the amount of displayed log messages on each log, and the maximum. for (int i=0; isetFont("font_regular"); paragraph_spacing = font->getLineHeight()/2; - loadGraphics(); + background = loadGraphicSurface("images/menus/log.png"); closeButton = new WidgetButton(mods->locate("images/menus/buttons/button_x.png")); color_normal = font->getColor("menu_normal"); } -void MenuLog::loadGraphics() { - - background = IMG_Load(mods->locate("images/menus/log.png").c_str()); - - if(!background) { - fprintf(stderr, "Could not load image: %s\n", IMG_GetError()); - } else { - // optimize - SDL_Surface *cleanup = background; - background = SDL_DisplayFormatAlpha(background); - SDL_FreeSurface(cleanup); - } - -} - void MenuLog::update() { tabControl->setMainArea(window_area.x + tab_area.x, window_area.y + tab_area.y, tab_area.w, tab_area.h); tabControl->updateHeader(); diff --git a/src/MenuManager.cpp b/src/MenuManager.cpp index 931869c9e..04c086779 100644 --- a/src/MenuManager.cpp +++ b/src/MenuManager.cpp @@ -182,7 +182,7 @@ MenuManager::MenuManager(PowerManager *_powers, StatBlock *_stats, CampaignManag } infile.close(); - } else fprintf(stderr, "Unable to open menus/menus.txt!\n"); + } // Some menus need to be updated to apply their new dimensions act->update(); @@ -213,17 +213,9 @@ MenuManager::MenuManager(PowerManager *_powers, StatBlock *_stats, CampaignManag /** * Icon set shared by all menus */ -void MenuManager::loadIcons() { - - icons = IMG_Load(mods->locate("images/icons/icons.png").c_str()); - if (!icons) { - fprintf(stderr, "Couldn't load icons: %s\n", IMG_GetError()); - } else { - // optimize - SDL_Surface *cleanup = icons; - icons = SDL_DisplayFormatAlpha(icons); - SDL_FreeSurface(cleanup); - } +void MenuManager::loadIcons() +{ + icons = loadGraphicSurface("images/icons/icons.png", "Couldn't load icons"); } void MenuManager::renderIcon(int icon_id, int x, int y) { @@ -423,8 +415,8 @@ void MenuManager::logic() { stack = vendor->click(inpt); if (stack.item > 0) { if (!inv->buy(stack,vendor->getTab())) { - log->add(msg->get("Not enough money."), LOG_TYPE_MESSAGES); - hudlog->add(msg->get("Not enough money.")); + log->add(msg->get("Not enough %s.", CURRENCY), LOG_TYPE_MESSAGES); + hudlog->add(msg->get("Not enough %s.", CURRENCY)); vendor->itemReturn( stack); } else { if (inv->full(stack.item)) { @@ -491,7 +483,7 @@ void MenuManager::logic() { } } else { - // The vendor could have a limited amount of money in the future. It will be tested here. + // The vendor could have a limited amount of currency in the future. It will be tested here. if ((SELL_WITHOUT_VENDOR || vendor->visible) && inv->sell(stack)) { vendor->setTab(VENDOR_SELL); vendor->add(stack); @@ -627,8 +619,8 @@ void MenuManager::logic() { // dropping an item from vendor (we only allow to drop into the carried area) if (inv->visible && isWithin( inv->carried_area, inpt->mouse)) { if (!inv->buy(drag_stack,vendor->getTab())) { - log->add(msg->get("Not enough money."), LOG_TYPE_MESSAGES); - hudlog->add(msg->get("Not enough money.")); + log->add(msg->get("Not enough %s.", CURRENCY), LOG_TYPE_MESSAGES); + hudlog->add(msg->get("Not enough %s.", CURRENCY)); vendor->itemReturn( drag_stack); } else { if (inv->full(drag_stack.item)) { diff --git a/src/MenuMiniMap.cpp b/src/MenuMiniMap.cpp index 6b55a0ed1..ce0b6fb68 100644 --- a/src/MenuMiniMap.cpp +++ b/src/MenuMiniMap.cpp @@ -55,7 +55,7 @@ MenuMiniMap::MenuMiniMap() { } } infile.close(); - } else fprintf(stderr, "Unable to open menus/minimap.txt!\n"); + } // label for map name label = new WidgetLabel(); diff --git a/src/MenuNPCActions.cpp b/src/MenuNPCActions.cpp index 99c869674..afd565edb 100644 --- a/src/MenuNPCActions.cpp +++ b/src/MenuNPCActions.cpp @@ -67,15 +67,13 @@ MenuNPCActions::MenuNPCActions() , first_dialog_node(-1) , current_action(-1) , action_menu(NULL) + , vendor_label(msg->get("Trade")) + , cancel_label(msg->get("Cancel")) , dialog_selected(false) , vendor_selected(false) , cancel_selected(false) , selected_dialog_node(-1) { - - vendor_label = msg->get("Trade"); - cancel_label = msg->get("Cancel"); - // Load config settings FileParser infile; if(infile.open(mods->locate("menus/npc.txt"))) { @@ -120,7 +118,7 @@ MenuNPCActions::MenuNPCActions() } } infile.close(); - } else fprintf(stderr, "Unable to open menus/npc.txt!\n"); + } } void MenuNPCActions::update() { diff --git a/src/MenuPowers.cpp b/src/MenuPowers.cpp index aedde7b24..312969f0a 100644 --- a/src/MenuPowers.cpp +++ b/src/MenuPowers.cpp @@ -142,7 +142,7 @@ MenuPowers::MenuPowers(StatBlock *_stats, PowerManager *_powers, SDL_Surface *_i } infile.close(); - } else fprintf(stderr, "Unable to open menus/powers.txt!\n"); + } loadGraphics(); @@ -193,53 +193,15 @@ void MenuPowers::update() { void MenuPowers::loadGraphics() { - background = IMG_Load(mods->locate("images/menus/powers.png").c_str()); + background = loadGraphicSurface("images/menus/powers.png"); + powers_unlock = loadGraphicSurface("images/menus/powers_unlock.png"); + overlay_disabled = loadGraphicSurface("images/menus/disabled.png"); if (tree_image_files.empty()) { - tree_surf.push_back(IMG_Load(mods->locate("images/menus/powers_tree.png").c_str())); + tree_surf.push_back(loadGraphicSurface("images/menus/powers_tree.png")); } else { - for (unsigned int i=0; ilocate("images/menus/" + tree_image_files[i]).c_str())); - } - - powers_unlock = IMG_Load(mods->locate("images/menus/powers_unlock.png").c_str()); - overlay_disabled = IMG_Load(mods->locate("images/menus/disabled.png").c_str()); - - if(!background || !powers_unlock || !overlay_disabled) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - } - for (unsigned int i=0; ilocate("images/menus/stash.png").c_str()); - if (!background) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - } else { - // optimize - SDL_Surface *cleanup = background; - background = SDL_DisplayFormatAlpha(background); - SDL_FreeSurface(cleanup); - } -} - void MenuStash::update() { slots_area.x += window_area.x; slots_area.y += window_area.y; diff --git a/src/MenuStash.h b/src/MenuStash.h index 8fce45007..8acb996dd 100644 --- a/src/MenuStash.h +++ b/src/MenuStash.h @@ -43,9 +43,6 @@ class MenuStash : public Menu { StatBlock *stats; WidgetButton *closeButton; - void loadGraphics(); - SDL_Surface *background; - int STASH_SLOTS; // label and widget positions diff --git a/src/MenuStatBar.cpp b/src/MenuStatBar.cpp index 16ba28aa5..a3ba02992 100644 --- a/src/MenuStatBar.cpp +++ b/src/MenuStatBar.cpp @@ -72,36 +72,17 @@ MenuStatBar::MenuStatBar(std::string type) { } } infile.close(); - } else fprintf(stderr, "Unable to open menus/%s.txt!\n", type.c_str()); + } loadGraphics(type); color_normal = font->getColor("menu_normal"); } -void MenuStatBar::loadGraphics(std::string type) { - - background = IMG_Load(mods->locate("images/menus/bar_"+type+"_background.png").c_str()); - bar = IMG_Load(mods->locate("images/menus/bar_"+type+".png").c_str()); - - if(!background || !bar) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - } - - // optimize - SDL_Surface *cleanup; - - if (background) { - cleanup = background; - background = SDL_DisplayFormatAlpha(background); - SDL_FreeSurface(cleanup); - } - - if (bar) { - cleanup = bar; - bar = SDL_DisplayFormatAlpha(bar); - SDL_FreeSurface(cleanup); - } +void MenuStatBar::loadGraphics(std::string type) +{ + background = loadGraphicSurface("images/menus/bar_" + type + "_background.png"); + bar = loadGraphicSurface("images/menus/bar_" + type + ".png"); } void MenuStatBar::update(int _stat_cur, int _stat_max, Point _mouse, std::string _custom_string) { diff --git a/src/MenuTalker.cpp b/src/MenuTalker.cpp index 61b3357cf..68cf4e6c5 100644 --- a/src/MenuTalker.cpp +++ b/src/MenuTalker.cpp @@ -58,7 +58,7 @@ MenuTalker::MenuTalker(MenuManager *_menu, CampaignManager *_camp) { // fonts font_who = font_dialog = "font_regular"; - loadGraphics(); + loadGraphicSurface("images/menus/dialog_box.png"); // Load config settings FileParser infile; @@ -102,25 +102,11 @@ MenuTalker::MenuTalker(MenuManager *_menu, CampaignManager *_camp) { } } infile.close(); - } else fprintf(stderr, "Unable to open menus/talker.txt!\n"); + } color_normal = font->getColor("menu_normal"); } -void MenuTalker::loadGraphics() { - - SDL_FreeSurface(background); - background = IMG_Load(mods->locate("images/menus/dialog_box.png").c_str()); - if(!background) { - fprintf(stderr, "Couldn't load image dialog_box.png: %s\n", IMG_GetError()); - } else { - // optimize - SDL_Surface *cleanup = background; - background = SDL_DisplayFormatAlpha(background); - SDL_FreeSurface(cleanup); - } -} - void MenuTalker::chooseDialogNode(int request_dialog_node) { event_cursor = 0; @@ -285,18 +271,7 @@ void MenuTalker::setHero(const string& name, const string& portrait_filename) { hero_name = name; SDL_FreeSurface(portrait); - portrait = IMG_Load(mods->locate("images/portraits/" + portrait_filename + ".png").c_str()); - if(!portrait) { - fprintf(stderr, "Couldn't load portrait: %s\n", IMG_GetError()); - - // keep playing, just don't show this portrait - } - else { - // optimize - SDL_Surface *cleanup = portrait; - portrait = SDL_DisplayFormatAlpha(portrait); - SDL_FreeSurface(cleanup); - } + portrait = loadGraphicSurface("images/portraits/" + portrait_filename + ".png", "Couldn't load portrait"); } MenuTalker::~MenuTalker() { diff --git a/src/MenuTalker.h b/src/MenuTalker.h index 489d652ca..92cd8c36c 100644 --- a/src/MenuTalker.h +++ b/src/MenuTalker.h @@ -44,8 +44,6 @@ class MenuTalker : public Menu { CampaignManager *camp; MenuManager *menu; - void loadGraphics(); - SDL_Surface *background; SDL_Surface *portrait; SDL_Surface *msg_buffer; std::string hero_name; diff --git a/src/MenuVendor.cpp b/src/MenuVendor.cpp index 9dc3d859a..5e1bdf185 100644 --- a/src/MenuVendor.cpp +++ b/src/MenuVendor.cpp @@ -46,7 +46,7 @@ MenuVendor::MenuVendor(ItemManager *_items, StatBlock *_stats) , buyback_stock() , talker_visible(false) { - loadGraphics(); + background = loadGraphicSurface("images/menus/vendor.png"); tabControl->setTabTitle(VENDOR_BUY,msg->get("Inventory")); tabControl->setTabTitle(VENDOR_SELL,msg->get("Buyback")); @@ -74,23 +74,11 @@ MenuVendor::MenuVendor(ItemManager *_items, StatBlock *_stats) } } infile.close(); - } else fprintf(stderr, "Unable to open menus/vendor.txt!\n"); + } VENDOR_SLOTS = slots_cols * slots_rows; } -void MenuVendor::loadGraphics() { - background = IMG_Load(mods->locate("images/menus/vendor.png").c_str()); - if(!background) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - } else { - // optimize - SDL_Surface *cleanup = background; - background = SDL_DisplayFormatAlpha(background); - SDL_FreeSurface(cleanup); - } -} - void MenuVendor::update() { slots_area.x += window_area.x; slots_area.y += window_area.y; diff --git a/src/MenuVendor.h b/src/MenuVendor.h index 8ac360aa2..0e3e8a20d 100644 --- a/src/MenuVendor.h +++ b/src/MenuVendor.h @@ -46,8 +46,6 @@ class MenuVendor : public Menu { WidgetButton *closeButton; WidgetTabControl *tabControl; - void loadGraphics(); - SDL_Surface *background; MenuItemStorage stock[2]; // items the vendor currently has in stock int VENDOR_SLOTS; diff --git a/src/NPC.cpp b/src/NPC.cpp index 2db3c5be9..3f6f99963 100644 --- a/src/NPC.cpp +++ b/src/NPC.cpp @@ -176,7 +176,7 @@ void NPC::load(const string& npc_id, int hero_level) { } } infile.close(); - } else fprintf(stderr, "Unable to open npcs/%s.txt!\n", npc_id.c_str()); + } loadGraphics(filename_portrait); } @@ -188,20 +188,8 @@ void NPC::loadGraphics(const string& filename_portrait) { animationSet = anim->getAnimationSet(anim_name); activeAnimation = animationSet->getAnimation(); } - if (filename_portrait != "") { - portrait = IMG_Load(mods->locate("images/portraits/" + filename_portrait + ".png").c_str()); - if(!portrait) { - fprintf(stderr, "Couldn't load NPC portrait: %s\n", IMG_GetError()); - } - - SDL_SetColorKey( portrait, SDL_SRCCOLORKEY, SDL_MapRGB(portrait->format, 255, 0, 255) ); - - // optimize - SDL_Surface *cleanup = portrait; - portrait = SDL_DisplayFormatAlpha(portrait); - SDL_FreeSurface(cleanup); - } - + if (filename_portrait != "") + portrait = loadGraphicSurface("images/portraits/" + filename_portrait + ".png", "Couldn't load NPC portrait", false, true); } /** diff --git a/src/NPCManager.cpp b/src/NPCManager.cpp index 9252cfa6a..c611bf9b4 100644 --- a/src/NPCManager.cpp +++ b/src/NPCManager.cpp @@ -52,7 +52,7 @@ NPCManager::NPCManager(MapRenderer *_map, LootManager *_loot, ItemManager *_item } } infile.close(); - } else fprintf(stderr, "Unable to open engine/tooltips.txt!\n"); + } } void NPCManager::addRenders(std::vector &r) { diff --git a/src/NPCManager.h b/src/NPCManager.h index a9a5d6188..fc2e65180 100644 --- a/src/NPCManager.h +++ b/src/NPCManager.h @@ -51,7 +51,9 @@ class NPCManager { public: NPCManager(MapRenderer *_map, LootManager *_loot, ItemManager *_items, StatBlock *stats); + NPCManager(const NPCManager ©); // not implemented ~NPCManager(); + std::vector npcs; void handleNewMap(); void logic(); diff --git a/src/PowerManager.cpp b/src/PowerManager.cpp index 88449909a..849859d04 100644 --- a/src/PowerManager.cpp +++ b/src/PowerManager.cpp @@ -33,6 +33,7 @@ FLARE. If not, see http://www.gnu.org/licenses/ #include "SharedResources.h" #include "StatBlock.h" #include "MapCollision.h" +#include "Utils.h" #include "UtilsFileSystem.h" #include "UtilsMath.h" #include "UtilsParsing.h" @@ -81,10 +82,8 @@ void PowerManager::loadAll() { */ void PowerManager::loadPowers(const std::string& filename) { FileParser infile; - if (!infile.open(filename)) { - fprintf(stderr, "Unable to open %s!\n", filename.c_str()); + if (!infile.open(filename)) return; - } int input_id = 0; bool skippingEntry = false; @@ -317,67 +316,6 @@ void PowerManager::handleNewMap(MapCollision *_collider) { collider = _collider; } -// convert cartesian to polar theta where (x1,x2) is the origin -float PowerManager::calcTheta(int x1, int y1, int x2, int y2) { - - float pi = 3.1415926535898f; - - // calculate base angle - float dx = (float)x2 - (float)x1; - float dy = (float)y2 - (float)y1; - int exact_dx = x2 - x1; - float theta; - - // convert cartesian to polar coordinates - if (exact_dx == 0) { - if (dy > 0.0) theta = pi/2.0f; - else theta = -pi/2.0f; - } - else { - theta = atan(dy/dx); - if (dx < 0.0 && dy >= 0.0) theta += pi; - if (dx < 0.0 && dy < 0.0) theta -= pi; - } - return theta; -} - -/** - * Change direction to face the target map location - */ -int PowerManager::calcDirection(int origin_x, int origin_y, int target_x, int target_y) { - - // TODO: use calcTheta instead and check for the areas between -PI and PI - - // inverting Y to convert map coordinates to standard cartesian coordinates - int dx = target_x - origin_x; - int dy = origin_y - target_y; - - // avoid div by zero - if (dx == 0) { - if (dy > 0) return 3; - else return 7; - } - - float slope = ((float)dy)/((float)dx); - if (0.5 <= slope && slope <= 2.0) { - if (dy > 0) return 4; - else return 0; - } - if (-0.5 <= slope && slope <= 0.5) { - if (dx > 0) return 5; - else return 1; - } - if (-2.0 <= slope && slope <= -0.5) { - if (dx > 0) return 6; - else return 2; - } - if (2.0 <= slope || -2.0 >= slope) { - if (dy > 0) return 3; - else return 7; - } - return 0; -} - /** * Keep two points within a certain range */ diff --git a/src/PowerManager.h b/src/PowerManager.h index c0b01e32b..cd5f86509 100644 --- a/src/PowerManager.h +++ b/src/PowerManager.h @@ -276,7 +276,6 @@ class PowerManager { int loadSFX(const std::string& filename); - int calcDirection(int origin_x, int origin_y, int target_x, int target_y); Point limitRange(int range, Point src, Point target); Point targetNeighbor(Point target, int range); Point targetNeighbor(Point target, int range, bool ignore_blocked); @@ -300,7 +299,6 @@ class PowerManager { void handleNewMap(MapCollision *_collider); bool activate(int power_index, StatBlock *src_stats, Point target); - float calcTheta(int x1, int y1, int x2, int y2); const Power &getPower(unsigned id) {assert(id < powers.size()); return powers[id];} bool canUsePower(unsigned id) const; bool hasValidTarget(int power_index, StatBlock *src_stats, Point target); diff --git a/src/QuestLog.cpp b/src/QuestLog.cpp index 8185f7fae..6c4493d28 100644 --- a/src/QuestLog.cpp +++ b/src/QuestLog.cpp @@ -102,10 +102,8 @@ void QuestLog::loadIndex(const std::string& filename) { */ void QuestLog::load(const std::string& filename) { FileParser infile; - if (!infile.open(mods->locate("quests/" + filename))) { - fprintf(stderr, "Unable to open quests/%s!\n", filename.c_str()); + if (!infile.open(mods->locate("quests/" + filename))) return; - } while (infile.next()) { if (infile.new_section) { diff --git a/src/Settings.cpp b/src/Settings.cpp index b987b2985..e29f3bc66 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -325,7 +325,7 @@ static ConfigEntry * getConfigEntry(const std::string & name) { void loadTilesetSettings() { FileParser infile; // load tileset settings from engine config - if (infile.open(mods->locate("engine/tileset_config.txt").c_str())) { + if (infile.open(mods->locate("engine/tileset_config.txt"), "Unable to open engine/tileset_config.txt! Defaulting to 64x32 isometric tiles.\n")) { while (infile.next()) { if (infile.key == "units_per_tile") { UNITS_PER_TILE = toInt(infile.val); @@ -344,7 +344,7 @@ void loadTilesetSettings() { } } infile.close(); - } else fprintf(stderr, "Unable to open engine/tileset_config.txt! Defaulting to 64x32 isometric tiles.\n"); + } // Init automatically calculated parameters TILE_SHIFT = log2(UNITS_PER_TILE); @@ -364,7 +364,7 @@ void loadMiscSettings() { FileParser infile; // load miscellaneous settings from engine config // misc.txt - if (infile.open(mods->locate("engine/misc.txt").c_str())) { + if (infile.open(mods->locate("engine/misc.txt"))) { while (infile.next()) { if (infile.key == "save_hpmp") { if (toInt(infile.val) == 1) @@ -388,9 +388,9 @@ void loadMiscSettings() { } infile.close(); - } else fprintf(stderr, "Unable to open engine/misc.txt!\n"); + } // resolutions.txt - if (infile.open(mods->locate("engine/resolutions.txt").c_str())) { + if (infile.open(mods->locate("engine/resolutions.txt"))) { while (infile.next()) { if (infile.key == "menu_frame_width") FRAME_W = toInt(infile.val); @@ -409,9 +409,9 @@ void loadMiscSettings() { } } infile.close(); - } else fprintf(stderr, "Unable to open engine/resolutions.txt!\n"); + } // gameplay.txt - if (infile.open(mods->locate("engine/gameplay.txt").c_str())) { + if (infile.open(mods->locate("engine/gameplay.txt"))) { while (infile.next()) { if (infile.key == "enable_playgame") { if (toInt(infile.val) == 1) @@ -421,9 +421,9 @@ void loadMiscSettings() { } } infile.close(); - } else fprintf(stderr, "Unable to open engine/gameplay.txt!\n"); + } // combat.txt - if (infile.open(mods->locate("engine/combat.txt").c_str())) { + if (infile.open(mods->locate("engine/combat.txt"))) { while (infile.next()) { if (infile.key == "max_absorb_percent") { MAX_ABSORB = toInt(infile.val); @@ -436,9 +436,9 @@ void loadMiscSettings() { } } infile.close(); - } else fprintf(stderr, "Unable to open engine/combat.txt!\n"); + } // elements.txt - if (infile.open(mods->locate("engine/elements.txt").c_str())) { + if (infile.open(mods->locate("engine/elements.txt"))) { Element e; ELEMENTS.clear(); while (infile.next()) { @@ -451,9 +451,9 @@ void loadMiscSettings() { } } infile.close(); - } else fprintf(stderr, "Unable to open engine/elements.txt!\n"); + } // classes.txt - if (infile.open(mods->locate("engine/classes.txt").c_str())) { + if (infile.open(mods->locate("engine/classes.txt"))) { HeroClass c; HERO_CLASSES.clear(); while (infile.next()) { @@ -492,7 +492,7 @@ void loadMiscSettings() { } } infile.close(); - } else fprintf(stderr, "Unable to open engine/classes.txt!\n"); + } // Make a default hero class if none were found if (HERO_CLASSES.empty()) { @@ -513,8 +513,8 @@ bool loadSettings() { // try read from file FileParser infile; - if (!infile.open(PATH_CONF + FILE_SETTINGS)) { - if (!infile.open(mods->locate("engine/default_settings.txt").c_str())) { + if (!infile.open(PATH_CONF + FILE_SETTINGS, "")) { + if (!infile.open(mods->locate("engine/default_settings.txt"), "")) { saveSettings(); return true; } else saveSettings(); diff --git a/src/SoundManager.cpp b/src/SoundManager.cpp index a9b094004..e3b525f52 100644 --- a/src/SoundManager.cpp +++ b/src/SoundManager.cpp @@ -170,11 +170,8 @@ SoundManager::SoundID SoundManager::load(const std::string& filename, const std: lsnd.chunk = Mix_LoadWAV(realfilename.c_str()); lsnd.refCnt = 1; if (!lsnd.chunk) { - // TODO: disabled for v0.18 as some sounds are just not needed such as - // EnemyManager critdeath sound: Loading sound ../flare-game/soundfx/enemies/wyvern_critdie.ogg (soundfx/enemies/wyvern_critdie.ogg) failed: Mix_LoadWAV_RW with NULL src - // EnemyManager mental attack sound: Loading sound ../flare-game/soundfx/enemies/antlion_ment.ogg (soundfx/enemies/antlion_ment.ogg) failed: Mix_LoadWAV_RW with NULL src - //fprintf(stderr, "%s: Loading sound %s (%s) failed: %s \n", errormessage.c_str(), - // realfilename.c_str(), filename.c_str(), Mix_GetError()); + fprintf(stderr, "%s: Loading sound %s (%s) failed: %s \n", errormessage.c_str(), + realfilename.c_str(), filename.c_str(), Mix_GetError()); return 0; } diff --git a/src/StatBlock.cpp b/src/StatBlock.cpp index 6867437cd..ab1bc421d 100644 --- a/src/StatBlock.cpp +++ b/src/StatBlock.cpp @@ -217,10 +217,8 @@ bool sortLoot(const EnemyLoot &a, const EnemyLoot &b) { */ void StatBlock::load(const string& filename) { FileParser infile; - if (!infile.open(mods->locate(filename))) { - fprintf(stderr, "Unable to open %s!\n", filename.c_str()); + if (!infile.open(mods->locate(filename))) return; - } int num = 0; string loot_token; @@ -579,10 +577,8 @@ bool StatBlock::canUsePower(const Power &power, unsigned powerid) const { void StatBlock::loadHeroStats() { // Redefine numbers from config file if present FileParser infile; - if (!infile.open(mods->locate("engine/stats.txt"))) { - fprintf(stderr, "Unable to open engine/stats.txt!\n"); + if (!infile.open(mods->locate("engine/stats.txt"))) return; - } while (infile.next()) { int value = toInt(infile.val); @@ -672,10 +668,9 @@ void StatBlock::loadHeroStats() { statsLoaded = true; // Load the XP table as well - if (!infile.open(mods->locate("engine/xp_table.txt"))) { - fprintf(stderr, "Unable to open engine/xp_table.txt!\n"); + if (!infile.open(mods->locate("engine/xp_table.txt"))) return; - } + while(infile.next()) { xp_table[toInt(infile.key) - 1] = toInt(infile.val); } diff --git a/src/TileSet.cpp b/src/TileSet.cpp index f429f67b2..691c49be5 100644 --- a/src/TileSet.cpp +++ b/src/TileSet.cpp @@ -56,33 +56,14 @@ void TileSet::reset() { } void TileSet::loadGraphics(const std::string& filename) { - if (sprites) SDL_FreeSurface(sprites); + if (sprites) + SDL_FreeSurface(sprites); - if (TEXTURE_QUALITY == false) - sprites = IMG_Load((mods->locate("images/tilesets/noalpha/" + filename)).c_str()); + if (!TEXTURE_QUALITY) + sprites = loadGraphicSurface("images/tilesets/noalpha/" + filename, "Couldn't load image", false, true); - if (!sprites) { - sprites = IMG_Load((mods->locate("images/tilesets/" + filename)).c_str()); - if (!sprites) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - } - } else { - alpha_background = false; - } - - if (sprites) { - // only set a color key if the tile set doesn't have an alpha channel - // the color ke is specified in the tilesetdef file like this: - // transparency=r,g,b - if (!alpha_background) { - SDL_SetColorKey( sprites, SDL_SRCCOLORKEY, SDL_MapRGB(sprites->format, trans_r, trans_g, trans_b) ); - } - - // optimize - SDL_Surface *cleanup = sprites; - sprites = SDL_DisplayFormatAlpha(sprites); - SDL_FreeSurface(cleanup); - } + if (!sprites) + sprites = loadGraphicSurface("images/tilesets/" + filename); } void TileSet::load(const std::string& filename) { @@ -147,7 +128,7 @@ void TileSet::load(const std::string& filename) { } infile.close(); loadGraphics(img); - } else fprintf(stderr, "Unable to open tilesetdefs/%s!\n", filename.c_str()); + } current_map = filename; } diff --git a/src/Utils.cpp b/src/Utils.cpp index e903716ff..02912479f 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -1,6 +1,7 @@ /* Copyright © 2011-2012 Clint Bellanger Copyright © 2012 Stefan Beller +Copyright © 2013 Henrik Andersson This file is part of FLARE. @@ -165,6 +166,43 @@ bool isWithin(SDL_Rect r, Point target) { return target.x >= r.x && target.y >= r.y && target.x < r.x+r.w && target.y < r.y+r.h; } + +Uint32 readPixel(SDL_Surface *surface, int x, int y) +{ + SDL_LockSurface(surface); + int bpp = surface->format->BytesPerPixel; + Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; + Uint32 pixel; + + switch (bpp) { + case 1: + pixel = *p; + break; + + case 2: + pixel = *(Uint16 *)p; + break; + + case 3: + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) + pixel = p[0] << 16 | p[1] << 8 | p[2]; + else + pixel = p[0] | p[1] << 8 | p[2] << 16; + break; + + case 4: + pixel = *(Uint32 *)p; + break; + + default: + SDL_UnlockSurface(surface); + return 0; + } + + SDL_UnlockSurface(surface); + return pixel; +} + /* * Set the pixel at (x, y) to the given value * NOTE: The surface must be locked before calling this! @@ -306,6 +344,26 @@ SDL_Surface* createSurface(int width, int height) { return surface; } +SDL_Surface* loadGraphicSurface(std::string filename, std::string errormessage, bool IfNotFoundExit, bool HavePinkColorKey) +{ + SDL_Surface *ret = NULL; + SDL_Surface *cleanup = IMG_Load(mods->locate(filename).c_str()); + if(!cleanup) { + if (!errormessage.empty()) + fprintf(stderr, "%s: %s\n", errormessage.c_str(), IMG_GetError()); + if (IfNotFoundExit) { + SDL_Quit(); + exit(1); + } + } else { + if (HavePinkColorKey) + SDL_SetColorKey(cleanup, SDL_SRCCOLORKEY, SDL_MapRGB(cleanup->format, 255, 0, 255)); + ret = SDL_DisplayFormatAlpha(cleanup); + SDL_FreeSurface(cleanup); + } + return ret; +} + /* * Returns false if a pixel at Point px is transparent * @@ -362,3 +420,113 @@ bool checkPixel(Point px, SDL_Surface *surface) { return true; } + +SDL_Surface* scaleSurface(SDL_Surface *source, int width, int height) +{ + if(!source || !width || !height) + return 0; + + double _stretch_factor_x, _stretch_factor_y; + SDL_Surface *_ret = SDL_CreateRGBSurface(source->flags, width, height, + source->format->BitsPerPixel, + source->format->Rmask, + source->format->Gmask, + source->format->Bmask, + source->format->Amask); + + _stretch_factor_x = width / (double)source->w; + _stretch_factor_y = height / (double)source->h; + + for(Uint32 y = 0; y < (Uint32)source->h; y++) + for(Uint32 x = 0; x < (Uint32)source->w; x++) + { + Uint32 spixel = readPixel(source, x, y); + for(Uint32 o_y = 0; o_y < _stretch_factor_y; ++o_y) + for(Uint32 o_x = 0; o_x < _stretch_factor_x; ++o_x) + { + Uint32 dx = (Sint32)(_stretch_factor_x * x) + o_x; + Uint32 dy = (Sint32)(_stretch_factor_y * y) + o_y; + drawPixel(_ret, dx, dy, spixel); + } + } + + return _ret; +} + +int calcDirection(const Point &src, const Point &dst) +{ + return calcDirection(src.x, src.y, dst.x, dst.y); +} + +int calcDirection(int x0, int y0, int x1, int y1) +{ + // TODO: use calcTheta instead and check for the areas between -PI and PI + + // inverting Y to convert map coordinates to standard cartesian coordinates + int dx = x1 - x0; + int dy = y0 - y1; + + // avoid div by zero + if (dx == 0) { + if (dy > 0) return 3; + else return 7; + } + + float slope = ((float)dy)/((float)dx); + if (0.5 <= slope && slope <= 2.0) { + if (dy > 0) return 4; + else return 0; + } + if (-0.5 <= slope && slope <= 0.5) { + if (dx > 0) return 5; + else return 1; + } + if (-2.0 <= slope && slope <= -0.5) { + if (dx > 0) return 6; + else return 2; + } + if (2.0 <= slope || -2.0 >= slope) { + if (dy > 0) return 3; + else return 7; + } + return 0; +} + +// convert cartesian to polar theta where (x1,x2) is the origin +float calcTheta(int x1, int y1, int x2, int y2) { + + float pi = 3.1415926535898f; + + // calculate base angle + float dx = (float)x2 - (float)x1; + float dy = (float)y2 - (float)y1; + int exact_dx = x2 - x1; + float theta; + + // convert cartesian to polar coordinates + if (exact_dx == 0) { + if (dy > 0.0) theta = pi/2.0f; + else theta = -pi/2.0f; + } + else { + theta = atan(dy/dx); + if (dx < 0.0 && dy >= 0.0) theta += pi; + if (dx < 0.0 && dy < 0.0) theta -= pi; + } + return theta; +} + +void setupSDLVideoMode(unsigned width, unsigned height) +{ + Uint32 flags = 0; + + if (FULLSCREEN) flags = flags | SDL_FULLSCREEN; + if (DOUBLEBUF) flags = flags | SDL_DOUBLEBUF; + if (HWSURFACE) + flags = flags | SDL_HWSURFACE | SDL_HWACCEL; + else + flags = flags | SDL_SWSURFACE; + + screen = SDL_SetVideoMode (width, height, 0, flags); +} + diff --git a/src/Utils.h b/src/Utils.h index 90192cb7c..9cc4c635f 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -1,6 +1,7 @@ /* Copyright © 2011-2012 Clint Bellanger Copyright © 2012 Stefan Beller +Copyright © 2013 Henrik Andersson This file is part of FLARE. @@ -57,8 +58,8 @@ class Renderable { Renderable() : sprite(0) , src(SDL_Rect()) - , map_pos(Point()) - , offset(Point()) + , map_pos() + , offset() , prio(0) {} }; @@ -94,13 +95,19 @@ Point map_to_collision(Point p); Point collision_to_map(Point p); FPoint calcVector(Point pos, int direction, int dist); double calcDist(Point p1, Point p2); +float calcTheta(int x1, int y1, int x2, int y2); +int calcDirection(int x0, int y0, int x1, int y1); +int calcDirection(const Point &src, const Point &dst); bool isWithin(Point center, int radius, Point target); bool isWithin(SDL_Rect r, Point target); + +Uint32 readPixel(SDL_Surface *screen, int x, int y); void drawPixel(SDL_Surface *screen, int x, int y, Uint32 color); void drawLine(SDL_Surface *screen, int x0, int y0, int x1, int y1, Uint32 color); void drawLine(SDL_Surface *screen, Point pos0, Point pos1, Uint32 color); bool checkPixel(Point px, SDL_Surface *surface); + /** * Creates a SDL_Surface. * The SDL_HWSURFACE or SDL_SWSURFACE flag is set according @@ -119,4 +126,33 @@ SDL_Surface* createAlphaSurface(int width, int height); */ SDL_Surface* createSurface(int width, int height); +SDL_Surface* scaleSurface(SDL_Surface *source, int width, int height); + +/** + * @brief loadGraphicSurface loads an image from a file. + * @param filename + * The parameter filename is mandatory and specifies the image to be + * loaded. The filename will be located via the modmanager. + * @param errormessage + * This is an optional parameter, which defines which error message + * should be displayed. If the errormessage is an empty string, no error + * message will be printed at all. + * @param IfNotFoundExit + * If this optional boolean parameter is set to true, the program will + * shutdown sdl and quit, if the specified image is not found. + * @param HavePinkColorKey + * This optional parameter specifies whether a color key with + * RGB(0xff, 0, 0xff) should be applied to the image. + * @return + * Returns the SDL_Surface of the specified image or NULL if not + * successful + */ + +SDL_Surface* loadGraphicSurface(std::string filename, + std::string errormessage = "Couldn't load image", + bool IfNotFoundExit = false, + bool HavePinkColorKey = false); + +void setupSDLVideoMode(unsigned width, unsigned height); + #endif diff --git a/src/WidgetButton.cpp b/src/WidgetButton.cpp index 7d53c2d60..83127b6b4 100644 --- a/src/WidgetButton.cpp +++ b/src/WidgetButton.cpp @@ -52,24 +52,16 @@ WidgetButton::WidgetButton(const std::string& _fileName) void WidgetButton::loadArt() { // load button images - SDL_Surface *cleanup = IMG_Load(fileName.c_str()); + buttons = loadGraphicSurface(fileName); - if(!cleanup) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); + if (!buttons) { SDL_Quit(); exit(1); // or abort ?? } - - // optimize - buttons = SDL_DisplayFormatAlpha(cleanup); - SDL_FreeSurface(cleanup); } bool WidgetButton::checkClick() { - if (checkClick(inpt->mouse.x,inpt->mouse.y)) - return true; - else - return false; + return checkClick(inpt->mouse.x,inpt->mouse.y); } /** @@ -80,11 +72,7 @@ bool WidgetButton::checkClick(int x, int y) { Point mouse(x,y); // Change the hover state - if (isWithin(pos, mouse)) { - hover = true; - } else { - hover = false; - } + hover = isWithin(pos, mouse); // Check the tooltip tip_new = checkTooltip(mouse); diff --git a/src/WidgetCheckBox.cpp b/src/WidgetCheckBox.cpp index d817441fd..2f7c0436b 100644 --- a/src/WidgetCheckBox.cpp +++ b/src/WidgetCheckBox.cpp @@ -32,21 +32,12 @@ FLARE. If not, see http://www.gnu.org/licenses/ using namespace std; -WidgetCheckBox::WidgetCheckBox (const string & fname) - : imgFileName(fname), - cb(NULL), +WidgetCheckBox::WidgetCheckBox (const string &fname) + : cb(NULL), checked(false), pressed(false) { - SDL_Surface * tmp = IMG_Load(imgFileName.c_str()); - if (NULL == tmp) { - fprintf(stderr, "Could not load image \"%s\" error \"%s\"\n", - imgFileName.c_str(), IMG_GetError()); - SDL_Quit(); - exit(1); - } - cb = SDL_DisplayFormatAlpha(tmp); - SDL_FreeSurface(tmp); + cb = loadGraphicSurface(fname, "Couldn't load image", true, false); pos.w = cb->w; pos.h = cb->h / 2; @@ -71,10 +62,7 @@ void WidgetCheckBox::unCheck () bool WidgetCheckBox::checkClick() { - if (checkClick(inpt->mouse.x,inpt->mouse.y)) - return true; - else - return false; + return checkClick(inpt->mouse.x,inpt->mouse.y); } bool WidgetCheckBox::checkClick (int x, int y) { @@ -86,12 +74,12 @@ bool WidgetCheckBox::checkClick (int x, int y) { if (pressed && !inpt->lock[MAIN1]) { // this is a button release pressed = false; - if (isWithin(pos, mouse)) { // the button release is done over the widget + if (isWithin(pos, mouse)) { // the button release is done over the widget // toggle the state of the check button checked = !checked; - // activate upon release - return true; - } + // activate upon release + return true; + } } if (inpt->pressing[MAIN1]) { diff --git a/src/WidgetCheckBox.h b/src/WidgetCheckBox.h index 6d507f570..06b90e0e1 100644 --- a/src/WidgetCheckBox.h +++ b/src/WidgetCheckBox.h @@ -29,7 +29,7 @@ class Widget; class WidgetCheckBox : public Widget { public: - WidgetCheckBox (const std::string & fname); + WidgetCheckBox (const std::string &fname); ~WidgetCheckBox (); void Check (); @@ -40,7 +40,6 @@ class WidgetCheckBox : public Widget { void render (SDL_Surface *target = NULL); private: - std::string imgFileName; SDL_Surface * cb; bool checked; bool pressed; diff --git a/src/WidgetInput.cpp b/src/WidgetInput.cpp index a7ef910fa..3a8d30d8f 100644 --- a/src/WidgetInput.cpp +++ b/src/WidgetInput.cpp @@ -48,19 +48,7 @@ WidgetInput::WidgetInput() { void WidgetInput::loadGraphics(const string& filename) { // load input background image - background = IMG_Load(filename.c_str()); - - if(!background) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - SDL_Quit(); - exit(1); - } - - // optimize - SDL_Surface *cleanup = background; - background = SDL_DisplayFormatAlpha(background); - SDL_FreeSurface(cleanup); - + background = loadGraphicSurface(filename, "Couldn't load image", true); } void WidgetInput::logic() { @@ -72,11 +60,7 @@ bool WidgetInput::logic(int x, int y) { Point mouse(x, y); // Change the hover state - if (isWithin(pos, mouse)) { - hover = true; - } else { - hover = false; - } + hover = isWithin(pos, mouse); if (checkClick()) { inFocus = true; diff --git a/src/WidgetListBox.cpp b/src/WidgetListBox.cpp index 25160222d..8b6a89c9b 100644 --- a/src/WidgetListBox.cpp +++ b/src/WidgetListBox.cpp @@ -51,43 +51,21 @@ WidgetListBox::WidgetListBox(int amount, int height, const std::string& _fileNam , can_select(true) , scrollbar_offset(0) { - listboxs = NULL; + // load ListBox images + listboxs = loadGraphicSurface(fileName, "Couldn't load image", true); click = NULL; - for (int i=0; iw; pos.h = (listboxs->h / 3); // height of one item } -void WidgetListBox::loadArt() { - - // load ListBox images - listboxs = IMG_Load(fileName.c_str()); - - if(!listboxs) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - SDL_Quit(); - exit(1); // or abort ?? - } - - // optimize - SDL_Surface *cleanup = listboxs; - listboxs = SDL_DisplayFormatAlpha(listboxs); - SDL_FreeSurface(cleanup); -} - bool WidgetListBox::checkClick() { - if (checkClick(inpt->mouse.x,inpt->mouse.y)) - return true; - else - return false; + return checkClick(inpt->mouse.x,inpt->mouse.y); } /** diff --git a/src/WidgetListBox.h b/src/WidgetListBox.h index 9546502ab..e6aed8678 100644 --- a/src/WidgetListBox.h +++ b/src/WidgetListBox.h @@ -64,7 +64,6 @@ class WidgetListBox : public Widget { WidgetListBox(int amount, int height, const std::string& _fileName); ~WidgetListBox(); - void loadArt(); bool checkClick(); bool checkClick(int x, int y); TooltipData checkTooltip(Point mouse); diff --git a/src/WidgetScrollBar.cpp b/src/WidgetScrollBar.cpp index c1d64430d..bfbc3ea87 100644 --- a/src/WidgetScrollBar.cpp +++ b/src/WidgetScrollBar.cpp @@ -47,19 +47,7 @@ WidgetScrollBar::WidgetScrollBar(const std::string& _fileName) void WidgetScrollBar::loadArt() { - // load ScrollBar images - scrollbars = IMG_Load(fileName.c_str()); - - if(!scrollbars) { - fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError()); - SDL_Quit(); - exit(1); // or abort ?? - } - - // optimize - SDL_Surface *cleanup = scrollbars; - scrollbars = SDL_DisplayFormatAlpha(scrollbars); - SDL_FreeSurface(cleanup); + scrollbars = loadGraphicSurface(fileName, "Couldn't load image", true); } int WidgetScrollBar::checkClick() { diff --git a/src/WidgetSlider.cpp b/src/WidgetSlider.cpp index 07d19e2fc..dab0aaf76 100644 --- a/src/WidgetSlider.cpp +++ b/src/WidgetSlider.cpp @@ -34,22 +34,17 @@ FLARE. If not, see http://www.gnu.org/licenses/ using namespace std; WidgetSlider::WidgetSlider (const string & fname) - : imgFileName(fname) - , sl(NULL) + : sl(NULL) , pressed(false) , minimum(0) , maximum(0) , value(0) { - SDL_Surface * tmp = IMG_Load(imgFileName.c_str()); - if (NULL == tmp) { - fprintf(stderr, "Could not load image \"%s\" error \"%s\"\n", - imgFileName.c_str(), IMG_GetError()); + sl = loadGraphicSurface(fname); + if (!sl) { SDL_Quit(); exit(1); } - sl = SDL_DisplayFormatAlpha(tmp); - SDL_FreeSurface(tmp); pos.w = sl->w; pos.h = sl->h / 2; @@ -67,10 +62,7 @@ WidgetSlider::~WidgetSlider () bool WidgetSlider::checkClick() { - if (checkClick(inpt->mouse.x,inpt->mouse.y)) - return true; - else - return false; + return checkClick(inpt->mouse.x,inpt->mouse.y); } diff --git a/src/WidgetSlider.h b/src/WidgetSlider.h index a506a00bf..210544ff9 100644 --- a/src/WidgetSlider.h +++ b/src/WidgetSlider.h @@ -40,7 +40,6 @@ class WidgetSlider : public Widget { SDL_Rect pos_knob; // This is the position of the slider's knob within the screen private: - std::string imgFileName; SDL_Surface * sl; bool pressed; int minimum; diff --git a/src/WidgetTabControl.cpp b/src/WidgetTabControl.cpp index d643888c0..8adb6e7ea 100644 --- a/src/WidgetTabControl.cpp +++ b/src/WidgetTabControl.cpp @@ -120,24 +120,13 @@ void WidgetTabControl::updateHeader() */ void WidgetTabControl::loadGraphics() { - activeTabSurface = IMG_Load(mods->locate("images/menus/tab_active.png").c_str()); - inactiveTabSurface = IMG_Load(mods->locate("images/menus/tab_inactive.png").c_str()); + activeTabSurface = loadGraphicSurface("images/menus/tab_active.png"); + inactiveTabSurface = loadGraphicSurface("images/menus/tab_inactive.png"); - if(!activeTabSurface || !inactiveTabSurface) { - fprintf(stderr, "Could not load image: %s\n", IMG_GetError()); + if (!activeTabSurface || !inactiveTabSurface) { SDL_Quit(); exit(1); } - - SDL_Surface *cleanup; - - cleanup = activeTabSurface; - activeTabSurface = SDL_DisplayFormatAlpha(activeTabSurface); - SDL_FreeSurface(cleanup); - - cleanup = inactiveTabSurface; - inactiveTabSurface = SDL_DisplayFormatAlpha(inactiveTabSurface); - SDL_FreeSurface(cleanup); } void WidgetTabControl::logic() diff --git a/src/WidgetTooltip.cpp b/src/WidgetTooltip.cpp index 4e3035c1c..0b4db2366 100644 --- a/src/WidgetTooltip.cpp +++ b/src/WidgetTooltip.cpp @@ -34,7 +34,7 @@ WidgetTooltip::WidgetTooltip() { FileParser infile; // load tooltip settings from engine config file - if (infile.open(mods->locate("engine/tooltips.txt").c_str())) { + if (infile.open(mods->locate("engine/tooltips.txt"))) { while (infile.next()) { if (infile.key == "tooltip_offset") offset = toInt(infile.val); @@ -45,8 +45,6 @@ WidgetTooltip::WidgetTooltip() { } infile.close(); } - else fprintf(stderr, "Unable to open engine/tooltips.txt!\n"); - } /** diff --git a/src/main.cpp b/src/main.cpp index c598a0bc9..5271c0185 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -77,16 +77,8 @@ static void init() { SDL_WM_SetIcon(titlebar_icon, NULL); // Create window - Uint32 flags = 0; + setupSDLVideoMode(VIEW_W, VIEW_H); - if (FULLSCREEN) flags = flags | SDL_FULLSCREEN; - if (DOUBLEBUF) flags = flags | SDL_DOUBLEBUF; - if (HWSURFACE) - flags = flags | SDL_HWSURFACE | SDL_HWACCEL; - else - flags = flags | SDL_SWSURFACE; - - screen = SDL_SetVideoMode (VIEW_W, VIEW_H, 0, flags); if (screen == NULL) { fprintf (stderr, "Error during SDL_SetVideoMode: %s\n", SDL_GetError());