diff --git a/data/scenarios/Wesbowl.cfg b/data/scenarios/Wesbowl.cfg new file mode 100644 index 00000000000..37934ef9543 --- /dev/null +++ b/data/scenarios/Wesbowl.cfg @@ -0,0 +1,721 @@ +[multiplayer] + name=Wesbowl + map=wesbowl + turns=20 + id=multiplayer1 + + {DAWN} + {MORNING} + {AFTERNOON} + {DUSK} + {FIRST_WATCH} + {SECOND_WATCH} + + [side] + side=1 + enemy=2 + canrecruit=1 + controller=human + [/side] + [side] + side=2 + enemy=1 + canrecruit=1 + controller=human + [/side] + +#define WESBOWL_UNIT SIDE FACING TYPE X Y + [unit] + side={SIDE} + type={TYPE} + facing={FACING} + x={X} + y={Y} + [/unit] +#enddef + +#define WESBOWL_SIDE LEADER SIDE FACING X A B C D E F G H I J K + [if] + [have_unit] + type={LEADER} + side={SIDE} + [/have_unit] + [then] + {WESBOWL_UNIT {SIDE} {FACING} ({A}) {X} 10} + {WESBOWL_UNIT {SIDE} {FACING} ({B}) {X} 8} + {WESBOWL_UNIT {SIDE} {FACING} ({C}) {X} 12} + {WESBOWL_UNIT {SIDE} {FACING} ({D}) {X} 6} + {WESBOWL_UNIT {SIDE} {FACING} ({E}) {X} 14} + {WESBOWL_UNIT {SIDE} {FACING} ({F}) {X} 4} + {WESBOWL_UNIT {SIDE} {FACING} ({G}) {X} 16} + {WESBOWL_UNIT {SIDE} {FACING} ({H}) {X} 2} + {WESBOWL_UNIT {SIDE} {FACING} ({I}) {X} 18} + {WESBOWL_UNIT {SIDE} {FACING} ({J}) {X} 1} + {WESBOWL_UNIT {SIDE} {FACING} ({K}) {X} 20} + [/then] + [/if] +#enddef + +#define WESBOWL_SIDE_DEFS SIDE FACING X + {WESBOWL_SIDE (Elvish Lord) {SIDE} {FACING} {X} Merman (Elvish Fighter) (Elvish Fighter) (Elvish Archer) (Elvish Archer) Mage Mage (Wose Sapling) (Wose Sapling) (Elvish Scout) (Elvish Scout)} + {WESBOWL_SIDE (Orcish Warlord) {SIDE} {FACING} {X} Naga (Orcish Grunt) (Orcish Grunt) (Orcish Archer) (Orcish Archer) Lizardman Lizardman (Troll Whelp) (Troll Whelp) (Wolf Rider) (Wolf Rider)} + {WESBOWL_SIDE Lich {SIDE} {FACING} {X} (Vampire Bat) Skeleton Skeleton (Skeleton Archer) (Skeleton Archer) Skeleton Skeleton (Dark Adept) (Dark Adept) Ghost Ghost} + {WESBOWL_SIDE (Dwarvish Lord) {SIDE} {FACING} {X} Poacher (Dwarvish Fighter) (Dwarvish Fighter) (Dwarvish Thunderer) (Dwarvish Thunderer) Footpad Footpad Thief Thief (Gryphon Rider) (Gryphon Rider)} + {WESBOWL_SIDE General {SIDE} {FACING} {X} Naga Spearman Spearman Fencer Fencer Horseman Horseman (Heavy Infantry) (Heavy Infantry) Cavalry Cavalry} +#enddef + + [event] + name=prestart + {WESBOWL_SIDE_DEFS 1 normal 5} + {WESBOWL_SIDE_DEFS 2 reverse 37} + + {VARIABLE b1x 7} + {VARIABLE b1y 9} + {VARIABLE b2x 35} + {VARIABLE b2y 11} + {VARIABLE b1down yes} + {VARIABLE b2down yes} + + {VARIABLE redscore 0} + {VARIABLE bluescore 0} + + [item] + image=misc/ball.png + x,y=$b1x,$b1y + [/item] + [item] + image=misc/ball.png + x,y=$b2x,$b2y + [/item] + [/event] + + [event] + name=moveto + first_time_only=no + [filter] + x,y=$b1x,$b1y + [/filter] + [store_unit] + variable=unit + [filter] + x,y=$b1x,$b1y + [/filter] + [/store_unit] + [if] + [variable] + name=b1down + equals=yes + [/variable] + [variable] + name=unit.variables.has_ball2 + not_equals=yes + [/variable] + [then] + [removeitem] + x,y=$b1x,$b1y + [/removeitem] + {VARIABLE b1down no} + {VARIABLE unit.variables.has_ball1 yes} + [unstore_unit] + variable=unit + [/unstore_unit] + [unit_overlay] + x,y=$b1x,$b1y + image=misc/ball.png + [/unit_overlay] + [/then] + [/if] + [/event] + + [event] + name=die + first_time_only=no + + [store_unit] + variable=unit + [filter] + x,y=$x1,$y1 + [/filter] + [/store_unit] + + [if] + [variable] + name=unit.variables.has_ball1 + equals=yes + [/variable] + [then] + [remove_unit_overlay] + x,y=$x1,$y1 + image=misc/ball.png + [/remove_unit_overlay] + [item] + x,y=$x1,$y1 + image=misc/ball.png + [/item] + {VARIABLE b1x $x1} + {VARIABLE b1y $y1} + {VARIABLE unit.variables.has_ball1 no} + {VARIABLE b1down yes} + [unstore_unit] + variable=unit + [/unstore_unit] + [/then] + [/if] + [/event] + + [event] + name=moveto + first_time_only=no + [filter] + side=1 + x=38-40 + y=1-20 + [/filter] + [store_unit] + variable=unit + [filter] + x,y=$x1,$y1 + [/filter] + [/store_unit] + [if] + [variable] + name=unit.variables.has_ball1 + equals=yes + [/variable] + [then] + [set_variable] + name=redscore + add=1 + [/set_variable] + [message] + speaker=narrator + message="Red scores! Current score is $redscore-$bluescore" + [/message] + {VARIABLE b1x 7} + {VARIABLE b1y 9} + {VARIABLE unit.variables.has_ball1 no} + {VARIABLE b1down yes} + + [unstore_unit] + variable=unit + [/unstore_unit] + [remove_unit_overlay] + x,y=$x1,$y1 + image=misc/ball.png + [/remove_unit_overlay] + [item] + x,y=$b1x,$b1y + image=misc/ball.png + [/item] + [/then] + [/if] + [/event] + + [event] + name=moveto + first_time_only=no + [filter] + side=2 + x=1-3 + y=1-20 + [/filter] + [store_unit] + variable=unit + [filter] + x,y=$x1,$y1 + [/filter] + [/store_unit] + [if] + [variable] + name=unit.variables.has_ball1 + equals=yes + [/variable] + [then] + [set_variable] + name=bluescore + add=1 + [/set_variable] + [message] + speaker=narrator + message="Blue scores! Current score is $redscore-$bluescore" + [/message] + {VARIABLE b1x 35} + {VARIABLE b1y 11} + {VARIABLE unit.variables.has_ball1 no} + {VARIABLE b1down yes} + + [unstore_unit] + variable=unit + [/unstore_unit] + [remove_unit_overlay] + x,y=$x1,$y1 + image=misc/ball.png + [/remove_unit_overlay] + [item] + x,y=$b1x,$b1y + image=misc/ball.png + [/item] + [/then] + [/if] + [/event] + + #event to transfer control of the ball by passing, after movement + [event] + name=moveto + first_time_only=no + [store_unit] + variable=unit + [filter] + x,y=$x1,$y1 + [/filter] + [/store_unit] + [if] + [variable] + name=unit.variables.has_ball1 + equals=yes + [/variable] + [then] + [store_locations] + variable=locs + x,y,radius=$x1,$y1,1 + [/store_locations] + {VARIABLE passed no} + {FOREACH locs i} + {VARIABLE_OP xloc to_variable locs[$i].x} + {VARIABLE_OP yloc to_variable locs[$i].y} + [if] + [or] + [variable] + name=xloc + not_equals=$x1 + [/variable] + [variable] + name=passed + equals=no + [/variable] + [have_unit] + x,y=$xloc,$yloc + side=$unit.side + [/have_unit] + [/or] + [or] + [variable] + name=yloc + not_equals=$y1 + [/variable] + [variable] + name=passed + equals=no + [/variable] + [have_unit] + x,y=$xloc,$yloc + side=$unit.side + [/have_unit] + [/or] + [then] + [store_unit] + variable=passto + [filter] + x,y=$xloc,$yloc + [/filter] + [/store_unit] + [if] + [variable] + name=passto.variables.has_ball2 + not_equals=yes + [/variable] + [then] + [message] + speaker=unit + message="Should I pass the ball to $passto.type ($xloc,$yloc)?" + [option] + message="Yes!" + [command] + {VARIABLE passed yes} + {VARIABLE unit.variables.has_ball1 no} + {VARIABLE passto.variables.has_ball1 yes} + [unstore_unit] + variable=passto + [/unstore_unit] + [unstore_unit] + variable=unit + [/unstore_unit] + [remove_unit_overlay] + x,y=$x1,$y1 + image=misc/ball.png + [/remove_unit_overlay] + [unit_overlay] + x,y=$xloc,$yloc + image=misc/ball.png + [/unit_overlay] + [/command] + [/option] + [option] + message="No" + [/option] + [/message] + [/then] + [/if] + [/then] + [/if] + + {NEXT i} + [/then] + [/if] + [/event] + + #control of the second ball. Exactly the same as control of the first + #ball, with different variable names + [event] + name=moveto + first_time_only=no + [filter] + x,y=$b2x,$b2y + [/filter] + [store_unit] + variable=unit + [filter] + x,y=$b2x,$b2y + [/filter] + [/store_unit] + [if] + [variable] + name=b2down + equals=yes + [/variable] + [variable] + name=unit.variables.has_ball1 + not_equals=yes + [/variable] + [then] + [removeitem] + x,y=$b2x,$b2y + [/removeitem] + {VARIABLE b2down no} + {VARIABLE unit.variables.has_ball2 yes} + [unstore_unit] + variable=unit + [/unstore_unit] + [unit_overlay] + x,y=$b2x,$b2y + image=misc/ball.png + [/unit_overlay] + [/then] + [/if] + [/event] + + [event] + name=die + first_time_only=no + + [store_unit] + variable=unit + [filter] + x,y=$x1,$y1 + [/filter] + [/store_unit] + + [if] + [variable] + name=unit.variables.has_ball2 + equals=yes + [/variable] + [then] + [remove_unit_overlay] + x,y=$x1,$y1 + image=misc/ball.png + [/remove_unit_overlay] + [item] + x,y=$x1,$y1 + image=misc/ball.png + [/item] + {VARIABLE b2x $x1} + {VARIABLE b2y $y1} + {VARIABLE unit.variables.has_ball2 no} + {VARIABLE b2down yes} + [unstore_unit] + variable=unit + [/unstore_unit] + [/then] + [/if] + [/event] + + [event] + name=moveto + first_time_only=no + [filter] + side=1 + x=38-40 + y=1-20 + [/filter] + [store_unit] + variable=unit + [filter] + x,y=$x1,$y1 + [/filter] + [/store_unit] + [if] + [variable] + name=unit.variables.has_ball2 + equals=yes + [/variable] + [then] + [set_variable] + name=redscore + add=1 + [/set_variable] + [message] + speaker=narrator + message="Red scores! Current score is $redscore-$bluescore" + [/message] + {VARIABLE b2x 7} + {VARIABLE b2y 9} + {VARIABLE unit.variables.has_ball2 no} + {VARIABLE b2down yes} + + [unstore_unit] + variable=unit + [/unstore_unit] + [remove_unit_overlay] + x,y=$x1,$y1 + image=misc/ball.png + [/remove_unit_overlay] + [item] + x,y=$b2x,$b2y + image=misc/ball.png + [/item] + [/then] + [/if] + [/event] + + [event] + name=moveto + first_time_only=no + [filter] + side=2 + x=1-3 + y=1-20 + [/filter] + [store_unit] + variable=unit + [filter] + x,y=$x1,$y1 + [/filter] + [/store_unit] + [if] + [variable] + name=unit.variables.has_ball2 + equals=yes + [/variable] + [then] + [set_variable] + name=bluescore + add=1 + [/set_variable] + [message] + speaker=narrator + message="Blue scores! Current score is $redscore-$bluescore" + [/message] + {VARIABLE b2x 35} + {VARIABLE b2y 11} + {VARIABLE unit.variables.has_ball2 no} + {VARIABLE b2down yes} + + [unstore_unit] + variable=unit + [/unstore_unit] + [remove_unit_overlay] + x,y=$x1,$y1 + image=misc/ball.png + [/remove_unit_overlay] + [item] + x,y=$b2x,$b2y + image=misc/ball.png + [/item] + [/then] + [/if] + [/event] + + #event to transfer control of the ball by passing, after movement + [event] + name=moveto + first_time_only=no + [store_unit] + variable=unit + [filter] + x,y=$x1,$y1 + [/filter] + [/store_unit] + [if] + [variable] + name=unit.variables.has_ball2 + equals=yes + [/variable] + [then] + [store_locations] + variable=locs + x,y,radius=$x1,$y1,1 + [/store_locations] + {VARIABLE passed no} + {FOREACH locs i} + {VARIABLE_OP xloc to_variable locs[$i].x} + {VARIABLE_OP yloc to_variable locs[$i].y} + [if] + [or] + [variable] + name=xloc + not_equals=$x1 + [/variable] + [variable] + name=passed + equals=no + [/variable] + [have_unit] + x,y=$xloc,$yloc + side=$unit.side + [/have_unit] + [/or] + [or] + [variable] + name=yloc + not_equals=$y1 + [/variable] + [variable] + name=passed + equals=no + [/variable] + [have_unit] + x,y=$xloc,$yloc + side=$unit.side + [/have_unit] + [/or] + [then] + [store_unit] + variable=passto + [filter] + x,y=$xloc,$yloc + [/filter] + [/store_unit] + [if] + [variable] + name=passto.variables.has_ball1 + not_equals=yes + [/variable] + [then] + [message] + speaker=unit + message="Should I pass the ball to $passto.type ($xloc,$yloc)?" + [option] + message="Yes!" + [command] + {VARIABLE passed yes} + {VARIABLE unit.variables.has_ball2 no} + {VARIABLE passto.variables.has_ball2 yes} + [unstore_unit] + variable=passto + [/unstore_unit] + [unstore_unit] + variable=unit + [/unstore_unit] + [remove_unit_overlay] + x,y=$x1,$y1 + image=misc/ball.png + [/remove_unit_overlay] + [unit_overlay] + x,y=$xloc,$yloc + image=misc/ball.png + [/unit_overlay] + [/command] + [/option] + [option] + message="No" + [/option] + [/message] + [/then] + [/if] + [/then] + [/if] + + {NEXT i} + [/then] + [/if] + [/event] + + [event] + name=time over + [if] + [variable] + name=redscore + less_than=$bluescore + [/variable] + [then] + [message] + speaker=narrator + message="Blue team wins! Final score: $redscore-$bluescore" + [/message] + [/then] + [/if] + [if] + [variable] + name=redscore + greater_than=$bluescore + [/variable] + [then] + [message] + speaker=narrator + message="Red team wins! Final score: $redscore-$bluescore" + [/message] + [/then] + [/if] + [if] + [variable] + name=redscore + equals=$bluescore + [/variable] + [then] + [message] + speaker=narrator + message="Draw! Final score: $redscore-$bluescore" + [/message] + [/then] + [/if] + + [endlevel] + result=continue + [/endlevel] + [/event] + + #if a unit dies, then it gets sent to its side's starting location + [event] + name=die + [store_unit] + variable=unit + [filter] + x,y=$x1,$y1 + [/filter] + [/store_unit] + [if] + [variable] + name=unit.side + equals=1 + [/variable] + [then] + {VARIABLE unit.x 2} + {VARIABLE unit.y 10} + [/then] + [else] + {VARIABLE unit.x 40} + {VARIABLE unit.y 10} + [/else] + [/if] + + {VARIABLE unit.hitpoints "-"} + + [unstore_unit] + find_vacant=yes + variable=unit + [/unstore_unit] + [/event] + + +[/multiplayer] diff --git a/images/misc/ball.png b/images/misc/ball.png new file mode 100644 index 00000000000..bd613ef1433 Binary files /dev/null and b/images/misc/ball.png differ diff --git a/src/config.cpp b/src/config.cpp index 0a799aa3a7c..2a13878d067 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -179,7 +179,7 @@ std::vector parse_macro_arguments(const std::string& macro) res.back() += " " + i->substr(begin,end-begin); config::strip(res.back()); - if(begin == 1) { + if(begin == 1 && end == i->size()) { in_braces = true; } } @@ -238,7 +238,7 @@ void internal_preprocess_data(const std::string& data, if(val.arguments.size() != items.size()) { std::cerr << "error: preprocessor symbol '" << symbol << "' has " << items.size() << " arguments, " - << val.arguments.size() << " expected\n"; + << val.arguments.size() << " expected: '" << newfilename << "'\n"; } std::string str = val.value; @@ -1121,6 +1121,19 @@ const config* config::find_child(const std::string& key, return NULL; } +std::string config::join(const std::vector& v, char c) +{ + std::stringstream str; + for(std::vector::const_iterator i = v.begin(); i != v.end(); ++i) { + str << *i; + if(i+1 != v.end()) { + str << c; + } + } + + return str.str(); +} + std::vector config::split(const std::string& val, char c, bool remove_empty) { std::vector res; @@ -1267,7 +1280,7 @@ namespace { bool not_id(char c) { - return !isalpha(c) && c != '.' && c != '_'; + return !isdigit(c) && !isalpha(c) && c != '.' && c != '_'; } void do_interpolation(std::string& res, size_t npos, const string_map* m) diff --git a/src/config.hpp b/src/config.hpp index fbab36ab3d1..49b3e8b8909 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -152,6 +152,7 @@ struct config void clear_children(const std::string& key); config* remove_child(const std::string& key, size_t index); + static std::string join(const std::vector& v, char c=','); static std::vector split(const std::string& val, char c=',', bool remove_empty=true); static std::vector quoted_split(const std::string& val, char c=',', bool remove_empty=true, char quote='\\'); diff --git a/src/display.cpp b/src/display.cpp index 128472ca8f8..7ce0d9cecfc 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -513,7 +513,6 @@ void draw_label(display& disp, SDL_Surface* target, const theme::label& label) void display::draw(bool update,bool force) { - std::cerr << "starting draw...\n"; if(!panelsDrawn_) { std::cerr << "drawing panels...\n"; SDL_Surface* const screen = screen_.getSurface(); @@ -581,10 +580,7 @@ void display::draw(bool update,bool force) update_display(); else drawSkips_++; - } - - std::cerr << "done draw...\n"; } void display::update_display() @@ -1423,6 +1419,16 @@ void display::draw_tile(int x, int y, SDL_Surface* unit_image, double alpha, Uin } } + const std::vector& overlays = un->second.overlays(); + for(std::vector::const_iterator ov = overlays.begin(); ov != overlays.end(); ++ov) { + const scoped_sdl_surface img(image::get_image(*ov)); + std::cerr << "drawing overlay: '" << *ov << "'\n"; + if(img.get() != NULL) { + std::cerr << "AA\n"; + draw_unit(xpos,ypos,img); + } + } + if(grid_) { scoped_sdl_surface grid_surface(image::get_image("terrain/grid.png")); if(grid_surface != NULL) { diff --git a/src/game_events.cpp b/src/game_events.cpp index dbd163fb506..08e20cc79af 100644 --- a/src/game_events.cpp +++ b/src/game_events.cpp @@ -616,6 +616,25 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s screen->remove_overlay(loc); } + else if(cmd == "unit_overlay") { + for(std::map::iterator itor = units->begin(); itor != units->end(); ++itor) { + if(game_events::unit_matches_filter(itor,cfg)) { + std::cerr << "adding overlay '" << cfg["image"] << "' to '" << itor->second.description() << "'\n"; + itor->second.add_overlay(cfg["image"]); + break; + } + } + } + + else if(cmd == "remove_unit_overlay") { + for(std::map::iterator itor = units->begin(); itor != units->end(); ++itor) { + if(game_events::unit_matches_filter(itor,cfg)) { + itor->second.remove_overlay(cfg["image"]); + break; + } + } + } + //hiding units else if(cmd == "hide_unit") { const gamemap::location loc(cfg); @@ -1007,6 +1026,8 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s const std::string& terrain = cfg["terrain"]; const config* const unit_filter = cfg.child("filter"); + state_of_game->variables.clear_children(variable); + std::vector locs = parse_location_range(cfg["x"],cfg["y"]); if(locs.size() > MaxLoop) { locs.resize(MaxLoop); diff --git a/src/multiplayer_connect.cpp b/src/multiplayer_connect.cpp index def5896fd84..bf64c2a44ff 100644 --- a/src/multiplayer_connect.cpp +++ b/src/multiplayer_connect.cpp @@ -692,6 +692,7 @@ lobby::RESULT mp_connect::process() } if(start_game) { + std::cerr << "multiplayer_connect returning create...\n"; return lobby::CREATE; } diff --git a/src/playlevel.cpp b/src/playlevel.cpp index 63f3225fd13..8687dcdce30 100644 --- a/src/playlevel.cpp +++ b/src/playlevel.cpp @@ -112,6 +112,8 @@ LEVEL_RESULT play_level(game_data& gameinfo, const config& game_config, game_state& state_of_game, const std::vector& story) { + std::cerr << "in play_level()...\n"; + //if the entire scenario should be randomly generated if((*level)["scenario_generation"] != "") { std::cerr << "randomly generating scenario...\n"; diff --git a/src/unit.cpp b/src/unit.cpp index 78579350431..5d7c932e131 100644 --- a/src/unit.cpp +++ b/src/unit.cpp @@ -523,6 +523,21 @@ bool unit::has_flag(const std::string& flag) const return statusFlags_.count(flag) != 0; } +void unit::add_overlay(const std::string& overlay) +{ + overlays_.push_back(overlay); +} + +void unit::remove_overlay(const std::string& overlay) +{ + overlays_.erase(std::remove(overlays_.begin(),overlays_.end(),overlay),overlays_.end()); +} + +const std::vector& unit::overlays() const +{ + return overlays_; +} + void unit::read(game_data& data, const config& cfg) { std::map::iterator i = data.unit_types.find(cfg["type"]); @@ -595,6 +610,11 @@ void unit::read(game_data& data, const config& cfg) } } + overlays_ = config::split(cfg["overlays"]); + if(overlays_.size() == 1 && overlays_.front() == "") { + overlays_.clear(); + } + const config* const variables = cfg.child("variables"); if(variables != NULL) { variables_ = *variables; @@ -618,10 +638,7 @@ void unit::read(game_data& data, const config& cfg) moves_ = atoi(moves.c_str()); const std::string& hitpoints = cfg["hitpoints"]; - if(hitpoints.size() == 0) - hitpoints_ = maxHitpoints_; - else - hitpoints_ = atoi(hitpoints.c_str()); + hitpoints_ = lexical_cast_default(hitpoints,maxHitpoints_); const std::string& experience = cfg["experience"]; if(experience.size() == 0) @@ -656,9 +673,10 @@ void unit::write(config& cfg) const } cfg.add_child("variables",variables_); - cfg.add_child("status",status_flags); + cfg["overlays"] = config::join(overlays_); + cfg["user_description"] = description_; cfg["description"] = underlying_description_; cfg["unit_description"] = custom_unit_description_; diff --git a/src/unit.hpp b/src/unit.hpp index 150293d3a12..8b99379a311 100644 --- a/src/unit.hpp +++ b/src/unit.hpp @@ -88,6 +88,10 @@ public: void remove_flag(const std::string& flag); bool has_flag(const std::string& flag) const; + void add_overlay(const std::string& overlay); + void remove_overlay(const std::string& overlay); + const std::vector& overlays() const; + void read(game_data& data, const config& cfg); void write(config& cfg) const; @@ -173,6 +177,7 @@ private: std::string role_; std::set statusFlags_; + std::vector overlays_; //this field stores user-variables associated with the unit config variables_;