added new WML commands

This commit is contained in:
Dave White 2004-04-30 18:24:26 +00:00
parent 977b77e693
commit 6274d5914f
9 changed files with 231 additions and 49 deletions

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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");