diff --git a/Makefile b/Makefile index 37322adfc..8f3504204 100644 --- a/Makefile +++ b/Makefile @@ -232,6 +232,7 @@ SOURCES += bauer/fabrikbauer.cc SOURCES += bauer/goods_manager.cc SOURCES += bauer/hausbauer.cc SOURCES += bauer/tunnelbauer.cc +SOURCES += bauer/script_tool_manager.cc SOURCES += bauer/vehikelbauer.cc SOURCES += bauer/wegbauer.cc SOURCES += boden/boden.cc @@ -405,6 +406,7 @@ SOURCES += gui/scenario_frame.cc SOURCES += gui/scenario_info.cc SOURCES += gui/schedule_gui.cc SOURCES += gui/schedule_list.cc +SOURCES += gui/script_tool_frame.cc SOURCES += gui/server_frame.cc SOURCES += gui/settings_frame.cc SOURCES += gui/settings_stats.cc diff --git a/bauer/script_tool_manager.cc b/bauer/script_tool_manager.cc new file mode 100644 index 000000000..3f3e25e2a --- /dev/null +++ b/bauer/script_tool_manager.cc @@ -0,0 +1,110 @@ +/* + * This file is part of the Simutrans project under the Artistic License. + * (see LICENSE.txt) + */ + +#include "script_tool_manager.h" + +#include "../dataobj/tabfile.h" + +#include "../simdebug.h" +#include "../simtool.h" +#include "../simskin.h" +#include "../sys/simsys.h" + +#include "../gui/tool_selector.h" +#include "../utils/searchfolder.h" + + +vector_tpl script_tool_manager_t::one_click_script_tools; +vector_tpl script_tool_manager_t::two_click_script_tools; + +bool script_tool_manager_t::check_file( const char *filename ) +{ + char buf[PATH_MAX]; + sprintf( buf, "%s/tool.nut", filename ); + if (FILE* const f = dr_fopen(buf, "r")) { + fclose(f); + return true; + } + return false; +} + +bool script_tool_manager_t::is_two_click_tool( const char *filename ) { + // read description.tab + char buf[PATH_MAX]; + sprintf( buf, "%s/description.tab", filename ); + tabfile_t file; + if ( !file.open(buf) ) { + // no description.tab -> handle as one_click script tool + return false; + } + tabfileobj_t contents; + file.read( contents ); + return strcmp(contents.get_string("type", "one_click"), "two_click")==0; +} + +void script_tool_manager_t::load_tool(tool_t* ttl, exec_script_base_t* etl, char const* fullpath, char const* name) { + // open description.tab and get more info + char buf[PATH_MAX]; + sprintf( buf, "%s/description.tab", fullpath ); + tabfile_t file; + if ( !file.open(buf) ) { + // no description.tab -> handle as one_click script tool + // set only default_param and title + ttl->set_default_param(fullpath); + etl->set_title(name); + return; + } + + tabfileobj_t contents; + file.read( contents ); + ttl->set_default_param(fullpath); + etl->set_title(contents.get_string("title", ttl->get_default_param())); + etl->set_menu_arg(contents.get_string("menu", ttl->get_default_param())); + if( contents.get_int("restart", 1) > 0 ) { + etl->enable_restart(); + } + const char* cursor_name = contents.get_string("icon", "-"); + const skin_desc_t * desc = skinverwaltung_t::get_extra(cursor_name, strlen(cursor_name), skinverwaltung_t::cursor); + if( desc ) { + ttl->cursor = desc->get_image_id(0); + ttl->set_icon(desc->get_image_id(1)); + } + return; +} + +void script_tool_manager_t::load_scripts(char const* path) { + dbg->message("script_tool_manager_t::load_scripts", "Loading scripts from %s", path); + searchfolder_t find; + find.search(path, "", true, false); + FOR(searchfolder_t, const &name, find) { + char* fullname = new char [strlen(path)+strlen(name)+1]; + sprintf(fullname,"%s%s",path,name); + + if( is_two_click_tool(fullname) ) { + tool_exec_two_click_script_t* tt = new tool_exec_two_click_script_t(); + load_tool(tt, tt, fullname, name); + two_click_script_tools.append(tt); + } else { + tool_exec_script_t* ot = new tool_exec_script_t(); + load_tool(ot, ot, fullname, name); + one_click_script_tools.append(ot); + } + } +} + +void script_tool_manager_t::fill_menu(tool_selector_t* tool_selector, char const* arg, sint16 /*sound_ok*/) { + for(uint32 i=0; iget_menu_arg(), arg)==0 ) { + tool_selector->add_tool_selector(tool); + } + } + for(uint32 i=0; iget_menu_arg(), arg)==0 ) { + tool_selector->add_tool_selector(tool); + } + } +} diff --git a/bauer/script_tool_manager.h b/bauer/script_tool_manager.h new file mode 100644 index 000000000..4825b86d9 --- /dev/null +++ b/bauer/script_tool_manager.h @@ -0,0 +1,41 @@ +/* + * This file is part of the Simutrans project under the Artistic License. + * (see LICENSE.txt) + */ + +#ifndef BAUER_SCRIPT_TOOL_MANAGER_H +#define BAUER_SCRIPT_TOOL_MANAGER_H + + +#include "../tpl/vector_tpl.h" + +class exec_script_base_t; +class tool_t; +class tool_selector_t; +class tool_exec_script_t; +class tool_exec_two_click_script_t; + +/** + * There's no need to construct an instance since everything is static here. + */ +class script_tool_manager_t +{ +private: + /// All one-click script tools + static vector_tpl one_click_script_tools; + /// All two-click script tools + static vector_tpl two_click_script_tools; + +public: + static void load_scripts(char const* path); + + static bool check_file(char const* path); + + static bool is_two_click_tool(char const* path); + + static void load_tool(tool_t*, exec_script_base_t*, char const* fullpath, char const* name); + + static void fill_menu(tool_selector_t* tool_selector, char const* arg, sint16 sound_ok); +}; + +#endif diff --git a/gui/script_tool_frame.cc b/gui/script_tool_frame.cc new file mode 100644 index 000000000..d31e940a5 --- /dev/null +++ b/gui/script_tool_frame.cc @@ -0,0 +1,96 @@ +/* + * This file is part of the Simutrans project under the Artistic License. + * (see LICENSE.txt) + */ + +#include "script_tool_frame.h" + +#include "../bauer/script_tool_manager.h" +#include "../dataobj/tabfile.h" +#include "../dataobj/translator.h" +#include "../simdebug.h" +#include "../simtool.h" +#include "../sys/simsys.h" + +script_tool_frame_t::script_tool_frame_t() : savegame_frame_t(NULL, true, NULL, false) +{ + static cbuffer_t pakset_script_tool; + static cbuffer_t addons_script_tool; + + pakset_script_tool.clear(); + pakset_script_tool.printf("%stool/", env_t::program_dir, env_t::objfilename.c_str()); + + addons_script_tool.clear(); + addons_script_tool.printf("%stool/", env_t::objfilename.c_str()); + + if (env_t::default_settings.get_with_private_paks()) { + this->add_path(addons_script_tool); + } + this->add_path(pakset_script_tool); + + set_name(translator::translate("Load script tool")); + set_focus(NULL); +} + + +static char executed_script_name[PATH_MAX]; + +/** + * Action, started after button pressing. + */ +bool script_tool_frame_t::item_action(const char *fullpath) +{ + strcpy(executed_script_name, fullpath); + if( script_tool_manager_t::is_two_click_tool(executed_script_name) ) { + tool_exec_two_click_script_t* tt = static_cast(tool_t::general_tool[TOOL_EXEC_TWO_CLICK_SCRIPT]); + if( !tt ) { + dbg->error("script_tool_frame_t::item_action", "cannot get tool object."); + } + script_tool_manager_t::load_tool(tt, tt, executed_script_name, executed_script_name); + tt->enable_restart(); + welt->set_tool( tt, welt->get_active_player() ); + } else { + tool_exec_script_t* ot = static_cast(tool_t::general_tool[TOOL_EXEC_SCRIPT]); + if( !ot ) { + dbg->error("script_tool_frame_t::item_action", "cannot get tool object."); + } + script_tool_manager_t::load_tool(ot, ot, executed_script_name, executed_script_name); + ot->enable_restart(); + welt->set_tool( ot, welt->get_active_player() ); + } + return true; +} + + +const char *script_tool_frame_t::get_info(const char *filename) +{ + static char info[PATH_MAX]; + // try to get tool title from description.tab + sprintf( info, "%s/description.tab", filename ); + tabfile_t file; + if ( file.open(info) ) { + tabfileobj_t contents; + file.read( contents ); + const char* title = contents.get_string("title", ""); + if( strcmp(title, "")!=0 ) { + // title is properly defined. + strcpy(info, title); + return info; + } + } + + sprintf(info,"%s",this->get_filename(filename, false).c_str()); + return info; +} + + +bool script_tool_frame_t::check_file( const char *filename, const char * ) +{ + char buf[PATH_MAX]; + sprintf( buf, "%s/tool.nut", filename ); + if (FILE* const f = dr_fopen(buf, "r")) { + fclose(f); + return true; + } + return false; +} diff --git a/gui/script_tool_frame.h b/gui/script_tool_frame.h new file mode 100644 index 000000000..f4783d55e --- /dev/null +++ b/gui/script_tool_frame.h @@ -0,0 +1,46 @@ +/* + * This file is part of the Simutrans project under the Artistic License. + * (see LICENSE.txt) + */ + +#ifndef GUI_SCRIPT_TOOL_INFO_H +#define GUI_SCRIPT_TOOL_INFO_H + + +#include "savegame_frame.h" +#include "../utils/cbuffer_t.h" + + +class script_tool_frame_t : public savegame_frame_t +{ +private: + cbuffer_t path; + +protected: + /** + * Action that's started by the press of a button. + */ + bool item_action(const char *fullpath) OVERRIDE; + + /** + * Action, started after X-Button pressing + */ + bool del_action(const char *f) OVERRIDE { return item_action(f); } + + // returns extra file info + const char *get_info(const char *fname) OVERRIDE; + + // true, if valid + bool check_file( const char *filename, const char *suffix ) OVERRIDE; + +public: + /** + * Set the window associated helptext + * @return the filename for the helptext, or NULL + */ + const char * get_help_filename() const OVERRIDE { return "script_tool.txt"; } + + script_tool_frame_t(); +}; + +#endif diff --git a/simmain.cc b/simmain.cc index bafb2bf56..d8c7a753e 100644 --- a/simmain.cc +++ b/simmain.cc @@ -81,6 +81,7 @@ #include "utils/simrandom.h" #include "bauer/vehikelbauer.h" +#include "bauer/script_tool_manager.h" #include "vehicle/simvehicle.h" #include "vehicle/simroadtraffic.h" @@ -1113,6 +1114,13 @@ int simu_main(int argc, char** argv) modal_dialogue( win, magic_pakset_info_t, NULL, wait_for_key ); destroy_all_win(true); } + + // load tool scripts + dbg->message("simmain()","Reading tool scripts ..."); + script_tool_manager_t::load_scripts((env_t::objfilename + "tool/").c_str()); + if( env_t::default_settings.get_with_private_paks() ) { + script_tool_manager_t::load_scripts(("addons/" + env_t::objfilename + "tool/").c_str()); + } dbg->message("simmain()","Reading menu configuration ..."); tool_t::read_menu(env_t::objfilename); diff --git a/simmenu.cc b/simmenu.cc index 9e43aee99..5cad122c1 100644 --- a/simmenu.cc +++ b/simmenu.cc @@ -22,6 +22,7 @@ #include "bauer/wegbauer.h" #include "bauer/brueckenbauer.h" #include "bauer/tunnelbauer.h" +#include "bauer/script_tool_manager.h" #include "descriptor/building_desc.h" #include "descriptor/bridge_desc.h" @@ -118,6 +119,8 @@ tool_t *create_general_tool(int toolnr) case TOOL_SET_CLIMATE: tool = new tool_set_climate_t(); break; case TOOL_ROTATE_BUILDING: tool = new tool_rotate_building_t(); break; case TOOL_MERGE_STOP: tool = new tool_merge_stop_t(); break; + case TOOL_EXEC_SCRIPT: tool = new tool_exec_script_t(); break; + case TOOL_EXEC_TWO_CLICK_SCRIPT: tool = new tool_exec_two_click_script_t(); break; default: dbg->error("create_general_tool()","cannot satisfy request for general_tool[%i]!",toolnr); return NULL; } @@ -213,6 +216,7 @@ tool_t *create_dialog_tool(int toolnr) case DIALOG_SCENARIO_INFO: tool = new dialog_scenario_info_t(); break; case DIALOG_LIST_DEPOT: tool = new dialog_list_depot_t(); break; case DIALOG_LIST_VEHICLE: tool = new dialog_list_vehicle_t(); break; + case DIALOG_SCRIPT_TOOL: tool = new dialog_script_tool_t(); break; default: dbg->error("create_dialog_tool()","cannot satisfy request for dialog_tool[%i]!",toolnr); return NULL; } @@ -887,6 +891,12 @@ void toolbar_t::update(player_t *player) waytype_t way = (waytype_t)(*c!=0 ? atoi(++c) : 0); hausbauer_t::fill_menu( tool_selector, utype, way, get_sound(c)); } + else if (char const* const c = strstart(param, "scripts(")) { + char buf[1000]; + strcpy(buf, c); + buf[strlen(c)-1] = '\0'; // omit the last ')' charactor + script_tool_manager_t::fill_menu(tool_selector, buf, get_sound(c)); + } else if (param[0] == '-') { // add dummy tool_t as seperator tool_selector->add_tool_selector( dummy ); diff --git a/simmenu.h b/simmenu.h index 88964c8b5..694c4383e 100644 --- a/simmenu.h +++ b/simmenu.h @@ -74,6 +74,8 @@ enum { TOOL_SET_CLIMATE, TOOL_ROTATE_BUILDING, TOOL_MERGE_STOP, + TOOL_EXEC_SCRIPT, + TOOL_EXEC_TWO_CLICK_SCRIPT, GENERAL_TOOL_COUNT, GENERAL_TOOL = 0x1000 }; @@ -156,6 +158,7 @@ enum { DIALOG_SCENARIO_INFO, DIALOG_LIST_DEPOT, DIALOG_LIST_VEHICLE, + DIALOG_SCRIPT_TOOL, DIALOGE_TOOL_COUNT, DIALOGE_TOOL = 0x4000 }; diff --git a/simskin.cc b/simskin.cc index bc853a6e5..1e1fbb554 100644 --- a/simskin.cc +++ b/simskin.cc @@ -78,7 +78,8 @@ const skin_desc_t* skinverwaltung_t::pumpe = NULL; const skin_desc_t* skinverwaltung_t::senke = NULL; const skin_desc_t* skinverwaltung_t::tunnel_texture = NULL; -slist_tplskinverwaltung_t::extra_obj; +slist_tplskinverwaltung_t::extra_menu_obj; +slist_tplskinverwaltung_t::extra_cursor_obj; static special_obj_tpl const misc_objekte[] = { @@ -191,20 +192,25 @@ bool skinverwaltung_t::register_desc(skintyp_t type, const skin_desc_t* desc) case nothing: return true; default: return false; } - if( !::register_desc(sd, desc) ) { - // currently no misc objects allowed ... - if( !(type==cursor || type==symbol) ) { - if( type==menu ) { - extra_obj.insert( desc ); - dbg->message( "skinverwaltung_t::register_desc()","Extra object %s added.", desc->get_name() ); - } - else { - dbg->warning("skinverwaltung_t::register_desc()","Spurious object '%s' loaded (will not be referenced anyway)!", desc->get_name() ); - } + if( ::register_desc(sd, desc) ) { + return true; + } + else if( type==cursor || type==symbol ) { + if( ::register_desc( fakultative_objekte, desc ) ) { + return true; } - else { - return ::register_desc( fakultative_objekte, desc ); + } + // currently no misc objects allowed ... + if( type==cursor || type==menu ) { + if( type==cursor ) { + extra_cursor_obj.insert( desc ); + } else { + extra_menu_obj.insert( desc ); } + dbg->message( "skinverwaltung_t::register_desc()","Extra object %s added.", desc->get_name() ); + } + else { + dbg->warning("skinverwaltung_t::register_desc()","Spurious object '%s' loaded (will not be referenced anyway)!", desc->get_name() ); } return true; } @@ -212,10 +218,15 @@ bool skinverwaltung_t::register_desc(skintyp_t type, const skin_desc_t* desc) // return the extra_obj with this name -const skin_desc_t *skinverwaltung_t::get_extra( const char *str, int len ) +const skin_desc_t *skinverwaltung_t::get_extra( const char *str, int len, skintyp_t type ) { - FOR(slist_tpl, const s, skinverwaltung_t::extra_obj) { - if (strncmp(str, s->get_name(), len) == 0) { + if( type!=menu && type!=cursor ) { + // illegal type + return NULL; + } + FOR(slist_tpl, const s, + (type==menu ? skinverwaltung_t::extra_menu_obj : skinverwaltung_t::extra_cursor_obj)) { + if ( strncmp(str, s->get_name(), len) == 0 ) { return s; } } diff --git a/simskin.h b/simskin.h index 54789d202..b8ef09ede 100644 --- a/simskin.h +++ b/simskin.h @@ -152,11 +152,12 @@ public: * @param len length of string * @return pointer to skin object or NULL if nothing found */ - static const skin_desc_t *get_extra( const char *str, int len ); + static const skin_desc_t *get_extra( const char *str, int len, skintyp_t type = menu ); private: - /// holds objects from paks with type 'menu' - static slist_tplextra_obj; + /// holds objects from paks with type 'menu' and 'cursor' + static slist_tplextra_menu_obj; + static slist_tplextra_cursor_obj; }; #endif diff --git a/simtool-dialogs.h b/simtool-dialogs.h index a282bc6cc..0c2a4151f 100644 --- a/simtool-dialogs.h +++ b/simtool-dialogs.h @@ -48,6 +48,7 @@ #include "gui/scenario_info.h" #include "gui/depotlist_frame.h" #include "gui/vehiclelist_frame.h" +#include "gui/script_tool_frame.h" class player_t; @@ -273,6 +274,21 @@ public: bool is_init_network_save() const OVERRIDE{ return true; } }; +// open scenario dialog +class dialog_script_tool_t : public tool_t { +public: + dialog_script_tool_t() : tool_t(DIALOG_SCRIPT_TOOL | DIALOGE_TOOL) {} + char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("Load tool script"); } + bool is_selected() const OVERRIDE{ return win_get_magic(magic_load_t); } + bool init(player_t*) OVERRIDE{ + destroy_win(magic_save_t); + create_win( new script_tool_frame_t(), w_info, magic_load_t ); + return false; + } + bool exit(player_t*) OVERRIDE{ destroy_win(magic_load_t); return false; } + bool is_init_network_save() const OVERRIDE{ return true; } +}; + // open scenario dialog class dialog_scenario_t : public tool_t { public: diff --git a/simtool.cc b/simtool.cc index 6f84a189d..ae3364362 100644 --- a/simtool.cc +++ b/simtool.cc @@ -92,6 +92,11 @@ #include "simtool.h" #include "player/finance.h" +// scripting +#include "script/script.h" +#include "script/export_objs.h" +#include "script/api/api.h" + #define is_scenario() welt->get_scenario()->is_scripted() @@ -6466,6 +6471,137 @@ const char *tool_merge_stop_t::do_work( player_t *player, const koord3d &last_po return NULL; } + +bool tool_exec_script_t::init( player_t * p ) { + // default_param holds script path + // init script vm if required. + init_vm(get_default_param(), p); + return call_function("init", p); +} + +void exec_script_base_t::init_vm( const char* path, player_t* player ) { + if( !script || restart ) { + load_script(path, player); + } +} + +bool load_base_script(script_vm_t *script, const char* base); // scenario.cc + +void exec_script_base_t::load_script( const char* path, player_t* player ) { + cbuffer_t buf; + buf.printf("script-exec-%d.log", player->get_player_nr()); + if( script ) { + // if vm already exists, delete it. + delete script; + } + script = new script_vm_t(path, buf); + // load ai definition + char filename[PATH_MAX]; + sprintf( filename, "%s/tool.nut", path ); + // load global stuff + // constants must be known compile time + export_global_constants(script->get_vm()); + + // load scripting base definitions and tool base definitions + if ( !load_base_script(script, "script_base.nut") || + !load_base_script(script, "tool_base.nut") ) { + return; + } + + // register api functions + register_export_function(script->get_vm(), false); + if (script->get_error()) { + dbg->error("tool_exec_script_t::load_script", "error [%s] calling register_export_function", script->get_error()); + return; + } + // set my player number + script->set_my_player(player->get_player_nr()); + if (const char* err = script->call_script(filename)) { + if (strcmp(err, "suspended")) { + dbg->error("tool_exec_script_t::load_script", "error [%s] calling %s", err, filename); + } + return; + } +} + +bool exec_script_base_t::call_function(const char* func_name, player_t* player) { + // exec script function that takes player and return bool + if( !script ) { + dbg->error("tool_exec_script_t::call_function", "script vm is not available."); + return false; + } + + bool ret_val; + const char* err; + err = script->call_function(script_vm_t::QUEUE, func_name, ret_val, player); + + if( err ) { + // script execution error + dbg->error("tool_exec_script_t::call_function", "%s", err); + return false; + } + return ret_val; +} + +const char* exec_script_base_t::call_function(const char* func_name, player_t* pl , koord3d pos) { + uint8 dummy; + return call_function_intern(1, func_name, pl, pos, koord3d::invalid, dummy); +} + +const char* exec_script_base_t::call_function(const char* func_name, player_t* pl , koord3d pos1, koord3d pos2) { + uint8 dummy; + return call_function_intern(2, func_name, pl, pos1, pos2, dummy); +} + +const char* exec_script_base_t::call_function(const char* func_name, player_t* pl , koord3d pos1, koord3d pos2, uint8& num) { + return call_function_intern(3, func_name, pl, pos1, pos2, num); +} + +const char* exec_script_base_t::call_function_intern(uint8 arg_num, const char* func_name, player_t* player, koord3d pos1, koord3d pos2, uint8& num) { + // exec script function that takes player and pos + plainstring* msg = new plainstring(); + if( !script ) { + dbg->error("tool_exec_script_t::call_function", "script vm is not available."); + return "script vm internal error!"; + } + const char* err; + if( arg_num==1 ) { + err = script->call_function(script_vm_t::QUEUE, func_name, *msg, player, pos1); + } else if( arg_num==2 ) { + err = script->call_function(script_vm_t::QUEUE, func_name, *msg, player, pos1, pos2); + } else { + // arg_num == 3 + // TODO: error message by script function + err = script->call_function(script_vm_t::QUEUE, func_name, num, player, pos1, pos2); + } + if( err ) { + // script execution error + dbg->error("tool_exec_script_t::call_function", "%s", err); + return err; + } + // propagate error + if( msg->c_str()==NULL ) { + delete msg; + return NULL; + } else { + return msg->c_str(); + } +} + + +bool tool_exec_two_click_script_t::init(player_t* pl) { + init_vm(get_default_param(), pl); + return two_click_tool_t::init(pl); +} + +uint8 tool_exec_two_click_script_t::is_valid_pos( player_t *pl, const koord3d &pos, const char *&error, const koord3d &start ) { + error = NULL; + uint8 ret_val; + call_function("is_valid_pos", pl, pos, start, ret_val); + return ret_val; +} + + bool tool_show_trees_t::init( player_t * ) { env_t::hide_trees = !env_t::hide_trees; diff --git a/simtool.h b/simtool.h index 555215c08..3dfb8f8fd 100644 --- a/simtool.h +++ b/simtool.h @@ -33,6 +33,7 @@ class roadsign_desc_t; class way_desc_t; class route_t; class way_obj_desc_t; +class script_vm_t; /****************************** helper functions: *****************************/ @@ -645,6 +646,53 @@ public: char const* work(player_t*, koord3d) OVERRIDE { return default_param ? default_param : ""; } }; + +class exec_script_base_t { +private: + script_vm_t *script; + char menu_arg[PATH_MAX]; + bool restart; // true -> the script vm is always scrapped when exit() is called. + void load_script(const char* path, player_t* player); + const char *call_function_intern(uint8 arg_num, const char*, player_t*, koord3d, koord3d, uint8&); +protected: + char title[PATH_MAX]; + void init_vm(const char* path, player_t* player); + bool call_function(const char*, player_t*); + const char *call_function(const char*, player_t*, koord3d); + const char *call_function(const char*, player_t*, koord3d, koord3d); + const char *call_function(const char*, player_t*, koord3d, koord3d, uint8&); +public: + exec_script_base_t() : script(NULL), restart(false) {} + const char* get_menu_arg() const { return menu_arg; } + void set_menu_arg(const char* arg) { strcpy(menu_arg, arg); } + void set_title(const char* str) { strcpy(title, str); } + void enable_restart(bool tf = true) { restart = tf; } +}; + +class tool_exec_script_t : public tool_t, public exec_script_base_t { +public: + tool_exec_script_t() : tool_t(TOOL_EXEC_SCRIPT | GENERAL_TOOL), + exec_script_base_t() {} + bool is_init_network_save() const OVERRIDE { return true; } + bool init(player_t*) OVERRIDE; + bool exit( player_t * player) OVERRIDE { return call_function("exit", player); } + const char *work(player_t* pl, koord3d pos) OVERRIDE { return call_function("work", pl, pos); } + const char *check_pos(player_t* pl, koord3d pos) OVERRIDE { return call_function("check_pos", pl, pos); } + const char *get_tooltip(const player_t *) const OVERRIDE { return title; } +}; + +class tool_exec_two_click_script_t : public two_click_tool_t, public exec_script_base_t { +public: + tool_exec_two_click_script_t() : + two_click_tool_t(TOOL_EXEC_TWO_CLICK_SCRIPT | GENERAL_TOOL), exec_script_base_t() {} + bool init(player_t* pl) OVERRIDE; + bool is_init_network_save() const OVERRIDE { return true; } + const char *get_tooltip(const player_t *) const OVERRIDE { return title; } + uint8 is_valid_pos( player_t *, const koord3d &pos, const char *&error, const koord3d &start ) OVERRIDE; + const char *do_work( player_t *pl, const koord3d &start, const koord3d &end ) OVERRIDE { return call_function("do_work", pl, start, end); }; + void mark_tiles( player_t *pl, const koord3d &start, const koord3d &end ) OVERRIDE { call_function("mark_tiles", pl, start, end); } +}; + /********************* one click tools ****************************/ class tool_pause_t : public tool_t { diff --git a/simutrans/script/tool_base.nut b/simutrans/script/tool_base.nut new file mode 100644 index 000000000..a950e0407 --- /dev/null +++ b/simutrans/script/tool_base.nut @@ -0,0 +1,72 @@ +/** + * Base file for tools + */ + +/** + * initialization, called when tool is called + * Returning true will select tool and will make it possible to call work. + * @param pl player_x object by whom the tool is called + */ +function init(pl) +{ + return true +} + +/** + * function called when the tool is clicked on a ground + * the return string can have different meanings: + * NULL: ok + * "": unspecified error + * "blabla": errors message, will be handled and translated as appropriate + * @param pl player_x object by whom the tool is called + * @param pos coord3d object that represents the position + */ +function work(pl, pos) +{ + return null +} + +/** + * function for position check. called before work() + * @param pl player_x object by whom the tool is called + * @param pos coord3d object that represents the position + */ +function check_pos(pl, pos) +{ + return null +} + +/** + * termination, called when the player exits from this tool + * @param pl player_x object by whom the tool is called + */ +function exit(pl) +{ + return true +} + +/* For two-click tools */ + +/** + * return state number as integer + */ +function is_valid_pos(pl, pos, start) +{ + return 3 +} + +/** + * return error message + */ +function do_work(pl, start, end) +{ + return null +} + +/** + * no return value + */ +function mark_tiles(pl, start, end) +{ + +}