diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index 2bce4861b5..6e2ad93c4d 100644 --- a/src/lang/finnish.txt +++ b/src/lang/finnish.txt @@ -189,6 +189,7 @@ STR_COLOUR_ORANGE :Oranssi STR_COLOUR_BROWN :Ruskea STR_COLOUR_GREY :Harmaa STR_COLOUR_WHITE :Valkoinen +STR_COLOUR_RANDOM :Satunnainen # Units used in OpenTTD STR_UNITS_VELOCITY_IMPERIAL :{COMMA}{NBSP}mph @@ -927,6 +928,7 @@ STR_GAME_OPTIONS_CURRENCY_CUSTOM :Oma... STR_GAME_OPTIONS_CURRENCY_GEL :Georgian lari (GEL) STR_GAME_OPTIONS_CURRENCY_IRR :Iranin rial (IRR) STR_GAME_OPTIONS_CURRENCY_RUB :Uusi Venäjän rupla (RUB) +STR_GAME_OPTIONS_CURRENCY_MXN :Meksikon peso (MXN) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Kulkuneuvot diff --git a/src/lang/french.txt b/src/lang/french.txt index 874ad03de0..aedcdb7547 100644 --- a/src/lang/french.txt +++ b/src/lang/french.txt @@ -931,6 +931,7 @@ STR_GAME_OPTIONS_CURRENCY_CUSTOM :Personnalisée. STR_GAME_OPTIONS_CURRENCY_GEL :Lari Géorgien (GEL) STR_GAME_OPTIONS_CURRENCY_IRR :Rial Iranien (IRR) STR_GAME_OPTIONS_CURRENCY_RUB :Nouveau rouble russe (RUB) +STR_GAME_OPTIONS_CURRENCY_MXN :Peso méxicain (MXN) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Véhicules routiers @@ -2379,9 +2380,9 @@ STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP :{BLACK}Signal c STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP :{BLACK}Signal de chemin (électrique){}Un signal de chemin autorise plus d'un train à entrer dans un bloc de signaux en même temps, si le train peut réserver un chemin jusqu'à un point d'attente sûr. Les signaux de chemin peuvent être passés par l'arrière. STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP :{BLACK}Signal de chemin à sens unique (électrique){}Un signal de chemin autorise plus d'un train à entrer dans un bloc de signaux en même temps, si le train peut réserver un chemin jusqu'à un point d'attente sûr. Les signaux de chemin à sens unique ne peuvent pas être passés par l'arrière. STR_BUILD_SIGNAL_CONVERT_TOOLTIP :{BLACK}Conversion de signal.{}Si sélectionné, cliquer sur un signal existant le convertit vers le type et la variante choisis.{}Ctrl-clic pour alterner entre les variantes existantes.{}Shift pour afficher seulement le coût estimé. -STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP :{BLACK}Densité de signaux -STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP :{BLACK}Réduire l'intervalle entre les signaux (augmenter la densité) -STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP :{BLACK}Augmenter l'intervalle entre les signaux (réduire la densité) +STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP :{BLACK}Intervalle entre les signaux +STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP :{BLACK}Réduire l'intervalle entre les signaux +STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP :{BLACK}Augmenter l'intervalle entre les signaux # Bridge selection window STR_SELECT_RAIL_BRIDGE_CAPTION :{WHITE}Choisir un pont ferroviaire diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index dded80fdaf..08ef388566 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -29,6 +29,7 @@ #include "core/random_func.hpp" #include "aircraft.h" #include "roadveh.h" +#include "ship.h" #include "station_base.h" #include "waypoint_base.h" #include "company_base.h" @@ -1086,7 +1087,7 @@ CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 dist = GetOrderDistance(prev, &new_order, v); } - if (dist >= 130) { + if (dist >= SHIP_MAX_ORDER_DISTANCE) { return_cmd_error(STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION); } } diff --git a/src/script/api/squirrel_export.awk b/src/script/api/squirrel_export.awk index 2cb47deddd..ef0a74c8db 100644 --- a/src/script/api/squirrel_export.awk +++ b/src/script/api/squirrel_export.awk @@ -29,46 +29,46 @@ function dump_class_templates(name) realname = name gsub("^Script", "", realname) - print " template <> inline " name " *GetParam(ForceType<" name " *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (" name " *)instance; }" - print " template <> inline " name " &GetParam(ForceType<" name " &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(" name " *)instance; }" - print " template <> inline const " name " *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (" name " *)instance; }" - print " template <> inline const " name " &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(" name " *)instance; }" + print " template <> inline " name " *GetParam(ForceType<" name " *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (" name " *)instance; }" CR + print " template <> inline " name " &GetParam(ForceType<" name " &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(" name " *)instance; }" CR + print " template <> inline const " name " *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (" name " *)instance; }" CR + print " template <> inline const " name " &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(" name " *)instance; }" CR if (name == "ScriptEvent") { - print " template <> inline int Return<" name " *>(HSQUIRRELVM vm, " name " *res) { if (res == NULL) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, \"" realname "\", res, NULL, DefSQDestructorCallback<" name ">, true); return 1; }" + print " template <> inline int Return<" name " *>(HSQUIRRELVM vm, " name " *res) { if (res == NULL) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, \"" realname "\", res, NULL, DefSQDestructorCallback<" name ">, true); return 1; }" CR } else if (name == "ScriptText") { - print "" - print " template <> inline Text *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) {" - print " if (sq_gettype(vm, index) == OT_INSTANCE) {" - print " return GetParam(ForceType(), vm, index, ptr);" - print " }" - print " if (sq_gettype(vm, index) == OT_STRING) {" - print " return new RawText(GetParam(ForceType(), vm, index, ptr));" - print " }" - print " return NULL;" - print " }" + print "" CR + print " template <> inline Text *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) {" CR + print " if (sq_gettype(vm, index) == OT_INSTANCE) {" CR + print " return GetParam(ForceType(), vm, index, ptr);" CR + print " }" CR + print " if (sq_gettype(vm, index) == OT_STRING) {" CR + print " return new RawText(GetParam(ForceType(), vm, index, ptr));" CR + print " }" CR + print " return NULL;" CR + print " }" CR } else { - print " template <> inline int Return<" name " *>(HSQUIRRELVM vm, " name " *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, \"" realname "\", res, NULL, DefSQDestructorCallback<" name ">, true); return 1; }" + print " template <> inline int Return<" name " *>(HSQUIRRELVM vm, " name " *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, \"" realname "\", res, NULL, DefSQDestructorCallback<" name ">, true); return 1; }" CR } } function dump_fileheader() { # Break the Id tag, so SVN doesn't replace it - print "/* $I" "d$ */" - print "" - print "/*" - print " * This file is part of OpenTTD." - print " * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2." - print " * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - print " * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see ." - print " */" - print "" - print "/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */" - print "" - print "#include \"../" filename "\"" + print "/* $I" "d$ */" CR + print "" CR + print "/*" CR + print " * This file is part of OpenTTD." CR + print " * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2." CR + print " * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." CR + print " * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see ." CR + print " */" CR + print "" CR + print "/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */" CR + print "" CR + print "#include \"../" filename "\"" CR if (api != "Template") { gsub("script_", "template_", filename) - print "#include \"../template/" filename ".sq\"" + print "#include \"../template/" filename ".sq\"" CR } } @@ -103,11 +103,12 @@ BEGIN { start_squirrel_define_on_next_line = "false" has_fileheader = "false" cls_level = 0 - RS = "\r|\n" apis = tolower(api) if (apis == "gs") apis = "game" } +{ CR = (match($0, "\\r$") > 0 ? "\r" : "") } + /@file/ { filename = $3 gsub("^" apis "_", "script_", filename) @@ -136,13 +137,13 @@ BEGIN { if (api == "Template") { api_selected = "true" - if ($0 == "none" || $0 == "-all") api_selected = "false" + if ($0 == "none" CR || $0 == "-all" CR) api_selected = "false" next } - if ($0 == "none") { + if ($0 == "none" CR) { api_selected = "false" - } else if ($0 == "-all") { + } else if ($0 == "-all" CR) { api_selected = "false" } else if (match($0, "-" apis)) { api_selected = "false" @@ -259,7 +260,7 @@ BEGIN { } # Empty/white lines. When we may do the Squirrel export, do that export. -/^([ ]*)$/ { +/^([ ]*)\r*$/ { if (start_squirrel_define_on_next_line == "false") next if (cls_in_api != "true") { @@ -280,19 +281,19 @@ BEGIN { api_super_cls = super_cls gsub("^Script", api, api_super_cls) - print "" + print "" CR if (api == "Template") { # First check whether we have enums to print if (enum_size != 0) { if (namespace_opened == "false") { - print "namespace SQConvert {" + print "namespace SQConvert {" CR namespace_opened = "true" } - print " /* Allow enums to be used as Squirrel parameters */" + print " /* Allow enums to be used as Squirrel parameters */" CR for (i = 1; i <= enum_size; i++) { - print " template <> inline " enums[i] " GetParam(ForceType<" enums[i] ">, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (" enums[i] ")tmp; }" - print " template <> inline int Return<" enums[i] ">(HSQUIRRELVM vm, " enums[i] " res) { sq_pushinteger(vm, (int32)res); return 1; }" + print " template <> inline " enums[i] " GetParam(ForceType<" enums[i] ">, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (" enums[i] ")tmp; }" CR + print " template <> inline int Return<" enums[i] ">(HSQUIRRELVM vm, " enums[i] " res) { sq_pushinteger(vm, (int32)res); return 1; }" CR delete enums[i] } } @@ -300,10 +301,10 @@ BEGIN { # Then check whether we have structs/classes to print if (struct_size != 0) { if (namespace_opened == "false") { - print "namespace SQConvert {" + print "namespace SQConvert {" CR namespace_opened = "true" } - print " /* Allow inner classes/structs to be used as Squirrel parameters */" + print " /* Allow inner classes/structs to be used as Squirrel parameters */" CR for (i = 1; i <= struct_size; i++) { dump_class_templates(structs[i]) delete structs[i] @@ -311,41 +312,41 @@ BEGIN { } if (namespace_opened == "false") { - print "namespace SQConvert {" + print "namespace SQConvert {" CR namespace_opened = "true" } else { - print "" + print "" CR } - print " /* Allow " cls " to be used as Squirrel parameter */" + print " /* Allow " cls " to be used as Squirrel parameter */" CR dump_class_templates(cls) - print "} // namespace SQConvert" + print "} // namespace SQConvert" CR reset_reader() next } - print ""; - print "template <> const char *GetClassName<" cls ", ST_" toupper(api) ">() { return \"" api_cls "\"; }" - print ""; + print "" CR + print "template <> const char *GetClassName<" cls ", ST_" toupper(api) ">() { return \"" api_cls "\"; }" CR + print "" CR # Then do the registration functions of the class. */ - print "void SQ" api_cls "_Register(Squirrel *engine)" - print "{" - print " DefSQClass<" cls ", ST_" toupper(api) "> SQ" api_cls "(\"" api_cls "\");" + print "void SQ" api_cls "_Register(Squirrel *engine)" CR + print "{" CR + print " DefSQClass<" cls ", ST_" toupper(api) "> SQ" api_cls "(\"" api_cls "\");" CR if (super_cls == "Text" || super_cls == "ScriptObject" || super_cls == "AIAbstractList::Valuator") { - print " SQ" api_cls ".PreRegister(engine);" + print " SQ" api_cls ".PreRegister(engine);" CR } else { - print " SQ" api_cls ".PreRegister(engine, \"" api_super_cls "\");" + print " SQ" api_cls ".PreRegister(engine, \"" api_super_cls "\");" CR } if (super_cls != "ScriptEvent") { if (cls_param[2] == "v") { - print " SQ" api_cls ".AddSQAdvancedConstructor(engine);" + print " SQ" api_cls ".AddSQAdvancedConstructor(engine);" CR } else { - print " SQ" api_cls ".AddConstructor(engine, \"" cls_param[2] "\");" + print " SQ" api_cls ".AddConstructor(engine, \"" cls_param[2] "\");" CR } } - print "" + print "" CR # Enum values mlen = 0 @@ -353,10 +354,10 @@ BEGIN { if (mlen <= length(enum_value[i])) mlen = length(enum_value[i]) } for (i = 1; i <= enum_value_size; i++) { - print " SQ" api_cls ".DefSQConst(engine, " cls "::" enum_value[i] ", " substr(spaces, 1, mlen - length(enum_value[i])) "\"" enum_value[i] "\");" + print " SQ" api_cls ".DefSQConst(engine, " cls "::" enum_value[i] ", " substr(spaces, 1, mlen - length(enum_value[i])) "\"" enum_value[i] "\");" CR delete enum_value[i] } - if (enum_value_size != 0) print "" + if (enum_value_size != 0) print "" CR # Const values mlen = 0 @@ -364,10 +365,10 @@ BEGIN { if (mlen <= length(const_value[i])) mlen = length(const_value[i]) } for (i = 1; i <= const_size; i++) { - print " SQ" api_cls ".DefSQConst(engine, " cls "::" const_value[i] ", " substr(spaces, 1, mlen - length(const_value[i])) "\"" const_value[i] "\");" + print " SQ" api_cls ".DefSQConst(engine, " cls "::" const_value[i] ", " substr(spaces, 1, mlen - length(const_value[i])) "\"" const_value[i] "\");" CR delete const_value[i] } - if (const_size != 0) print "" + if (const_size != 0) print "" CR # Mapping of OTTD strings to errors mlen = 0 @@ -375,11 +376,11 @@ BEGIN { if (mlen <= length(enum_string_to_error_mapping_string[i])) mlen = length(enum_string_to_error_mapping_string[i]) } for (i = 1; i <= enum_string_to_error_size; i++) { - print " ScriptError::RegisterErrorMap(" enum_string_to_error_mapping_string[i] ", " substr(spaces, 1, mlen - length(enum_string_to_error_mapping_string[i])) cls "::" enum_string_to_error_mapping_error[i] ");" + print " ScriptError::RegisterErrorMap(" enum_string_to_error_mapping_string[i] ", " substr(spaces, 1, mlen - length(enum_string_to_error_mapping_string[i])) cls "::" enum_string_to_error_mapping_error[i] ");" CR delete enum_string_to_error_mapping_string[i] } - if (enum_string_to_error_size != 0) print "" + if (enum_string_to_error_size != 0) print "" CR # Mapping of errors to human 'readable' strings. mlen = 0 @@ -387,10 +388,10 @@ BEGIN { if (mlen <= length(enum_error_to_string_mapping[i])) mlen = length(enum_error_to_string_mapping[i]) } for (i = 1; i <= enum_error_to_string_size; i++) { - print " ScriptError::RegisterErrorMapString(" cls "::" enum_error_to_string_mapping[i] ", " substr(spaces, 1, mlen - length(enum_error_to_string_mapping[i])) "\"" enum_error_to_string_mapping[i] "\");" + print " ScriptError::RegisterErrorMapString(" cls "::" enum_error_to_string_mapping[i] ", " substr(spaces, 1, mlen - length(enum_error_to_string_mapping[i])) "\"" enum_error_to_string_mapping[i] "\");" CR delete enum_error_to_string_mapping[i] } - if (enum_error_to_string_size != 0) print "" + if (enum_error_to_string_size != 0) print "" CR # Static methods mlen = 0 @@ -399,13 +400,13 @@ BEGIN { } for (i = 1; i <= static_method_size; i++) { if (static_methods[i, 2] == "v") { - print " SQ" api_cls ".DefSQAdvancedStaticMethod(engine, &" cls "::" static_methods[i, 0] ", " substr(spaces, 1, mlen - length(static_methods[i, 0]) - 8) "\"" static_methods[i, 0] "\");" + print " SQ" api_cls ".DefSQAdvancedStaticMethod(engine, &" cls "::" static_methods[i, 0] ", " substr(spaces, 1, mlen - length(static_methods[i, 0]) - 8) "\"" static_methods[i, 0] "\");" CR } else { - print " SQ" api_cls ".DefSQStaticMethod(engine, &" cls "::" static_methods[i, 0] ", " substr(spaces, 1, mlen - length(static_methods[i, 0])) "\"" static_methods[i, 0] "\", " substr(spaces, 1, mlen - length(static_methods[i, 0])) "" static_methods[i, 1] ", \"" static_methods[i, 2] "\");" + print " SQ" api_cls ".DefSQStaticMethod(engine, &" cls "::" static_methods[i, 0] ", " substr(spaces, 1, mlen - length(static_methods[i, 0])) "\"" static_methods[i, 0] "\", " substr(spaces, 1, mlen - length(static_methods[i, 0])) "" static_methods[i, 1] ", \"" static_methods[i, 2] "\");" CR } delete static_methods[i] } - if (static_method_size != 0) print "" + if (static_method_size != 0) print "" CR # Non-static methods mlen = 0 @@ -414,16 +415,16 @@ BEGIN { } for (i = 1; i <= method_size; i++) { if (methods[i, 2] == "v") { - print " SQ" api_cls ".DefSQAdvancedMethod(engine, &" cls "::" methods[i, 0] ", " substr(spaces, 1, mlen - length(methods[i, 0]) - 8) "\"" methods[i, 0] "\");" + print " SQ" api_cls ".DefSQAdvancedMethod(engine, &" cls "::" methods[i, 0] ", " substr(spaces, 1, mlen - length(methods[i, 0]) - 8) "\"" methods[i, 0] "\");" CR } else { - print " SQ" api_cls ".DefSQMethod(engine, &" cls "::" methods[i, 0] ", " substr(spaces, 1, mlen - length(methods[i, 0])) "\"" methods[i, 0] "\", " substr(spaces, 1, mlen - length(methods[i, 0])) "" methods[i, 1] ", \"" methods[i, 2] "\");" + print " SQ" api_cls ".DefSQMethod(engine, &" cls "::" methods[i, 0] ", " substr(spaces, 1, mlen - length(methods[i, 0])) "\"" methods[i, 0] "\", " substr(spaces, 1, mlen - length(methods[i, 0])) "" methods[i, 1] ", \"" methods[i, 2] "\");" CR } delete methods[i] } - if (method_size != 0) print "" + if (method_size != 0) print "" CR - print " SQ" api_cls ".PostRegister(engine);" - print "}" + print " SQ" api_cls ".PostRegister(engine);" CR + print "}" CR reset_reader() @@ -438,6 +439,7 @@ BEGIN { if (in_enum == "true") { enum_value_size++ sub(",", "", $1) + sub("\r", "", $1) enum_value[enum_value_size] = $1 # Check if this a special error enum @@ -475,7 +477,7 @@ BEGIN { } # Add a method to the list -/^.*\(.*\).*$/ { +/^.*\(.*\).*\r*$/ { if (cls_level != 1) next if (match($0, "~")) { if (api_selected != "") { diff --git a/src/script/api/squirrel_export.sh b/src/script/api/squirrel_export.sh index 92bd434b93..e1f5e8613c 100755 --- a/src/script/api/squirrel_export.sh +++ b/src/script/api/squirrel_export.sh @@ -26,7 +26,7 @@ apilc=`pwd | sed "s@/api@@;s@.*/@@"` # Check if we are in the root directory of the API, as then we generate all APIs if [ "$apilc" = "script" ]; then - for api in `find -type d | cut -b3- | grep -v '\.svn\|/'`; do + for api in `find . -type d | cut -b3-`; do if [ -z "$api" ]; then continue; fi echo "Generating for API '$api' ..." cd $api @@ -43,57 +43,34 @@ case $apilc in *) echo "Unknown API type."; exit 1 ;; esac -if [ -z "$1" ]; then - for f in `ls ../*.hpp`; do - bf=`basename ${f} | sed s@script_@${apilc}_@` +for f in `ls ../*.hpp`; do + bf=`basename ${f} | sed s@script_@${apilc}_@` - # ScriptController has custom code, and should not be generated - if [ "`basename ${f}`" = "script_controller.hpp" ]; then continue; fi - if [ "`basename ${f}`" = "script_object.hpp" ]; then continue; fi + # ScriptController has custom code, and should not be generated + if [ "`basename ${f}`" = "script_controller.hpp" ]; then continue; fi - ${AWK} -v api=${apiuc} -f ${scriptdir}/squirrel_export.awk ${f} > ${bf}.tmp + ${AWK} -v api=${apiuc} -f ${scriptdir}/squirrel_export.awk ${f} > ${bf}.tmp - if [ "`wc -l ${bf}.tmp | cut -d\ -f1`" = "0" ]; then - if [ -f "${bf}.sq" ]; then - echo "Deleted: ${bf}.sq" - svn del --force ${bf}.sq > /dev/null 2>&1 - fi - rm -f ${bf}.tmp - elif ! [ -f "${bf}.sq" ] || [ -n "`diff -I '$Id' ${bf}.tmp ${bf}.sq 2> /dev/null || echo boo`" ]; then - mv ${bf}.tmp ${bf}.sq - echo "Updated: ${bf}.sq" - svn add ${bf}.sq > /dev/null 2>&1 - svn propset svn:eol-style native ${bf}.sq > /dev/null 2>&1 - svn propset svn:keywords Id ${bf}.sq > /dev/null 2>&1 - else - rm -f ${bf}.tmp + if [ "`wc -l ${bf}.tmp | cut -d\ -f1`" = "0" ]; then + if [ -f "${bf}.sq" ]; then + echo "Deleted: ${bf}.sq" + rm -f ${bf}.sq fi - done -else - ${AWK} -v api=${apiuc} -f ${scriptdir}/squirrel_export.awk $1 > $1.tmp - if [ `wc -l $1.tmp | cut -d\ -f1` -eq "0" ]; then - if [ -f "$1.sq" ]; then - echo "Deleted: $1.sq" - svn del --force $1.sq > /dev/null 2>&1 - fi - rm -f $1.tmp - elif ! [ -f "${f}.sq" ] || [ -n "`diff -I '$Id' $1.sq $1.tmp 2> /dev/null || echo boo`" ]; then - mv $1.tmp $1.sq - echo "Updated: $1.sq" - svn add $1.sq > /dev/null 2>&1 - svn propset svn:eol-style native $1.sq > /dev/null 2>&1 - svn propset svn:keywords Id $1.sq > /dev/null 2>&1 + rm -f ${bf}.tmp + elif ! [ -f "${bf}.sq" ] || [ -n "`diff -I '$Id' ${bf}.tmp ${bf}.sq 2> /dev/null || echo boo`" ]; then + mv ${bf}.tmp ${bf}.sq + echo "Updated: ${bf}.sq" else - rm -f $1.tmp + rm -f ${bf}.tmp fi -fi +done # Remove .hpp.sq if .hpp doesn't exist anymore for f in `ls *.hpp.sq`; do f=`echo ${f} | sed "s/.hpp.sq$/.hpp/;s@${apilc}_@script_@"` if [ ! -f ../${f} ];then echo "Deleted: ${f}.sq" - svn del --force ${f}.sq > /dev/null 2>&1 + rm -f ${f}.sq fi done diff --git a/src/script/api/squirrel_export.vbs b/src/script/api/squirrel_export.vbs new file mode 100644 index 0000000000..a13869509a --- /dev/null +++ b/src/script/api/squirrel_export.vbs @@ -0,0 +1,946 @@ +Option Explicit + +' $Id$ +' +' This file is part of OpenTTD. +' OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. +' OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +' See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + +Dim FSO +Dim enum_size, enums, enum_value_size, enum_value +Dim enum_string_to_error_size, enum_string_to_error_mapping_string, enum_string_to_error_mapping_error +Dim enum_error_to_string_size, enum_error_to_string_mapping, const_size, const_value +Dim struct_size, structs, method_size, methods, static_method_size, static_methods +Dim super_cls, cls, api_selected, cls_in_api, start_squirrel_define_on_next_line, has_fileheader, cls_level +Dim apis, filename, doxygen_skip, squirrel_stuff, is_public, cls_param(2), comment, in_enum + +Set FSO = CreateObject("Scripting.FileSystemObject") + +Function CompareFiles(filename1, filename2) + Dim file, lines1, lines2 + + If Not FSO.FileExists(filename1) Then + CompareFiles = False + Exit Function + End If + Set file = FSO.OpenTextFile(filename1, 1) + If Not file.AtEndOfStream Then + lines1 = file.ReadAll + End IF + file.Close + + If Not FSO.FileExists(filename2) Then + CompareFiles = False + Exit Function + End If + Set file = FSO.OpenTextFile(filename2, 1) + If Not file.AtEndOfStream Then + lines2 = file.ReadAll + End IF + file.Close + + CompareFiles = (lines1 = lines2) +End Function + +Function IsEmptyFile(filename) + Dim file + Set file = FSO.OpenTextFile(filename, 1) + IsEmptyFile = file.AtEndOfStream + file.Close +End Function + +Function DumpClassTemplates(name, file) + Dim re, realname + Set re = New RegExp + + re.Pattern = "^Script" + realname = re.Replace(name, "") + + file.WriteLine " template <> inline " & name & " *GetParam(ForceType<" & name & " *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (" & name & " *)instance; }" + file.WriteLine " template <> inline " & name & " &GetParam(ForceType<" & name & " &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(" & name & " *)instance; }" + file.WriteLine " template <> inline const " & name & " *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (" & name & " *)instance; }" + file.WriteLine " template <> inline const " & name & " &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(" & name & " *)instance; }" + If name = "ScriptEvent" Then + file.WriteLine " template <> inline int Return<" & name & " *>(HSQUIRRELVM vm, " & name & " *res) { if (res == NULL) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, " & Chr(34) & realname & Chr(34) & ", res, NULL, DefSQDestructorCallback<" & name & ">, true); return 1; }" + ElseIf name = "ScriptText" Then + file.WriteLine "" + file.WriteLine " template <> inline Text *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) {" + file.WriteLine " if (sq_gettype(vm, index) == OT_INSTANCE) {" + file.WriteLine " return GetParam(ForceType(), vm, index, ptr);" + file.WriteLine " }" + file.WriteLine " if (sq_gettype(vm, index) == OT_STRING) {" + file.WriteLine " return new RawText(GetParam(ForceType(), vm, index, ptr));" + file.WriteLine " }" + file.WriteLine " return NULL;" + file.WriteLine " }" + Else + file.WriteLine " template <> inline int Return<" & name & " *>(HSQUIRRELVM vm, " & name & " *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, " & Chr(34) & realname & Chr(34) & ", res, NULL, DefSQDestructorCallback<" & name & ">, true); return 1; }" + End If +End Function + +Function DumpFileheader(api, file) + Dim re + Set re = New RegExp + ' Break the Id tag, so SVN doesn't replace it + file.WriteLine "/* $I" & "d$ */" + file.WriteLine "" + file.WriteLine "/*" + file.WriteLine " * This file is part of OpenTTD." + file.WriteLine " * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2." + file.WriteLine " * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + file.WriteLine " * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see ." + file.WriteLine " */" + file.WriteLine "" + file.WriteLine "/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */" + file.WriteLine "" + file.WriteLine "#include " & Chr(34) & "../" & filename & Chr(34) + If api <> "Template" Then + re.Pattern = "script_" + filename = re.Replace(filename, "template_") + file.WriteLine "#include " & Chr(34) & "../template/" & filename & ".sq" & Chr(34) + End If +End Function + +Function ResetReader() + enum_size = 0 + enums.RemoveAll + enum_value_size = 0 + enum_value.RemoveAll + enum_string_to_error_size = 0 + enum_string_to_error_mapping_string.RemoveAll + enum_string_to_error_mapping_error.RemoveAll + enum_error_to_string_size = 0 + enum_error_to_string_mapping.RemoveAll + const_size = 0 + const_value.RemoveAll + struct_size = 0 + structs.RemoveAll + method_size = 0 + methods.RemoveAll + static_method_size = 0 + static_methods.RemoveAll + cls = "" + start_squirrel_define_on_next_line = False + cls_level = 0 + cls_in_api = "" +End Function + +Sub SquirrelExportParse(api, line, file) + Dim re + Set re = New RegExp + + re.Pattern = "@file" + If re.Test(line) Then + filename = Split(line)(2) + re.Pattern = "^" & apis & "_" + filename = re.Replace(filename, "script_") + End If + + ' Ignore special doxygen blocks + re.Pattern = "^#ifndef DOXYGEN_API" + If re.Test(line) Then + doxygen_skip = "next" + Exit Sub + End If + re.Pattern = "^#ifdef DOXYGEN_API" + If re.Test(line) Then + doxygen_skip = "true" + Exit Sub + End If + re.Pattern = "^#endif /\* DOXYGEN_API \*/" + If re.Test(line) Then + doxygen_skip = "false" + Exit Sub + End If + re.Pattern = "^#else" + If re.Test(line) Then + If doxygen_skip = "next" Then + doxygen_skip = "true" + Else + doxygen_skip = "false" + End If + Exit Sub + End If + If doxygen_skip = "true" Then Exit Sub + + re.Pattern = "^([ ]*)\* @api" + If re.Test(line) Then + ' By default, classes are not selected + If cls_level = 0 Then api_selected = "false" + + re.Pattern = "^([ ]*)" + line = re.Replace(line, "") + re.Pattern = "\* @api " + line = re.Replace(line, "") + + If api = "Template" Then + api_selected = "true" + If line = "none" Or line = "-all" Then api_selected = "false" + Exit Sub + End If + + If line = "none" Then + api_selected = "false" + ElseIf line = "-all" Then + api_selected = "false" + Else + re.Pattern = "-" & apis + If re.Test(line) Then + api_selected = "false" + Else + re.Pattern = apis + If re.Test(line) Then + api_selected = "true" + End If + End If + End If + Exit Sub + End If + + ' Remove the old squirrel stuff + re.Pattern = "#ifdef DEFINE_SQUIRREL_CLASS" + If re.Test(line) Then + squirrel_stuff = True + Exit Sub + End If + re.Pattern = "^#endif /\* DEFINE_SQUIRREL_CLASS \*/" + If re.Test(line) Then + If squirrel_stuff Then squirrel_stuff = False + Exit Sub + End If + If squirrel_stuff Then Exit Sub + + ' Ignore forward declarations of classes + re.Pattern = "^( *)class(.*);" + If re.Test(line) Then Exit Sub + ' We only want to have public functions exported for now + re.Pattern = "^( *)class" + If re.Test(line) Then + line = Split(line) + If cls_level = 0 Then + If api_selected = "" Then + WScript.Echo "Class '" & line(1) & "' has no @api. It won't be published to any API." + api_selected = "false" + End If + is_public = False + cls_param(0) = "" + cls_param(1) = 1 + cls_param(2) = "x" + cls_in_api = api_selected + api_selected = "" + cls = line(1) + re.Pattern = "public|protected|private" + If UBound(line) > 2 Then + If re.Test(line(3)) Then + super_cls = line(4) + Else + super_cls = line(3) + End If + End If + ElseIf cls_level = 1 Then + If api_selected = "" Then api_selected = cls_in_api + + If api_selected = "true" Then + struct_size = struct_size + 1 + structs.Item(struct_size) = cls & "::" & line(1) + End If + api_selected = "" + End If + cls_level = cls_level + 1 + Exit Sub + End If + re.Pattern = "^( *)public" + If re.Test(line) Then + If cls_level = 1 Then is_public = True + Exit Sub + End If + re.Pattern = "^( *)protected" + If re.Test(line) Then + If cls_level = 1 Then is_public = False + Exit Sub + End If + re.Pattern = "^( *)private" + If re.Test(line) Then + If cls_level = 1 Then is_public = False + Exit Sub + End If + + ' Ignore the comments + re.Pattern = "^#" + If re.Test(line) Then Exit Sub + re.Pattern = "/\*.*\*/" + If re.Test(line) Then + comment = False + Exit Sub + End If + re.Pattern = "/\*" + If re.Test(line) Then + comment = True + Exit Sub + End If + re.Pattern = "\*/" + If re.Test(line) Then + comment = False + Exit Sub + End If + If comment Then Exit Sub + + ' We need to make specialized conversions for structs + re.Pattern = "^( *)struct" + If re.Test(line) Then + cls_level = cls_level + 1 + + ' Check if we want to publish this struct + If api_selected = "" Then api_selected = cls_in_api + If api_selected = "false" Then + api_selected = "" + Exit Sub + End If + api_selected = "" + + If Not is_public Then Exit Sub + If cls_level <> 1 Then Exit Sub + + struct_size = struct_size + 1 + structs.Item(struct_size) = cls & "::" & Split(line)(1) + Exit Sub + End If + + ' We need to make specialized conversions for enums + re.Pattern = "^( *)enum" + If re.Test(line) Then + cls_level = cls_level + 1 + + ' Check if we want to publish this enum + If api_selected = "" Then api_selected = cls_in_api + If api_selected = "false" Then + api_selected = "" + Exit Sub + End If + api_selected = "" + + If Not is_public Then Exit Sub + + in_enum = True + enum_size = enum_size + 1 + enums.Item(enum_size) = cls & "::" & Split(line)(1) + Exit Sub + End If + + ' Maybe the end of the class, if so we can start with the Squirrel export pretty soon + re.Pattern = "};" + If re.Test(line) Then + cls_level = cls_level - 1 + If cls_level <> 0 Then + in_enum = False + Exit Sub + End If + + If cls = "" Then Exit Sub + start_squirrel_define_on_next_line = True + Exit Sub + End If + + ' Empty/white lines. When we may do the Squirrel export, do that export. + re.Pattern = "^([ ]*)$" + If re.Test(line) Then + Dim namespace_opened, api_cls, api_super_cls, i, mlen, spaces + + If Not start_squirrel_define_on_next_line Then Exit Sub + + If cls_in_api <> "true" Then + ResetReader + Exit Sub + End If + If Not has_fileheader Then + DumpFileHeader api, file + has_fileheader = True + End If + + is_public = False + namespace_opened = False + + re.Pattern = "^Script" + api_cls = re.Replace(cls, api) + api_super_cls = re.Replace(super_cls, api) + + file.WriteLine "" + + If api = "Template" Then + ' First check whether we have enums to print + If enum_size <> 0 Then + If Not namespace_opened Then + file.WriteLine "namespace SQConvert {" + namespace_opened = True + End If + file.WriteLine " /* Allow enums to be used as Squirrel parameters */" + For i = 1 To enum_size + file.WriteLine " template <> inline " & enums.Item(i) & " GetParam(ForceType<" & enums.Item(i) & ">, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (" & enums.Item(i) & ")tmp; }" + file.WriteLine " template <> inline int Return<" & enums.Item(i) & ">(HSQUIRRELVM vm, " & enums.Item(i) & " res) { sq_pushinteger(vm, (int32)res); return 1; }" + Next + End If + + ' Then check whether we have structs/classes to print + If struct_size <> 0 Then + If Not namespace_opened Then + file.WriteLine "namespace SQConvert {" + namespace_opened = True + End If + file.WriteLine " /* Allow inner classes/structs to be used as Squirrel parameters */" + For i = 1 To struct_size + DumpClassTemplates structs.Item(i), file + Next + End If + + If Not namespace_opened Then + file.WriteLine "namespace SQConvert {" + namespace_opened = True + Else + file.WriteLine "" + End If + file.WriteLine " /* Allow " & cls & " to be used as Squirrel parameter */" + DumpClassTemplates cls, file + + file.WriteLine "} // namespace SQConvert" + + ResetReader + Exit Sub + End If + + file.WriteLine "" + file.WriteLine "template <> const char *GetClassName<" & cls & ", ST_" & UCase(api) & ">() { return " & Chr(34) & api_cls & Chr(34) & "; }" + file.WriteLine "" + + ' Then do the registration functions of the class. + file.WriteLine "void SQ" & api_cls & "_Register(Squirrel *engine)" + file.WriteLine "{" + file.WriteLine " DefSQClass<" & cls & ", ST_" & UCase(api) & "> SQ" & api_cls & "(" & Chr(34) & api_cls & Chr(34) & ");" + If super_cls = "Text" Or super_cls = "ScriptObject" Or super_cls = "AIAbstractiveList::Valuator" Then + file.WriteLine " SQ" & api_cls & ".PreRegister(engine);" + Else + file.WriteLine " SQ" & api_cls & ".PreRegister(engine, " & Chr(34) & api_super_cls & Chr(34) & ");" + End If + If super_cls <> "ScriptEvent" Then + If cls_param(2) = "v" Then + file.WriteLine " SQ" & api_cls & ".AddSQAdvancedConstructor(engine);" + Else + file.WriteLine " SQ" & api_cls & ".AddConstructor(engine, " & Chr(34) & cls_param(2) & Chr(34) & ");" + End If + End If + file.WriteLine "" + + ' Enum values + mlen = 0 + For i = 1 To enum_value_size + If mlen <= Len(enum_value.Item(i)) Then mlen = Len(enum_value.Item(i)) + Next + For i = 1 To enum_value_size + file.WriteLine " SQ" & api_cls & ".DefSQConst(engine, " & cls & "::" & enum_value.Item(i) & ", " & Space(mlen - Len(enum_value.Item(i))) & Chr(34) & enum_value.Item(i) & Chr(34) & ");" + Next + If enum_value_size <> 0 Then file.WriteLine "" + + ' Const values + mlen = 0 + For i = 1 To const_size + If mlen <= Len(const_value.Item(i)) Then mlen = Len(const_value.Item(i)) + Next + For i = 1 To const_size + file.WriteLine " SQ" & api_cls & ".DefSQConst(engine, " & cls & "::" & const_value.Item(i) & ", " & Space(mlen - Len(const_value.Item(i))) & Chr(34) & const_value.Item(i) & Chr(34) & ");" + Next + If const_size <> 0 Then file.WriteLine "" + + ' Mapping of OTTD strings to errors + mlen = 0 + For i = 1 To enum_string_to_error_size + If mlen <= Len(enum_string_to_error_mapping_string.Item(i)) Then mlen = Len(enum_string_to_error_mapping_string.Item(i)) + Next + For i = 1 To enum_string_to_error_size + file.WriteLine " ScriptError::RegisterErrorMap(" & enum_string_to_error_mapping_string.Item(i) & ", " & Space(mlen - Len(enum_string_to_error_mapping_string.Item(i))) & cls & "::" & enum_string_to_error_mapping_error.Item(i) & ");" + Next + If enum_string_to_error_size <> 0 Then file.WriteLine "" + + ' Mapping of errors to human 'readable' strings. + mlen = 0 + For i = 1 To enum_error_to_string_size + If mlen <= Len(enum_error_to_string_mapping.Item(i)) Then mlen = Len(enum_error_to_string_mapping.Item(i)) + Next + For i = 1 To enum_error_to_string_size + file.WriteLine " ScriptError::RegisterErrorMapString(" & cls & "::" & enum_error_to_string_mapping.Item(i) & ", " & Space(mlen - Len(enum_error_to_string_mapping.Item(i))) & Chr(34) & enum_error_to_string_mapping.Item(i) & Chr(34) & ");" + Next + If enum_error_to_string_size <> 0 Then file.WriteLine "" + + ' Static methods + mlen = 0 + For i = 1 To static_method_size + If mlen <= Len(static_methods.Item(i)(0)) Then mlen = Len(static_methods.Item(i)(0)) + Next + For i = 1 To static_method_size + If static_methods.Item(i)(2) = "v" Then + spaces = mlen - Len(static_methods.Item(i)(0)) - 8 + If spaces < 0 Then spaces = 0 + file.WriteLine " SQ" & api_cls & ".DefSQAdvancedStaticMethod(engine, &" & cls & "::" & static_methods.Item(i)(0) & ", " & Space(spaces) & Chr(34) & static_methods.Item(i)(0) & Chr(34) & ");" + Else + file.WriteLine " SQ" & api_cls & ".DefSQStaticMethod(engine, &" & cls & "::" & static_methods.Item(i)(0) & ", " & Space(mlen - Len(static_methods.Item(i)(0))) & Chr(34) & static_methods.Item(i)(0) & Chr(34) & ", " & Space(mlen - Len(static_methods.Item(i)(0))) & static_methods.Item(i)(1) & ", " & Chr(34) & static_methods.Item(i)(2) & Chr(34) & ");" + End If + Next + If static_method_size <> 0 Then file.WriteLine "" + + ' Non-static methods + mlen = 0 + For i = 1 To method_size + If mlen <= Len(methods.Item(i)(0)) Then mlen = Len(methods.Item(i)(0)) + Next + For i = 1 To method_size + If methods.Item(i)(2) = "v" Then + spaces = mlen - Len(methods.Item(i)(0)) - 8 + If spaces < 0 Then spaces = 0 + file.WriteLine " SQ" & api_cls & ".DefSQAdvancedMethod(engine, &" & cls & "::" & methods.Item(i)(0) & ", " & Space(spaces) & Chr(34) & methods.Item(i)(0) & Chr(34) & ");" + Else + file.WriteLine " SQ" & api_cls & ".DefSQMethod(engine, &" & cls & "::" & methods.Item(i)(0) & ", " & Space(mlen - Len(methods.Item(i)(0))) & Chr(34) & methods.Item(i)(0) & Chr(34) & ", " & Space(mlen - Len(methods.Item(i)(0))) & methods.Item(i)(1) & ", " & Chr(34) & methods.Item(i)(2) & Chr(34) & ");" + End If + Next + If method_size <> 0 Then file.WriteLine "" + + file.WriteLine " SQ" & api_cls & ".PostRegister(engine);" + file.WriteLine "}" + + ResetReader + + Exit Sub + End If + + ' Skip non-public functions + If Not is_public Then Exit Sub + + ' Add enums + If in_enum Then + enum_value_size = enum_value_size + 1 + re.Pattern = "[, ]" + re.Global = True + enum_value.Item(enum_value_size) = re.Replace(split(line)(0), "") + + ' Check if this a special error enum + re.Pattern = ".*::ErrorMessages" + If re.Test(enums.Item(enum_size)) Then + ' syntax: + ' enum ErrorMessages { + ' ERR_SOME_ERROR, // [STR_ITEM1, STR_ITEM2, ...] + ' } + + ' Set the mappings + re.Pattern = "\[.*\]" + If re.Test(line) Then + Dim mappings + mappings = re.Execute(line)(0).Value + re.Pattern = "[\[ \]]" + mappings = re.Replace(mappings, "") + + mappings = Split(mappings, ",") + For i = LBound(mappings) To UBound(mappings) + enum_string_to_error_size = enum_string_to_error_size + 1 + enum_string_to_error_mapping_string.Item(enum_string_to_error_size) = mappings(i) + enum_string_to_error_mapping_error.Item(enum_string_to_error_size) = enum_value.Item(enum_value_size) + Next + + enum_error_to_string_size = enum_error_to_string_size + 1 + enum_error_to_string_mapping.Item(enum_error_to_string_size) = enum_value.Item(enum_value_size) + End If + End If + re.Global = False + Exit Sub + End If + + ' Add a const (non-enum) value + re.Pattern = "^[ ]*static const \w+ \w+ = -?\(?\w*\)?\w+;" + If re.Test(line) Then + const_size = const_size + 1 + const_value.Item(const_size) = Split(line)(3) + Exit Sub + End If + + ' Add a method to the list + re.Pattern = "^.*\(.*\).*$" + If re.Test(line) Then + Dim is_static, param_s, func, funcname, params, types + If cls_level <> 1 Then Exit Sub + re.Pattern = "~" + If re.Test(line) Then + If api_selected <> "" Then + WScript.Echo "Destructor for '" & cls & "' has @api. Tag ignored." + api_selected = "" + End If + Exit Sub + End If + + re.Pattern = "static" + is_static = re.Test(line) + re.Pattern = "\bvirtual\b" + line = re.Replace(line, "") + re.Pattern = "\bstatic\b" + line = re.Replace(line, "") + re.Pattern = "\bconst\b" + line = re.Replace(line, "") + re.Pattern = "{.*" + line = re.Replace(line, "") + param_s = line + re.Pattern = "\*" + line = re.Replace(line, "") + re.Pattern = "\(.*" + line = re.Replace(line, "") + re.Pattern = "^[ ]*" + line = re.Replace(line, "") + + re.Pattern = ".*\(" + param_s = re.Replace(param_s, "") + re.Pattern = "\).*" + param_s = re.Replace(param_s, "") + + func = Split(line) + If UBound(func) > 0 Then + funcname = func(1) + Else + funcname = "" + End If + If func(0) = cls And funcname = "" Then + If api_selected <> "" Then + WScript.Echo "Constructor for '" & cls & "' has @api. Tag ignored." + api_selected = "" + End If + cls_param(0) = param_s + If param_s = "" Then Exit Sub + ElseIf funcname = "" Then + Exit Sub + End If + + params = Split(param_s, ",") + If is_static Then + types = "." + Else + types = "x" + End If + For i = LBound(params) To UBound(params) + Do ' null loop for logic short-circuit + re.Pattern = "^[ ]*" + params(i) = re.Replace(params(i), "") + re.Pattern = "\*|&" + If re.Test(params(i)) Then + re.Pattern = "^char" + If re.test(params(i)) Then + ' Many types can be converted to string, so use '.', not 's'. (handled by our glue code) + types = types & "." + Exit Do + End If + re.Pattern = "^void" + If re.test(params(i)) Then + types = types & "p" + Exit Do + End If + re.Pattern = "^Array" + If re.test(params(i)) Then + types = types & "a" + Exit Do + End If + re.Pattern = "^struct Array" + If re.test(params(i)) Then + types = types & "a" + Exit Do + End If + re.Pattern = "^Text" + If re.test(params(i)) Then + types = types & "." + Exit Do + End If + types = types & "x" + Exit Do + End If + re.Pattern = "^bool" + If re.Test(params(i)) Then + types = types & "b" + Exit Do + End If + re.Pattern = "^HSQUIRRELVM" + If re.Test(params(i)) Then + types = "v" + Exit Do + End If + types = types & "i" + Loop While False ' end of null loop + Next + i = i + 1 + + ' Check if we want to publish this function + If api_selected = "" Then api_selected = cls_in_api + If api_selected = "false" Then + api_selected = "" + Exit Sub + End If + api_selected = "" + + If func(0) = cls And funcname = "" Then + cls_param(1) = i + cls_param(2) = types + Exit Sub + End If + If Left(funcname, 1) = "_" And types <> "v" Then Exit Sub + If is_static Then + static_method_size = static_method_size + 1 + static_methods.Item(static_method_size) = Array(funcname, i, types) + Exit Sub + End If + method_size = method_size + 1 + methods.Item(method_size) = Array(funcname, i, types) + Exit Sub + End If +End Sub + +Sub SquirrelExport(api, srcfilename, dstfilename) + Dim src, dst, line + Set src = FSO.OpenTextFile(srcfilename, 1) + Set dst = FSO.OpenTextFile(dstfilename, 2, True) + + enum_size = 0 + Set enums = CreateObject("Scripting.Dictionary") + enum_value_size = 0 + Set enum_value = CreateObject("Scripting.Dictionary") + enum_string_to_error_size = 0 + Set enum_string_to_error_mapping_string = CreateObject("Scripting.Dictionary") + Set enum_string_to_error_mapping_error = CreateObject("Scripting.Dictionary") + enum_error_to_string_size = 0 + Set enum_error_to_string_mapping = CreateObject("Scripting.Dictionary") + const_size = 0 + Set const_value = CreateObject("Scripting.Dictionary") + struct_size = 0 + Set structs = CreateObject("Scripting.Dictionary") + method_size = 0 + Set methods = CreateObject("Scripting.Dictionary") + static_method_size = 0 + Set static_methods = CreateObject("Scripting.Dictionary") + super_cls = "" + cls = "" + api_selected = "" + cls_in_api = "" + start_squirrel_define_on_next_line = False + has_fileheader = False + cls_level = 0 + apis = LCase(api) + If apis = "gs" Then apis = "game" + + While Not src.AtEndOfStream + line = src.ReadLine + SquirrelExportParse api, line, dst + Wend + + src.Close + dst.Close +End Sub + +Function SortDict(dict) + Set SortDict = CreateObject("Scripting.Dictionary") + While dict.Count <> 0 + Dim first, i + first = "" + For Each i in dict + If first = "" Or StrComp(first, i) = 1 Then first = i + Next + SortDict.Add first, first + dict.Remove(first) + Wend +End Function + +Sub ExportInstanceParse(apiuc, apilc, line, file) + Dim re, fname, f, files, r, regs + Set re = New RegExp + + re.Pattern = "\.hpp\.sq" + If re.Test(line) Then + re.Pattern = "template" + If re.Test(line) Then + file.WriteLine line + End If + Exit Sub + End If + + re.Pattern = "SQ" & apiuc & "Controller_Register" + If re.Test(line) Then + file.WriteLine line + Exit Sub + End If + + re.Pattern = "SQ" & apiuc & ".*_Register" + If re.Test(line) Then Exit Sub + + re.Pattern = "Note: this line is a marker in squirrel_export.sh. Do not change!" + If re.Test(line) Then + file.WriteLine line + Set files = CreateObject("Scripting.Dictionary") + For Each fname In FSO.GetFolder(".").Files + Do ' null loop for logic short-circuit + re.Pattern = ".*_(.*)\.hpp\.sq" + If Not re.Test(fname) Then Exit Do + Set f = FSO.OpenTextFile(fname, 1) + fname = fname.Name + re.Pattern = "^void SQ" & apiuc & ".*Register\(Squirrel \*engine\)$" + While Not f.AtEndOfStream + If re.Test(f.ReadLine) And Not files.Exists(fname) Then + files.Add fname, fname + End If + Wend + f.Close + Loop While False ' end of null loop + Next + Set files = SortDict(files) + For Each f in files + file.WriteLine "#include " & Chr(34) & "../script/api/" & apilc & "/" & f & Chr(34) + Next + Exit Sub + End If + + re.Pattern = "/\* Register all classes \*/" + If re.Test(line) Then + file.WriteLine line + Set regs = CreateObject("Scripting.Dictionary") + ' List needs to be registered with squirrel before all List subclasses + file.WriteLine " SQ" & apiuc & "List_Register(this->engine);" + For Each fname In FSO.GetFolder(".").Files + Do ' null loop for logic short-circuit + re.Pattern = ".*_(.*)\.hpp\.sq" + If Not re.Test(fname) Then Exit Do + Set f = FSO.OpenTextFile(fname, 1) + While Not f.AtEndOfStream + Do ' null loop for logic short-circuit + r = f.ReadLine + re.Pattern = "^void SQ" & apiuc & ".*Register\(Squirrel \*engine\)$" + If Not re.Test(r) Then Exit Do + re.Pattern = "SQ" & apiuc & "List_Register" + If re.Test(r) Then Exit Do + re.Pattern = "^.*void " + r = re.Replace(r, "") + re.Pattern = "Squirrel \*" + r = re.Replace(r, "this->") + re.Pattern = "$" + r = re.Replace(r, ";") + re.Pattern = "_Register" + r = re.Replace(r, "0000Register") + If Not regs.Exists(r) Then regs.Add r, r + Loop While False ' end of null loop + Wend + f.Close + Loop While False ' end of null loop + Next + Set regs = SortDict(regs) + re.Pattern = "0000Register" + For Each r in regs.Items + r = re.Replace(r, "_Register") + If r <> "SQ" & apiuc & "Controller_Register(this->engine);" Then file.WriteLine " " & r + Next + Exit Sub + End If + + file.WriteLine line +End Sub + +Sub ExportInstance(apiuc, apilc, srcfilename, dstfilename) + Dim src, dst, line + Set src = FSO.OpenTextFile(srcfilename, 1) + Set dst = FSO.OpenTextFile(dstfilename, 2, True) + + While Not src.AtEndOfStream + line = src.ReadLine + ExportInstanceParse apiuc, apilc, line, dst + Wend + + src.Close + dst.Close +End Sub + +' Recursive entry point +Sub Main + Dim WSH, scriptdir, apilc, re, api, apiuc, f, bf + Set WSH = CreateObject("WScript.Shell") + Set re = New RegExp + + ' This must be called from within a src/???/api directory. + scriptdir = FSO.GetParentFolderName(WScript.ScriptFullName) + apilc = WSH.CurrentDirectory + re.Pattern = "\\api" + apilc = re.Replace(apilc, "") + re.Pattern = ".*\\" + apilc = re.Replace(apilc, "") + + ' Check if we are in the root directory of the API, as then we generate all APIs + If apilc = "script" Then + For Each api In FSO.GetFolder(".").SubFolders + WScript.Echo "Generating for API '" & api.Name & "' ..." + WSH.CurrentDirectory = api + Main + Next + WScript.Quit 0 + End If + + Select Case apilc + Case "template" apiuc = "Template" + Case "ai" apiuc = "AI" + Case "game" apiuc = "GS" + Case Else + WScript.Echo "Unknown API type." + Exit Sub + End Select + + For Each f in FSO.GetFolder("..").Files + Do ' null loop for logic short-circuit + re.Pattern = ".*\.hpp" + If Not re.Test(f) Then Exit Do + ' ScriptController has custom code, and should not be generated + If f.Name = "script_controller.hpp" Then Exit Do + re.Pattern = "script_" + bf = re.Replace(f.name, apilc & "_") + SquirrelExport apiuc, f, bf & ".tmp" + If IsEmptyFile(bf & ".tmp") Then + If FSO.FileExists(bf & ".sq") Then + WScript.Echo "Deleted: " & bf & ".sq" + FSO.DeleteFile bf & ".sq" + End If + FSO.DeleteFile bf & ".tmp" + ElseIf Not FSO.FileExists(bf & ".sq") Or Not CompareFiles(bf & ".sq", bf & ".tmp") Then + If FSO.FileExists(bf & ".sq") Then FSO.DeleteFile bf & ".sq" + FSO.MoveFile bf & ".tmp", bf & ".sq" + WScript.Echo "Updated: " & bf & ".sq" + Else + FSO.DeleteFile bf & ".tmp" + End If + Loop While False ' end of null loop + Next + + ' Remove .hpp.sq if .hpp doesn't exist anymore + For Each f in FSO.GetFolder(".").Files + Do ' null loop for logic short-circuit + re.Pattern = ".*\.hpp\.sq" + If Not re.Test(f) Then Exit Do + f = f.Name + re.Pattern = "\.hpp\.sq$" + f = re.Replace(f, ".hpp") + re.Pattern = apilc & "_" + f = re.Replace(f, "script_") + If Not FSO.FileExists("..\" & f) Then + WScript.Echo "Deleted: " & f & ".sq" + 'FSO.DeleteFile f & ".sq" + End If + Loop While False ' end of null loop + Next + + If apilc = "template" Then Exit Sub + + ' Add stuff to ${apilc}_instance.cpp + f = "..\..\..\" & apilc & "\" & apilc & "_instance.cpp" + ExportInstance apiuc, apilc, f, f & ".tmp" + If Not FSO.FileExists(f) Or Not CompareFiles(f, f & ".tmp") Then + If FSO.FileExists(f) Then FSO.DeleteFile f + FSO.MoveFile f & ".tmp", f + WScript.Echo "Updated: " & f + Else + FSO.DeleteFile f & ".tmp" + End If +End Sub + +Main diff --git a/src/ship.h b/src/ship.h index 13983614b9..04a7120bb4 100644 --- a/src/ship.h +++ b/src/ship.h @@ -50,6 +50,8 @@ struct Ship FINAL : public SpecializedVehicle { void UpdateCache(); }; +static const uint SHIP_MAX_ORDER_DISTANCE = 130; + /** * Iterate over all ships. * @param var The variable used for iteration. diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index 13b2983aa2..807502c5d6 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -320,6 +320,14 @@ void Ship::UpdateDeltaXY() this->z_extent = 6; } +/** + * Test-procedure for HasVehicleOnPos to check for a ship. + */ +static Vehicle *EnsureNoVisibleShipProc(Vehicle *v, void *data) +{ + return v->type == VEH_SHIP && (v->vehstatus & VS_HIDDEN) == 0 ? v : NULL; +} + static bool CheckShipLeaveDepot(Ship *v) { if (!v->IsChainInDepot()) return false; @@ -338,6 +346,13 @@ static bool CheckShipLeaveDepot(Ship *v) return true; } + /* Don't leave depot if no destination set */ + if (v->dest_tile == 0) return true; + + /* Don't leave depot if another vehicle is already entering/leaving */ + /* This helps avoid CPU load if many ships are set to start at the same time */ + if (HasVehicleOnPos(v->tile, NULL, &EnsureNoVisibleShipProc)) return true; + TileIndex tile = v->tile; Axis axis = GetShipDepotAxis(tile); @@ -463,11 +478,27 @@ static Track ChooseShipTrack(Ship *v, TileIndex tile, DiagDirection enterdir, Tr bool path_found = true; Track track; - switch (_settings_game.pf.pathfinder_for_ships) { - case VPF_OPF: track = OPFShipChooseTrack(v, tile, enterdir, tracks, path_found); break; - case VPF_NPF: track = NPFShipChooseTrack(v, tile, enterdir, tracks, path_found); break; - case VPF_YAPF: track = YapfShipChooseTrack(v, tile, enterdir, tracks, path_found); break; - default: NOT_REACHED(); + + if (v->dest_tile == 0 || DistanceManhattan(tile, v->dest_tile) > SHIP_MAX_ORDER_DISTANCE + 5) { + /* No destination or destination too far, don't invoke pathfinder. */ + track = TrackBitsToTrack(v->state); + if (track != TRACK_X && track != TRACK_Y) track = TrackToOppositeTrack(track); + if (!HasBit(tracks, track)) { + /* Can't continue in same direction so pick first available track. */ + if (_settings_game.pf.forbid_90_deg) { + tracks &= ~TrackCrossesTracks(TrackdirToTrack(v->GetVehicleTrackdir())); + if (tracks == TRACK_BIT_NONE) return INVALID_TRACK; + } + track = FindFirstTrack(tracks); + } + path_found = false; + } else { + switch (_settings_game.pf.pathfinder_for_ships) { + case VPF_OPF: track = OPFShipChooseTrack(v, tile, enterdir, tracks, path_found); break; + case VPF_NPF: track = NPFShipChooseTrack(v, tile, enterdir, tracks, path_found); break; + case VPF_YAPF: track = YapfShipChooseTrack(v, tile, enterdir, tracks, path_found); break; + default: NOT_REACHED(); + } } v->HandlePathfindingResult(path_found);