mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-22 18:23:50 +00:00
294 lines
8.6 KiB
C++
294 lines
8.6 KiB
C++
/* $Id$ */
|
|
/*
|
|
Copyright (C) 2003 by David White <davidnwhite@optusnet.com.au>
|
|
Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License.
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY.
|
|
|
|
See the COPYING file for more details.
|
|
*/
|
|
#include "game_events.hpp"
|
|
#include "intro.hpp"
|
|
#include "language.hpp"
|
|
#include "playlevel.hpp"
|
|
#include "playturn.hpp"
|
|
#include "preferences.hpp"
|
|
#include "replay.hpp"
|
|
#include "sound.hpp"
|
|
|
|
#include <iostream>
|
|
|
|
LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
|
|
config* level, CVideo& video,
|
|
game_state& state_of_game,
|
|
std::vector<config*>& story)
|
|
{
|
|
const int num_turns = atoi(level->values["turns"].c_str());
|
|
gamestatus status(num_turns);
|
|
|
|
gamemap map(terrain_config,read_file("data/maps/" + level->values["map"]));
|
|
|
|
CKey key;
|
|
typedef std::map<gamemap::location,unit> units_map;
|
|
units_map units;
|
|
|
|
std::vector<team> teams;
|
|
|
|
std::vector<config*>& unit_cfg = level->children["side"];
|
|
for(std::vector<config*>::iterator ui = unit_cfg.begin();
|
|
ui != unit_cfg.end(); ++ui) {
|
|
unit new_unit(gameinfo, **ui);
|
|
if(ui == unit_cfg.begin()) {
|
|
for(std::vector<unit>::iterator it =
|
|
state_of_game.available_units.begin();
|
|
it != state_of_game.available_units.end(); ++it) {
|
|
if(it->can_recruit()) {
|
|
new_unit = *it;
|
|
state_of_game.available_units.erase(it);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string gold = (*ui)->values["gold"];
|
|
if(gold.empty())
|
|
gold = "100";
|
|
|
|
int ngold = ::atoi(gold.c_str());
|
|
if(ui == unit_cfg.begin() && state_of_game.gold >= 0)
|
|
ngold = state_of_game.gold;
|
|
|
|
units.insert(std::pair<gamemap::location,unit>(
|
|
map.starting_position(new_unit.side()), new_unit));
|
|
teams.push_back(team(**ui,ngold));
|
|
|
|
//if there are additional starting units on this side
|
|
std::vector<config*>& starting_units = (*ui)->children["unit"];
|
|
for(std::vector<config*>::iterator su = starting_units.begin();
|
|
su != starting_units.end(); ++su) {
|
|
unit new_unit(gameinfo,**su);
|
|
const std::string& x = (*su)->values["x"];
|
|
const std::string& y = (*su)->values["y"];
|
|
|
|
const gamemap::location loc(**su);
|
|
if(x.size() == 0 || y.size() == 0 || !map.on_board(loc)) {
|
|
state_of_game.available_units.push_back(new_unit);
|
|
} else {
|
|
units.insert(std::pair<gamemap::location,unit>(loc,new_unit));
|
|
}
|
|
}
|
|
}
|
|
|
|
display gui(units,video,map,status,teams);
|
|
const preferences::display_manager prefs_disp_manager(&gui);
|
|
|
|
if(recorder.skipping() == false) {
|
|
for(std::vector<config*>::iterator story_i = story.begin();
|
|
story_i != story.end(); ++story_i) {
|
|
show_intro(gui,**story_i);
|
|
}
|
|
|
|
show_map_scene(gui,*level);
|
|
}
|
|
|
|
const std::string& music = level->values["music"];
|
|
if(!music.empty()) {
|
|
sound::play_music(music);
|
|
}
|
|
|
|
game_events::manager events_manager(*level,gui,map,units,
|
|
state_of_game,gameinfo);
|
|
|
|
//find a list of 'items' (i.e. overlays) on the level, and add them
|
|
std::vector<config*>& overlays = level->children["item"];
|
|
for(std::vector<config*>::iterator overlay = overlays.begin();
|
|
overlay != overlays.end(); ++overlay) {
|
|
gui.add_overlay(gamemap::location(**overlay),
|
|
(*overlay)->values["image"]);
|
|
}
|
|
|
|
const double scroll_speed = 30.0;
|
|
const double zoom_amount = 5.0;
|
|
|
|
for(units_map::iterator i = units.begin(); i != units.end(); ++i) {
|
|
i->second.new_turn();
|
|
}
|
|
|
|
bool left_button = false, right_button = false;
|
|
|
|
gamemap::location selected_hex;
|
|
|
|
gui.scroll_to_tile(map.starting_position(1).x,map.starting_position(1).y,
|
|
display::WARP);
|
|
|
|
bool replaying = (recorder.empty() == false);
|
|
|
|
std::cout << "starting main loop\n";
|
|
for(bool first_time = true; true; first_time = false) {
|
|
try {
|
|
|
|
if(first_time) {
|
|
update_locker lock_display(gui,recorder.skipping());
|
|
game_events::fire("start");
|
|
}
|
|
|
|
gui.invalidate_game_status();
|
|
|
|
for(std::vector<team>::iterator team_it = teams.begin();
|
|
team_it != teams.end(); ++team_it) {
|
|
const int player_number = (team_it - teams.begin()) + 1;
|
|
|
|
calculate_healing(gui,map,units,player_number);
|
|
|
|
//scroll the map to the leader
|
|
const units_map::iterator leader =
|
|
find_leader(units,player_number);
|
|
|
|
if(leader != units.end() && !recorder.skipping()) {
|
|
gui.scroll_to_tile(leader->first.x,leader->first.y);
|
|
}
|
|
|
|
if(replaying) {
|
|
replaying = do_replay(gui,map,gameinfo,units,teams,
|
|
player_number,status,state_of_game);
|
|
}
|
|
|
|
if(!replaying && team_it->is_human()) {
|
|
play_turn(gameinfo,state_of_game,status,terrain_config,
|
|
level, video, key, gui, events_manager, map,
|
|
teams, player_number, units);
|
|
|
|
if(game_config::debug)
|
|
display::clear_debug_highlights();
|
|
|
|
} else if(!replaying) {
|
|
ai::do_move(gui,map,gameinfo,units,teams,
|
|
player_number,status);
|
|
|
|
gui.invalidate_unit();
|
|
gui.invalidate_game_status();
|
|
gui.invalidate_all();
|
|
gui.draw();
|
|
SDL_Delay(1000);
|
|
}
|
|
|
|
for(units_map::iterator uit = units.begin();
|
|
uit != units.end(); ++uit) {
|
|
if(uit->second.side() == player_number)
|
|
uit->second.end_turn();
|
|
}
|
|
|
|
game_events::pump();
|
|
|
|
const int victory = check_victory(units);
|
|
if(victory > 1) {
|
|
throw end_level_exception(DEFEAT);
|
|
} else if(victory == 1) {
|
|
throw end_level_exception(VICTORY);
|
|
}
|
|
}
|
|
|
|
//time has run out
|
|
if(!status.next_turn()) {
|
|
game_events::fire("time over");
|
|
throw end_level_exception(DEFEAT);
|
|
}
|
|
|
|
std::stringstream event_stream;
|
|
event_stream << "turn " << status.turn();
|
|
|
|
{
|
|
update_locker lock_display(gui,recorder.skipping());
|
|
game_events::fire(event_stream.str());
|
|
}
|
|
|
|
std::map<int,int> expenditure;
|
|
for(units_map::iterator i = units.begin();
|
|
i != units.end(); ++i) {
|
|
i->second.new_turn();
|
|
expenditure[i->second.side()]++;
|
|
}
|
|
|
|
int team_num = 1;
|
|
for(std::vector<team>::iterator it = teams.begin();
|
|
it != teams.end(); ++it, ++team_num) {
|
|
it->new_turn();
|
|
it->spend_gold(expenditure[team_num]);
|
|
}
|
|
} catch(end_level_exception& end_level) {
|
|
|
|
if(end_level.result == QUIT || end_level.result == REPLAY) {
|
|
return end_level.result;
|
|
} else if(end_level.result == DEFEAT) {
|
|
try {
|
|
game_events::fire("defeat");
|
|
} catch(end_level_exception&) {
|
|
}
|
|
|
|
gui::show_dialog(gui,NULL,
|
|
string_table["defeat_heading"],
|
|
string_table["defeat_message"],
|
|
gui::OK_ONLY);
|
|
return DEFEAT;
|
|
} else if(end_level.result == VICTORY) {
|
|
try {
|
|
game_events::fire("victory");
|
|
} catch(end_level_exception&) {
|
|
}
|
|
|
|
//add all the units that survived the scenario
|
|
for(std::map<gamemap::location,unit>::iterator un =
|
|
units.begin(); un != units.end(); ++un) {
|
|
if(un->second.side() == 1) {
|
|
un->second.new_level();
|
|
state_of_game.available_units.
|
|
push_back(un->second);
|
|
}
|
|
}
|
|
|
|
const int remaining_gold = teams[0].gold();
|
|
const int finishing_bonus_per_turn =
|
|
map.towers().size()*game_config::tower_income;
|
|
const int turns_left = status.number_of_turns() - status.turn();
|
|
const int finishing_bonus = end_level.gold_bonus ?
|
|
(finishing_bonus_per_turn * turns_left) : 0;
|
|
state_of_game.gold = (remaining_gold+finishing_bonus)/2;
|
|
|
|
gui::show_dialog(gui,NULL,string_table["victory_heading"],
|
|
string_table["victory_message"],gui::OK_ONLY);
|
|
std::stringstream report;
|
|
report << string_table["remaining_gold"] << ": "
|
|
<< remaining_gold << "\n";
|
|
if(end_level.gold_bonus) {
|
|
report << string_table["early_finish_bonus"] << ": "
|
|
<< finishing_bonus_per_turn
|
|
<< " " << string_table["per_turn"] << "\n"
|
|
<< string_table["turns_finished_early"] << ": "
|
|
<< string_table["bonus"] << ": "
|
|
<< finishing_bonus << "\n"
|
|
<< string_table["gold"] << ": "
|
|
<< (remaining_gold+finishing_bonus);
|
|
}
|
|
|
|
report << "\n" << string_table["fifty_percent"] << "\n"
|
|
<< string_table["retained_gold"] << ": "
|
|
<< state_of_game.gold;
|
|
|
|
gui::show_dialog(gui,NULL,"",report.str(),gui::OK_ONLY);
|
|
return VICTORY;
|
|
}
|
|
} //end catch
|
|
catch(replay::error& e) {
|
|
gui::show_dialog(gui,NULL,"","The file you loaded is corrupt "
|
|
"or from a different version of the game",gui::OK_ONLY);
|
|
return DEFEAT;
|
|
}
|
|
|
|
} //end for(;;)
|
|
|
|
return QUIT;
|
|
}
|