added new WML commands
This commit is contained in:
parent
977b77e693
commit
6274d5914f
9 changed files with 231 additions and 49 deletions
|
@ -38,6 +38,10 @@ Defeat:
|
|||
{CROSS 259 352}
|
||||
[/bigmap]
|
||||
|
||||
{STARTING_VILLAGES 5 10}
|
||||
{STARTING_VILLAGES 6 10}
|
||||
{STARTING_VILLAGES 1 10}
|
||||
|
||||
[side]
|
||||
type=Fighter
|
||||
description=Konrad
|
||||
|
|
|
@ -63,6 +63,15 @@ random={RANGE}
|
|||
[/set_variable]
|
||||
#enddef
|
||||
|
||||
#macro to initialize a variable
|
||||
|
||||
#define VARIABLE VAR VALUE
|
||||
[set_variable]
|
||||
name={VAR}
|
||||
value={VALUE}
|
||||
[/set_variable]
|
||||
#enddef
|
||||
|
||||
#macro to do mathematical operations on variables
|
||||
|
||||
#define VARIABLE_OP VAR OP ARG
|
||||
|
@ -72,3 +81,73 @@ name={VAR}
|
|||
[/set_variable]
|
||||
#enddef
|
||||
|
||||
#define CLEAR_VARIABLE VAR
|
||||
[clear_variable]
|
||||
name={VAR}
|
||||
[/clear_variable]
|
||||
#enddef
|
||||
|
||||
#macro to iterate over an array
|
||||
#define FOREACH ARRAY VAR
|
||||
{VARIABLE {VAR} 0}
|
||||
[while]
|
||||
[variable]
|
||||
name={VAR}
|
||||
less_than=${ARRAY}.length
|
||||
[/variable]
|
||||
[do]
|
||||
#enddef
|
||||
|
||||
|
||||
#define NEXT VAR
|
||||
[set_variable]
|
||||
name={VAR}
|
||||
add=1
|
||||
[/set_variable]
|
||||
[/do]
|
||||
[/while]
|
||||
{CLEAR_VARIABLE {VAR}}
|
||||
#enddef
|
||||
|
||||
#define DEBUG_MSG MSG
|
||||
[message]
|
||||
speaker=narrator
|
||||
message={MSG}
|
||||
[/message]
|
||||
#enddef
|
||||
|
||||
#macro to make a side start a scenario with villages
|
||||
|
||||
#define STARTING_VILLAGES SIDE RADIUS
|
||||
[event]
|
||||
name=prestart
|
||||
[store_starting_location]
|
||||
side={SIDE}
|
||||
variable=temp_starting_location
|
||||
[/store_starting_location]
|
||||
[store_locations]
|
||||
x,y=$temp_starting_location.x,$temp_starting_location.y
|
||||
radius={RADIUS}
|
||||
variable=temp_starting_locs
|
||||
|
||||
#all the types of villages
|
||||
terrain=ZYtvVD
|
||||
[/store_locations]
|
||||
|
||||
{FOREACH temp_starting_locs i}
|
||||
{VARIABLE_OP temp_x_var to_variable temp_starting_locs[$i].x}
|
||||
{VARIABLE_OP temp_y_var to_variable temp_starting_locs[$i].y}
|
||||
[capture_village]
|
||||
side={SIDE}
|
||||
x,y=$temp_x_var,$temp_y_var
|
||||
[/capture_village]
|
||||
{NEXT i}
|
||||
|
||||
{CLEAR_VARIABLE temp_x_var}
|
||||
{CLEAR_VARIABLE temp_y_var}
|
||||
{CLEAR_VARIABLE temp_starting_location}
|
||||
{CLEAR_VARIABLE temp_starting_locs}
|
||||
{CLEAR_VARIABLE i}
|
||||
[/event]
|
||||
#enddef
|
||||
|
||||
|
|
|
@ -163,7 +163,7 @@ std::vector<std::string> parse_macro_arguments(const std::string& macro)
|
|||
bool in_braces = false;
|
||||
for(std::vector<std::string>::const_iterator i = args.begin()+1; i != args.end(); ++i) {
|
||||
size_t begin = 0, end = i->size();
|
||||
if((*i)[0] == '{') {
|
||||
if((*i)[0] == '(') {
|
||||
++begin;
|
||||
}
|
||||
|
||||
|
@ -171,7 +171,7 @@ std::vector<std::string> parse_macro_arguments(const std::string& macro)
|
|||
res.push_back("");
|
||||
}
|
||||
|
||||
if((*i)[i->size()-1] == '}') {
|
||||
if((*i)[i->size()-1] == ')') {
|
||||
in_braces = false;
|
||||
--end;
|
||||
}
|
||||
|
@ -622,7 +622,7 @@ void config::read(const std::string& data,
|
|||
|
||||
//see if this is a CVS list=CVS list style assignment (e.g. x,y=5,8)
|
||||
std::vector<std::string> vars, values;
|
||||
if(std::count(var.begin(),var.end(),',') > 1) {
|
||||
if(std::count(var.begin(),var.end(),',') > 0) {
|
||||
vars = config::split(var);
|
||||
values = config::split(value);
|
||||
} else {
|
||||
|
@ -1257,7 +1257,7 @@ namespace {
|
|||
|
||||
bool not_id(char c)
|
||||
{
|
||||
return !isalpha(c) && c != '.';
|
||||
return !isalpha(c) && c != '.' && c != '_';
|
||||
}
|
||||
|
||||
void do_interpolation(std::string& res, size_t npos, const string_map* m)
|
||||
|
|
|
@ -105,14 +105,10 @@ bool conditional_passed(game_state& state_of_game,
|
|||
}
|
||||
|
||||
const std::string& less_than = values["less_than"];
|
||||
std::cerr << num_value << " < '" << less_than << "' ?\n";
|
||||
if(less_than != "" && atof(less_than.c_str()) <= num_value){
|
||||
std::cerr << "no\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cerr << "yes\n";
|
||||
|
||||
const std::string& greater_than_equal_to = values["greater_than_equal_to"];
|
||||
if(greater_than_equal_to != "" && atof(greater_than_equal_to.c_str()) > num_value){
|
||||
return false;
|
||||
|
@ -140,6 +136,8 @@ game_data* game_data_ptr = NULL;
|
|||
gamestatus* status_ptr = NULL;
|
||||
std::set<std::string> used_items;
|
||||
|
||||
const size_t MaxLoop = 1024;
|
||||
|
||||
bool events_init() { return screen != NULL; }
|
||||
|
||||
struct queued_event {
|
||||
|
@ -434,11 +432,8 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
|
|||
|
||||
//setting a variable
|
||||
else if(cmd == "set_variable") {
|
||||
std::cerr << "setting variable\n";
|
||||
const std::string& name = config::interpolate_variables_into_string(cfg.get_attribute("name"));
|
||||
std::cerr << "name: '" << name << "'\n";
|
||||
std::string& var = game_events::get_variable(name);
|
||||
std::cerr << "got variable...\n";
|
||||
const std::string& value = cfg["value"];
|
||||
if(value.empty() == false) {
|
||||
var = value;
|
||||
|
@ -449,6 +444,11 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
|
|||
var = format;
|
||||
}
|
||||
|
||||
const std::string& to_variable = config::interpolate_variables_into_string(cfg.get_attribute("to_variable"));
|
||||
if(to_variable.empty() == false) {
|
||||
var = game_events::get_variable(to_variable);
|
||||
}
|
||||
|
||||
const std::string& add = cfg["add"];
|
||||
if(add.empty() == false) {
|
||||
int value = atof(var.c_str());
|
||||
|
@ -464,7 +464,6 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
|
|||
value = int(double(value) * atof(multiply.c_str()));
|
||||
char buf[50];
|
||||
sprintf(buf,"%d",value);
|
||||
std::cerr << "'" << var << "' * '" << multiply << "' = '" << buf << "'\n";
|
||||
var = buf;
|
||||
}
|
||||
|
||||
|
@ -536,14 +535,15 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
|
|||
break;
|
||||
}
|
||||
}
|
||||
std::cerr << "(" << choice << ")" << random_value << " ";
|
||||
|
||||
var = random_value;
|
||||
}
|
||||
}
|
||||
|
||||
//conditional statements
|
||||
else if(cmd == "if" || cmd == "while") {
|
||||
const size_t max_iterations = (cmd == "if" ? 1 : 1024);
|
||||
log_scope(cmd);
|
||||
const size_t max_iterations = (cmd == "if" ? 1 : MaxLoop);
|
||||
const std::string pass = (cmd == "if" ? "then" : "do");
|
||||
const std::string fail = (cmd == "if" ? "else" : "");
|
||||
for(size_t i = 0; i != max_iterations; ++i) {
|
||||
|
@ -650,15 +650,11 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
|
|||
|
||||
//if we should spawn a new unit on the map somewhere
|
||||
else if(cmd == "unit") {
|
||||
std::cerr << "spawning unit...\n";
|
||||
unit new_unit(*game_data_ptr,cfg);
|
||||
gamemap::location loc(cfg);
|
||||
|
||||
std::cerr << "location: " << loc.x << "," << loc.y << "\n";
|
||||
|
||||
if(game_map->on_board(loc)) {
|
||||
loc = find_vacant_tile(*game_map,*units,loc);
|
||||
std::cerr << "found vacant tile: " << loc.x << "," << loc.y << "\n";
|
||||
units->insert(std::pair<gamemap::location,unit>(loc,new_unit));
|
||||
screen->invalidate(loc);
|
||||
} else {
|
||||
|
@ -821,8 +817,6 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
|
|||
std::vector<std::string> options;
|
||||
std::vector<config::const_child_itors> option_events;
|
||||
|
||||
std::cerr << "building menu items...\n";
|
||||
|
||||
const config::child_list& menu_items = cfg.get_children("option");
|
||||
for(config::child_list::const_iterator mi = menu_items.begin();
|
||||
mi != menu_items.end(); ++mi) {
|
||||
|
@ -991,6 +985,75 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
|
|||
}
|
||||
}
|
||||
|
||||
else if(cmd == "store_starting_location") {
|
||||
const int side = lexical_cast_default<int>(cfg["side"]);
|
||||
const gamemap::location& loc = game_map->starting_position(side);
|
||||
static const std::string default_store = "location";
|
||||
const std::string& store = cfg["variable"].empty() ? default_store : cfg["variable"];
|
||||
loc.write(game_events::get_variable_cfg(store));
|
||||
}
|
||||
|
||||
else if(cmd == "store_locations") {
|
||||
log_scope("store_locations");
|
||||
const std::string& variable = cfg["variable"];
|
||||
const std::string& terrain = cfg["terrain"];
|
||||
const config* const unit_filter = cfg.child("filter");
|
||||
|
||||
std::vector<gamemap::location> locs = parse_location_range(cfg["x"],cfg["y"]);
|
||||
if(locs.size() > MaxLoop) {
|
||||
locs.resize(MaxLoop);
|
||||
}
|
||||
|
||||
const size_t radius = minimum<size_t>(MaxLoop,lexical_cast_default<size_t>(cfg["radius"]));
|
||||
std::set<gamemap::location> res;
|
||||
for(std::vector<gamemap::location>::const_iterator i = locs.begin(); i != locs.end(); ++i) {
|
||||
get_tiles_radius(*i,radius,res);
|
||||
}
|
||||
|
||||
size_t added = 0;
|
||||
for(std::set<gamemap::location>::const_iterator j = res.begin(); j != res.end() && added != MaxLoop; ++j) {
|
||||
if(game_map->on_board(*j)) {
|
||||
if(terrain.empty() == false) {
|
||||
const gamemap::TERRAIN c = game_map->get_terrain(*j);
|
||||
if(std::find(terrain.begin(),terrain.end(),c) == terrain.end()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(unit_filter != NULL) {
|
||||
const unit_map::const_iterator u = units->find(*j);
|
||||
if(u == units->end() || game_events::unit_matches_filter(u,*unit_filter) == false) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
j->write(state_of_game->variables.add_child(variable));
|
||||
++added;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//command to take control of a village for a certain side
|
||||
else if(cmd == "capture_village") {
|
||||
const int side = lexical_cast_default<int>(cfg["side"]);
|
||||
|
||||
//if 'side' is 0, then it will become an invalid index, and so
|
||||
//the village will become neutral.
|
||||
const size_t team_num = size_t(side-1);
|
||||
|
||||
const gamemap::location loc(cfg);
|
||||
|
||||
if(game_map->is_village(loc)) {
|
||||
get_village(loc,*teams,team_num,*units);
|
||||
}
|
||||
}
|
||||
|
||||
//command to remove a variable
|
||||
else if(cmd == "clear_variable") {
|
||||
state_of_game->variables.values.erase(cfg["name"]);
|
||||
state_of_game->variables.clear_children(cfg["name"]);
|
||||
}
|
||||
|
||||
else if(cmd == "endlevel") {
|
||||
const std::string& next_scenario = cfg["next_scenario"];
|
||||
if(next_scenario.empty() == false) {
|
||||
|
@ -1158,9 +1221,9 @@ void get_variable_internal(const std::string& key, config& cfg,
|
|||
const std::string::iterator index_end = std::find(index_start,element.end(),']');
|
||||
const std::string index_str(index_start+1,index_end);
|
||||
index = size_t(atoi(index_str.c_str()));
|
||||
if(index > 1024) {
|
||||
if(index > MaxLoop) {
|
||||
std::cerr << "ERROR: index greater than 1024: truncated\n";
|
||||
index = 1024;
|
||||
index = MaxLoop;
|
||||
}
|
||||
|
||||
element = std::string(element.begin(),index_start);
|
||||
|
@ -1178,7 +1241,7 @@ void get_variable_internal(const std::string& key, config& cfg,
|
|||
}
|
||||
} else {
|
||||
char buf[50];
|
||||
sprintf(buf,"%d",minimum<int>(1024,int(items.size())));
|
||||
sprintf(buf,"%d",minimum<int>(MaxLoop,int(items.size())));
|
||||
((*items.back())["__length"] = buf);
|
||||
if(varout != NULL) {
|
||||
*varout = &(*items.back())["__length"];
|
||||
|
@ -1189,7 +1252,6 @@ void get_variable_internal(const std::string& key, config& cfg,
|
|||
}
|
||||
|
||||
while(cfg.get_children(element).size() <= index) {
|
||||
std::cerr << "element '" << element << "', " << index << " not found -- adding\n";
|
||||
cfg.add_child(element);
|
||||
}
|
||||
|
||||
|
|
|
@ -290,7 +290,12 @@ gamemap::TERRAIN gamemap::get_terrain(const gamemap::location& loc) const
|
|||
|
||||
const gamemap::location& gamemap::starting_position(int n) const
|
||||
{
|
||||
return startingPositions_[n];
|
||||
if(n < sizeof(startingPositions_)/sizeof(*startingPositions_)) {
|
||||
return startingPositions_[n];
|
||||
} else {
|
||||
static const gamemap::location null_loc;
|
||||
return null_loc;
|
||||
}
|
||||
}
|
||||
|
||||
int gamemap::num_valid_starting_positions() const
|
||||
|
|
|
@ -92,6 +92,34 @@ void get_adjacent_tiles(const gamemap::location& a, gamemap::location* res)
|
|||
res->y = a.y - (is_even(a.x) ? 1:0);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void get_tiles_radius_internal(const gamemap::location& a, size_t radius, std::set<gamemap::location>& res, std::map<gamemap::location,int>& visited)
|
||||
{
|
||||
visited[a] = radius;
|
||||
res.insert(a);
|
||||
|
||||
if(radius == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
gamemap::location adj[6];
|
||||
get_adjacent_tiles(a,adj);
|
||||
for(size_t i = 0; i != 6; ++i) {
|
||||
if(visited.count(adj[i]) == 0 || visited[adj[i]] < radius-1) {
|
||||
get_tiles_radius_internal(adj[i],radius-1,res,visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void get_tiles_radius(const gamemap::location& a, size_t radius, std::set<gamemap::location>& res)
|
||||
{
|
||||
std::map<gamemap::location,int> visited;
|
||||
get_tiles_radius_internal(a,radius,res,visited);
|
||||
}
|
||||
|
||||
bool tiles_adjacent(const gamemap::location& a, const gamemap::location& b)
|
||||
{
|
||||
//two tiles are adjacent if y is different by 1, and x by 0, or if
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
//res. res must point to an array of 6 location objects.
|
||||
void get_adjacent_tiles(const gamemap::location& a, gamemap::location* res);
|
||||
|
||||
//function which, given a location, will find all tiles within 'radius' of that tile
|
||||
void get_tiles_radius(const gamemap::location& a, size_t radius, std::set<gamemap::location>& res);
|
||||
|
||||
//function which tells if two locations are adjacent.
|
||||
bool tiles_adjacent(const gamemap::location& a, const gamemap::location& b);
|
||||
|
||||
|
|
|
@ -317,31 +317,32 @@ LEVEL_RESULT play_level(game_data& gameinfo, const config& game_config,
|
|||
gui.add_overlay(gamemap::location(**overlay),(**overlay)["image"]);
|
||||
}
|
||||
|
||||
if(first_human_team != -1) {
|
||||
clear_shroud(gui,status,map,gameinfo,units,teams,first_human_team);
|
||||
gui.scroll_to_tile(map.starting_position(first_human_team+1).x,map.starting_position(first_human_team+1).y,display::WARP);
|
||||
}
|
||||
|
||||
gui.scroll_to_tile(map.starting_position(1).x,map.starting_position(1).y,display::WARP);
|
||||
|
||||
bool replaying = (recorder.at_end() == false);
|
||||
|
||||
//if a team is specified whose turn it is, it means we're loading a game
|
||||
//instead of starting a fresh one
|
||||
const bool loading_game = (*level)["playing_team"].empty() == false;
|
||||
int first_player = atoi((*level)["playing_team"].c_str());
|
||||
if(first_player < 0 || first_player >= int(teams.size())) {
|
||||
first_player = 0;
|
||||
}
|
||||
|
||||
int turn = 1;
|
||||
std::cerr << "starting main loop\n";
|
||||
|
||||
int player_number = 0;
|
||||
|
||||
std::deque<config> data_backlog;
|
||||
int turn = 1, player_number = 0;
|
||||
|
||||
try {
|
||||
game_events::fire("prestart");
|
||||
|
||||
if(first_human_team != -1) {
|
||||
clear_shroud(gui,status,map,gameinfo,units,teams,first_human_team);
|
||||
gui.scroll_to_tile(map.starting_position(first_human_team+1).x,map.starting_position(first_human_team+1).y,display::WARP);
|
||||
}
|
||||
|
||||
gui.scroll_to_tile(map.starting_position(1).x,map.starting_position(1).y,display::WARP);
|
||||
|
||||
bool replaying = (recorder.at_end() == false);
|
||||
|
||||
//if a team is specified whose turn it is, it means we're loading a game
|
||||
//instead of starting a fresh one
|
||||
const bool loading_game = (*level)["playing_team"].empty() == false;
|
||||
int first_player = atoi((*level)["playing_team"].c_str());
|
||||
if(first_player < 0 || first_player >= int(teams.size())) {
|
||||
first_player = 0;
|
||||
}
|
||||
|
||||
std::cerr << "starting main loop\n";
|
||||
|
||||
std::deque<config> data_backlog;
|
||||
|
||||
for(bool first_time = true; true; first_time = false, first_player = 0) {
|
||||
player_number = 0;
|
||||
|
||||
|
|
|
@ -363,7 +363,7 @@ bool unit::invisible(const std::string& terrain, int lawful_bonus,
|
|||
bool is_inv = false;
|
||||
|
||||
static const std::string forest_invisible("ambush");
|
||||
if(std::count(terrain.begin(),terrain.end(),gamemap::FOREST) && has_flag(forest_invisible)) {
|
||||
if(std::count(terrain.begin(),terrain.end(),static_cast<gamemap::TERRAIN>(gamemap::FOREST)) && has_flag(forest_invisible)) {
|
||||
is_inv = true;
|
||||
}
|
||||
static const std::string night_invisible("nightstalk");
|
||||
|
|
Loading…
Add table
Reference in a new issue