From 34c438d7ad74e134c842c5b1ee6595cf38c0fbce Mon Sep 17 00:00:00 2001 From: glx Date: Tue, 8 Jan 2019 05:19:17 +0100 Subject: [PATCH 01/13] Fix: keep line endings when running squirrel_export.sh on windows --- src/script/api/squirrel_export.awk | 148 +++++++++++++++-------------- 1 file changed, 75 insertions(+), 73 deletions(-) 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 != "") { From 2cf9405aa2abfbb97dae93cf6587d5fba21ad958 Mon Sep 17 00:00:00 2001 From: glx Date: Tue, 8 Jan 2019 16:38:13 +0100 Subject: [PATCH 02/13] Fix: remove manual single file generation in squirrel_export.sh as it's broken --- src/script/api/squirrel_export.sh | 56 ++++++++++--------------------- 1 file changed, 18 insertions(+), 38 deletions(-) diff --git a/src/script/api/squirrel_export.sh b/src/script/api/squirrel_export.sh index 92bd434b93..1070fb1aed 100755 --- a/src/script/api/squirrel_export.sh +++ b/src/script/api/squirrel_export.sh @@ -43,50 +43,30 @@ 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" + svn del --force ${bf}.sq > /dev/null 2>&1 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" + 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 $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 From 8e5a8d3ec3ec19e25f040b0b85b8f5764a735db1 Mon Sep 17 00:00:00 2001 From: glx Date: Tue, 8 Jan 2019 16:40:38 +0100 Subject: [PATCH 03/13] Cleanup: remove svn references in squirrel_export.sh --- src/script/api/squirrel_export.sh | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/script/api/squirrel_export.sh b/src/script/api/squirrel_export.sh index 1070fb1aed..54e595b9bc 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 @@ -54,15 +54,12 @@ for f in `ls ../*.hpp`; do 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 + rm -f ${bf}.sq 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 fi @@ -73,7 +70,7 @@ 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 From 3f28e0cf53dc0c3de53a47874465be140f949949 Mon Sep 17 00:00:00 2001 From: glx Date: Wed, 9 Jan 2019 14:52:13 +0100 Subject: [PATCH 04/13] Add: squirrel_export.vbs for users unable to run bash/gawk scripts --- src/script/api/squirrel_export.vbs | 946 +++++++++++++++++++++++++++++ 1 file changed, 946 insertions(+) create mode 100644 src/script/api/squirrel_export.vbs 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 From 9f0ad7e2699a84dd47a0bb4a469b2b166d260f53 Mon Sep 17 00:00:00 2001 From: glx Date: Sun, 13 Jan 2019 19:12:33 +0100 Subject: [PATCH 05/13] Fix: BSD find used by OSX requires explicit path --- src/script/api/squirrel_export.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/script/api/squirrel_export.sh b/src/script/api/squirrel_export.sh index 54e595b9bc..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-`; do + for api in `find . -type d | cut -b3-`; do if [ -z "$api" ]; then continue; fi echo "Generating for API '$api' ..." cd $api From 29b6b74ee19e6df4ff71b592f27ccbfeb0f9c2f3 Mon Sep 17 00:00:00 2001 From: translators Date: Mon, 14 Jan 2019 19:45:41 +0100 Subject: [PATCH 06/13] Update: Translations from eints french: 4 changes by glx finnish: 2 changes by ln --- src/lang/finnish.txt | 2 ++ src/lang/french.txt | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index 0450afa0b3..700a58dabd 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 cc5b331ea0..bb54e6a86e 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 @@ -2381,9 +2382,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 From 6a38a3f5df177cdf85bd64b1b873f524d5b0629c Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 18 May 2018 09:04:39 +0100 Subject: [PATCH 07/13] Change: Don't leave ship depot with no orders. --- src/ship_cmd.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index e606afc0ce..16b93e48b3 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -330,6 +330,9 @@ static bool CheckShipLeaveDepot(Ship *v) return true; } + /* Don't leave depot if no destination set */ + if (v->dest_tile == 0) return true; + TileIndex tile = v->tile; Axis axis = GetShipDepotAxis(tile); From ebddd596c7138d629ec0259d2397c1039401ada7 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 18 May 2018 09:05:24 +0100 Subject: [PATCH 08/13] Change: Don't pathfind with no destination or if destination is known to be too far. --- src/ship_cmd.cpp | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index 16b93e48b3..0ea400b954 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -446,11 +446,38 @@ 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) > 130) { + /* No destination or destination too far, don't invoke pathfinder. */ + static const TrackBits direction_to_trackbits[DIR_END] = { + TRACK_BIT_LEFT | TRACK_BIT_RIGHT, // DIR_N + TRACK_BIT_X, // DIR_NE + TRACK_BIT_UPPER | TRACK_BIT_LOWER, // DIR_E + TRACK_BIT_Y, // DIR_SE + TRACK_BIT_LEFT | TRACK_BIT_RIGHT, // DIR_S + TRACK_BIT_X, // DIR_SW + TRACK_BIT_UPPER | TRACK_BIT_LOWER, // DIR_W + TRACK_BIT_Y, // DIR_NW + }; + + TrackBits next_tracks = direction_to_trackbits[v->direction] & tracks; + if (next_tracks != TRACK_BIT_NONE) { + /* Continue in same direction when possible. */ + track = (Track)FindFirstBit(next_tracks); + } else { + /* Pick a random track. */ + do { + track = (Track)RandomRange(TRACK_END); + } while ((TrackToTrackBits(track) & tracks) == TRACK_BIT_NONE); + } + 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); From b98887c4a014d5bc193b0c1089b3ac0334187775 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 18 May 2018 18:02:53 +0100 Subject: [PATCH 09/13] Change: Allow only one ship to leave depot at a time. --- src/ship_cmd.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index 0ea400b954..080015eacb 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -319,6 +319,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; @@ -333,6 +341,10 @@ static bool CheckShipLeaveDepot(Ship *v) /* 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); From 7af53d7588a97bc4b02dbfa456a0e2a9ab598864 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sun, 20 May 2018 12:01:17 +0100 Subject: [PATCH 10/13] Codechange: Use const instead of magic number for ship order distance. Allow slightly further distance when following orders. --- src/order_cmd.cpp | 3 ++- src/ship.h | 2 ++ src/ship_cmd.cpp | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index ba8a1a060d..093e4b9b50 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -23,6 +23,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" @@ -929,7 +930,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/ship.h b/src/ship.h index 0f396a237d..7fea5fc1d1 100644 --- a/src/ship.h +++ b/src/ship.h @@ -48,6 +48,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 080015eacb..79560be041 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -459,7 +459,7 @@ static Track ChooseShipTrack(Ship *v, TileIndex tile, DiagDirection enterdir, Tr bool path_found = true; Track track; - if (v->dest_tile == 0 || DistanceManhattan(tile, v->dest_tile) > 130) { + 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. */ static const TrackBits direction_to_trackbits[DIR_END] = { TRACK_BIT_LEFT | TRACK_BIT_RIGHT, // DIR_N From 8b6420441814e95ca32ffd4c601e3646f840c58c Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 23 May 2018 17:34:39 +0100 Subject: [PATCH 11/13] Codechange: Replace trackbit lookup table with existing functions. --- src/ship_cmd.cpp | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index 79560be041..88e2392e01 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -461,23 +461,10 @@ static Track ChooseShipTrack(Ship *v, TileIndex tile, DiagDirection enterdir, Tr 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. */ - static const TrackBits direction_to_trackbits[DIR_END] = { - TRACK_BIT_LEFT | TRACK_BIT_RIGHT, // DIR_N - TRACK_BIT_X, // DIR_NE - TRACK_BIT_UPPER | TRACK_BIT_LOWER, // DIR_E - TRACK_BIT_Y, // DIR_SE - TRACK_BIT_LEFT | TRACK_BIT_RIGHT, // DIR_S - TRACK_BIT_X, // DIR_SW - TRACK_BIT_UPPER | TRACK_BIT_LOWER, // DIR_W - TRACK_BIT_Y, // DIR_NW - }; - - TrackBits next_tracks = direction_to_trackbits[v->direction] & tracks; - if (next_tracks != TRACK_BIT_NONE) { - /* Continue in same direction when possible. */ - track = (Track)FindFirstBit(next_tracks); - } else { - /* Pick a random track. */ + 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 a random available track. */ do { track = (Track)RandomRange(TRACK_END); } while ((TrackToTrackBits(track) & tracks) == TRACK_BIT_NONE); From 7284b593c71dc54a055077d7f12dac91fca34324 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Mon, 28 May 2018 08:37:43 +0100 Subject: [PATCH 12/13] Change: When ship is lost, pick first available track instead of a random track. --- src/ship_cmd.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index 88e2392e01..1594c2bf42 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -464,10 +464,8 @@ static Track ChooseShipTrack(Ship *v, TileIndex tile, DiagDirection enterdir, Tr 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 a random available track. */ - do { - track = (Track)RandomRange(TRACK_END); - } while ((TrackToTrackBits(track) & tracks) == TRACK_BIT_NONE); + /* Can't continue in same direction so pick first available track. */ + track = FindFirstTrack(tracks); } path_found = false; } else { From 6b0a467a50c706546129044a5bd6013bf6d310a1 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sun, 13 Jan 2019 23:29:29 +0000 Subject: [PATCH 13/13] Change: Obey forbid_90_deg_turns when choosing available track with no destination. --- src/ship_cmd.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index 1594c2bf42..ab1f59f11d 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -465,6 +465,10 @@ static Track ChooseShipTrack(Ship *v, TileIndex tile, DiagDirection enterdir, Tr 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;