diff --git a/README b/README index 6dd6d153..6a277275 100644 --- a/README +++ b/README @@ -1,8 +1,12 @@ +PLEASE UPDATE YOUR LINKS +https://sourceforge.net/projects/skfans + Seven Kingdoms: Ancient Adversaries ----------------------------------- Release version 2.15.6 Project website: www.7kfans.com +Downloads and source repo: sourceforge.net/projects/skfans This is a GPL release of the Seven Kingdoms: Ancient Adversaries thanks to Enlight Software which granted the ability to license the game under a @@ -13,6 +17,39 @@ of the game. Summary of changes from 2.15.5 to 2.15.6 --------- +* Fixed bugs related to rebelling +* Improved AI on handling rebellions +* Fixed several crash bugs +* Fixed small graphic update bugs +* Fixed bug when assigning to ship +* Fixed AI declare war bug +* Fixed AI give tribute bug +* Greatly improved AI sea based missions +* Improved AI on training and recruiting +* Cleaned up some deinit code +* Improved handling of town migration with workers +* Improved AI to be move aggressive in attack missions +* Improved validation of attack actions +* Added display of the land mass size in the F10 menu +* Enabled town peasant migration +* Created button for markets to control stocking type -- thanks MicroVirus and + sraboy +* Added Phoenix vision on fryhtan lairs +* Improved AI at building harbors +* Fixed bugs related to AI surrenders +* Improved locale code +* Made English the default language on Windows +* Increased the max number of raw resource sites to 10 +* Fixed bug on trade ship docking and exiting +* Reduced penalty on trade unit destruction +* Improved distance calculating so placing buildings and towns on any side is + treated the same +* Fixed some path finding issues +* Enabled the ability for AI to scout the map +* Fixed screen edge mouse handling bug +* Fixed exploit when spying on an enemy nation report +* Improved AI handling on granting money to towns and recruiting +* Increased the speed of speed level 9 System Requirements @@ -41,7 +78,7 @@ configure their system -- you are expected to know how to use your tools. Required dependencies * GCC 4.6+ C++11 compliant compiler -* SDL 2.0.8 +* SDL 2.24.0+ * enet 1.3.xx Reliable UDP networking library * OpenAL-soft or equivalent driver diff --git a/configure.ac b/configure.ac index f99f001f..960b68cd 100644 --- a/configure.ac +++ b/configure.ac @@ -79,8 +79,24 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE( ) CXXFLAGS="$save_CXXFLAGS" +AC_MSG_CHECKING(checking for register keyword) +AC_COMPILE_IFELSE([AC_LANG_SOURCE( +int main() +{ + register int x; + return 0; +} + )],[ + AC_MSG_RESULT(yes) + have_register=yes + ],[ + AC_MSG_RESULT(no) + ] +) + # Checks for header files. dnl AC_CHECK_HEADERS([]) +gt_LC_MESSAGES # Checks for typedefs, structures, and compiler characteristics. AC_CANONICAL_HOST @@ -95,7 +111,7 @@ AC_TYPE_UINT64_T AC_TYPE_UINT8_T # Checks for library functions. -AC_CHECK_FUNCS([_NSGetExecutablePath]) +AC_CHECK_FUNCS_ONCE([_NSGetExecutablePath setenv]) AX_STRING_STRCASECMP if test x"$ac_cv_string_strcasecmp" = "xno" ; then @@ -365,6 +381,16 @@ AS_IF([test "$enable_enet" = yes], [ ]) ]) +AS_IF([test "$have_register" = yes], [ + AC_DEFINE([REGISTER], [register], [ + Define to the register keyword your compiler allows + ]) +],[ + AC_DEFINE([REGISTER], [], [ + Define to the register keyword your compiler allows + ]) +]) + AC_SUBST([GLOBAL_LDFLAGS]) AC_SUBST([GLOBAL_CFLAGS]) diff --git a/include/ConfigAdv.h b/include/ConfigAdv.h index ea93e58d..cd78090c 100644 --- a/include/ConfigAdv.h +++ b/include/ConfigAdv.h @@ -49,12 +49,17 @@ class ConfigAdv char firm_migrate_stricter_rules; // bug fix settings + char fix_path_blocked_by_team; char fix_recruit_dec_loyalty; + char fix_sea_travel_final_move; char fix_town_unjob_worker; // locale settings char locale[LOCALE_LEN+1]; + // mine settings + char mine_unlimited_reserve; + // monster settings char monster_alternate_attack_curve; int monster_attack_divisor; @@ -85,6 +90,7 @@ class ConfigAdv char unit_ai_team_help; char unit_finish_attack_move; char unit_loyalty_require_local_leader; + char unit_allow_path_power_mode; char unit_spy_fixed_target_loyalty; char unit_target_move_range_cycle; diff --git a/include/GAMEDEF.h b/include/GAMEDEF.h index 79cdd181..bb1278bb 100644 --- a/include/GAMEDEF.h +++ b/include/GAMEDEF.h @@ -127,6 +127,9 @@ enum { COMMAND_PLAYER=0, COMMAND_REMOTE=1, COMMAND_AI, COMMAND_AUTO }; #define SPY_KILLED_REPUTATION_DECREASE 3 +#define MIN_RAW_RES_SITE 1 +#define MAX_RAW_RES_SITE 10 + //-----------------------------------------------// #endif diff --git a/include/LocaleRes.h b/include/LocaleRes.h index 6f659778..ebedb45b 100644 --- a/include/LocaleRes.h +++ b/include/LocaleRes.h @@ -64,11 +64,13 @@ class LocaleRes void init(); void deinit(); - void load(); + void load(const char *locale); #ifdef ENABLE_NLS const char *conv_str(iconv_t cd, const char *s); #endif + const char *get_locale_dir(); + const char *get_messages_locale(); }; extern LocaleRes locale_res; diff --git a/include/OGAME.h b/include/OGAME.h index 837bba51..258b9ec0 100644 --- a/include/OGAME.h +++ b/include/OGAME.h @@ -39,7 +39,8 @@ enum { GAME_PREGAME=1, // ####### begin Gilbert 2/9 ######// GAME_CREDITS, // ####### end Gilbert 2/9 ######// - GAME_DEMO + GAME_DEMO, + GAME_POSTGAME }; //--------- Define struct ColorRemapMethod ----------// diff --git a/include/OMISC.h b/include/OMISC.h index 3f856e33..ecdcc266 100644 --- a/include/OMISC.h +++ b/include/OMISC.h @@ -96,6 +96,7 @@ class Misc int sqrt(long); int diagonal_distance(int,int,int,int); int points_distance(int,int,int,int); + int rects_distance(int ax1, int ay1, int ax2, int ay2, int bx1, int by1, int bx2, int by2, int edgeA=0, int edgeB=0); float round(float,int,int=0); float round_dec(float); diff --git a/include/ONATIONB.h b/include/ONATIONB.h index 5f437dd8..8555112a 100644 --- a/include/ONATIONB.h +++ b/include/ONATIONB.h @@ -416,8 +416,8 @@ class NationBase int has_people(); // whether the nation has any people (but not counting the king). If no, then the nation is going to end. void being_attacked(int attackNationRecno); - void civilian_killed(int civilianRaceId, int penaltyLevel); - void change_all_people_loyalty(int loyaltyChange, int raceId=0); + void civilian_killed(int civilianRaceId, int isAttacker, int penaltyType); + void change_all_people_loyalty(float loyaltyChange, int raceId=0); void form_friendly_treaty(int nationRecno); void form_alliance_treaty(int nationRecno); diff --git a/include/OSPY.h b/include/OSPY.h index a6325208..cf59effe 100644 --- a/include/OSPY.h +++ b/include/OSPY.h @@ -95,6 +95,7 @@ class Spy int can_change_cloaked_nation(int newNationRecno); int capture_firm(); + int can_capture_firm(); void reward(int remoteAction); void set_exposed(int remoteAction); diff --git a/include/OU_GOD.h b/include/OU_GOD.h index 7a87659c..310c4944 100644 --- a/include/OU_GOD.h +++ b/include/OU_GOD.h @@ -63,7 +63,7 @@ class UnitGod : public Unit virtual void init_crc(UnitGodCrc *c); private: - void consume_power_pray_points(); + int consume_power_pray_points(); void cast_on_loc(int castXLoc, int castYLoc); void cast_on_unit(int unitRecno, int divider); diff --git a/include/OWORLD.h b/include/OWORLD.h index f9f20c29..c94a38a1 100644 --- a/include/OWORLD.h +++ b/include/OWORLD.h @@ -142,6 +142,7 @@ class World int spaceLocWidth, int spaceLocHeight, int maxTries, int regionId=0, int buildSite=0, char teraMask=1); int is_adjacent_region( int x, int y, int regionId ); + int is_harbor_region(int xLoc, int yLoc, int landRegionId, int seaRegionId); void draw_link_line(int srcFirmId, int srcTownRecno, int srcXLoc1, int srcYLoc1, int srcXLoc2, int srcYLoc2, int giveEffectiveDis=0); diff --git a/include/version.h b/include/version.h index 222fb451..ce2fdd12 100644 --- a/include/version.h +++ b/include/version.h @@ -32,6 +32,6 @@ #define SKVERMED 15 #define SKVERMIN 6 -#define DEV_VERSION +//#define DEV_VERSION #endif diff --git a/m4/lcmessage.m4 b/m4/lcmessage.m4 new file mode 100644 index 00000000..2e56de66 --- /dev/null +++ b/m4/lcmessage.m4 @@ -0,0 +1,35 @@ +# lcmessage.m4 serial 8 +dnl Copyright (C) 1995-2002, 2004-2005, 2008-2014, 2016, 2019-2023 Free +dnl Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can be used in projects which are not available under +dnl the GNU General Public License or the GNU Lesser General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Lesser General Public License, and the rest of the GNU +dnl gettext package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1995. + +# Check whether LC_MESSAGES is available in . + +AC_DEFUN([gt_LC_MESSAGES], +[ + AC_CACHE_CHECK([for LC_MESSAGES], [gt_cv_val_LC_MESSAGES], + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[#include ]], + [[return LC_MESSAGES]])], + [gt_cv_val_LC_MESSAGES=yes], + [gt_cv_val_LC_MESSAGES=no])]) + if test $gt_cv_val_LC_MESSAGES = yes; then + AC_DEFINE([HAVE_LC_MESSAGES], [1], + [Define if your file defines LC_MESSAGES.]) + fi +]) diff --git a/packaging/windows/install.nsi b/packaging/windows/install.nsi index 08547682..33353c6a 100644 --- a/packaging/windows/install.nsi +++ b/packaging/windows/install.nsi @@ -55,8 +55,8 @@ SetCompressor /SOLID lzma ;-------------------------------- ;Pages - !insertmacro MUI_PAGE_LICENSE "COPYING" - !insertmacro MUI_PAGE_LICENSE "COPYING-Music.txt" + ;!insertmacro MUI_PAGE_LICENSE "COPYING" + ;!insertmacro MUI_PAGE_LICENSE "COPYING-Music.txt" !insertmacro MUI_PAGE_COMPONENTS !insertmacro MUI_PAGE_DIRECTORY diff --git a/po/es.po b/po/es.po index 3bcea22f..8d8ba42c 100644 --- a/po/es.po +++ b/po/es.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-05-14 08:14-0500\n" -"PO-Revision-Date: 2021-10-15 13:54+0200\n" -"Last-Translator: Lenny Andreu\n" +"PO-Revision-Date: 2023-05-23 20:54+0200\n" +"Last-Translator: Jorge Maldonado Ventura\n" "Language-Team: \n" "Language: es\n" "MIME-Version: 1.0\n" @@ -58,128 +58,128 @@ msgstr "Cancelar" #: src/ODATE.cpp:231 src/ODATE.cpp:235 #, c-format msgid "%s %d, %d" -msgstr "%2$d de %1$s del %3$d" +msgstr "%2$d de %1$s, %3$d" #: src/ODATE.cpp:254 msgctxt "Month|Full" msgid "January" -msgstr "Enero" +msgstr "enero" #: src/ODATE.cpp:256 msgctxt "Month|Full" msgid "February" -msgstr "Febrero" +msgstr "febrero" #: src/ODATE.cpp:258 msgctxt "Month|Full" msgid "March" -msgstr "Marzo" +msgstr "marzo" #: src/ODATE.cpp:260 msgctxt "Month|Full" msgid "April" -msgstr "Abril" +msgstr "abril" #: src/ODATE.cpp:262 msgctxt "Month|Full" msgid "May" -msgstr "Mayo" +msgstr "mayo" #: src/ODATE.cpp:264 msgctxt "Month|Full" msgid "June" -msgstr "Junio" +msgstr "junio" #: src/ODATE.cpp:266 msgctxt "Month|Full" msgid "July" -msgstr "Julio" +msgstr "julio" #: src/ODATE.cpp:268 msgctxt "Month|Full" msgid "August" -msgstr "Agosto" +msgstr "agosto" #: src/ODATE.cpp:270 msgctxt "Month|Full" msgid "September" -msgstr "Septiembre" +msgstr "septiembre" #: src/ODATE.cpp:272 msgctxt "Month|Full" msgid "October" -msgstr "Octubre" +msgstr "octubre" #: src/ODATE.cpp:274 msgctxt "Month|Full" msgid "November" -msgstr "Noviembre" +msgstr "noviembre" #: src/ODATE.cpp:276 msgctxt "Month|Full" msgid "December" -msgstr "Diciembre" +msgstr "diciembre" #. TRANSLATORS: An abbreviated month. If not used in your language, spell full month. #: src/ODATE.cpp:295 msgctxt "Month|Short" msgid "Jan" -msgstr "Ene" +msgstr "ene" #: src/ODATE.cpp:297 msgctxt "Month|Short" msgid "Feb" -msgstr "Feb" +msgstr "feb" #: src/ODATE.cpp:299 msgctxt "Month|Short" msgid "Mar" -msgstr "Mar" +msgstr "mar" #: src/ODATE.cpp:301 msgctxt "Month|Short" msgid "Apr" -msgstr "Abr" +msgstr "abr" #: src/ODATE.cpp:303 msgctxt "Month|Short" msgid "May" -msgstr "Mayo" +msgstr "mayo" #: src/ODATE.cpp:305 msgctxt "Month|Short" msgid "Jun" -msgstr "Jun" +msgstr "jun" #: src/ODATE.cpp:307 msgctxt "Month|Short" msgid "Jul" -msgstr "Jul" +msgstr "jul" #: src/ODATE.cpp:309 msgctxt "Month|Short" msgid "Aug" -msgstr "Ago" +msgstr "ago" #: src/ODATE.cpp:311 msgctxt "Month|Short" msgid "Sep" -msgstr "Sep" +msgstr "sep" #: src/ODATE.cpp:313 msgctxt "Month|Short" msgid "Oct" -msgstr "Oct" +msgstr "oct" #: src/ODATE.cpp:315 msgctxt "Month|Short" msgid "Nov" -msgstr "Nov" +msgstr "nov" #: src/ODATE.cpp:317 msgctxt "Month|Short" msgid "Dec" -msgstr "Dic" +msgstr "dic" #. TRANSLATORS: #. This is the name of the firm when there are multiple linked firms to a town. @@ -226,7 +226,7 @@ msgstr "Combate" #: src/OFIRMIF.cpp:696 src/OFIRMIF.cpp:744 src/OR_MIL.cpp:102 #: src/OR_TECH.cpp:145 src/OR_TRADE.cpp:147 src/OU_MARIF.cpp:524 msgid "Hit Points" -msgstr "Puntos de impacto" +msgstr "Puntos impacto" #: src/OFIRMIF2.cpp:94 src/OTOWNIF.cpp:1412 msgid "Spy Skill" @@ -900,7 +900,7 @@ msgstr "Reputación" #: src/OGAMEND.cpp:481 src/OR_RANK.cpp:92 msgid "Fryhtan Battling" -msgstr "Batallando Frythan" +msgstr "Matando Frythan" #: src/OGAMEND.cpp:528 src/OR_RANK.cpp:137 msgid "Population Score" @@ -3352,7 +3352,7 @@ msgstr "Permitir atacar" #: src/OR_NAT.cpp:172 src/OR_NAT.cpp:604 msgid "Trade Treaty" -msgstr "Tratado de Comercio" +msgstr "Tratado comerc." #: src/OR_NAT.cpp:174 msgid "Trade Amount" @@ -3483,31 +3483,31 @@ msgstr "Tiempo total de juego: %s" #. TRANSLATORS: Ordinal number for ranking players #: src/OR_RANK.cpp:472 msgid "1st" -msgstr "1ro" +msgstr "1.º" #: src/OR_RANK.cpp:473 msgid "2nd" -msgstr "2do" +msgstr "2.º" #: src/OR_RANK.cpp:474 msgid "3rd" -msgstr "3ro" +msgstr "3.º" #: src/OR_RANK.cpp:475 -msgid "4th" -msgstr "4to" +msgid "4º" +msgstr "4.º" #: src/OR_RANK.cpp:476 msgid "5th" -msgstr "5to" +msgstr "5.º" #: src/OR_RANK.cpp:477 msgid "6th" -msgstr "6to" +msgstr "6.º" #: src/OR_RANK.cpp:478 msgid "7th" -msgstr "7mo" +msgstr "7.º" #: src/OR_SPY.cpp:73 msgid "Spy Name" @@ -3571,7 +3571,7 @@ msgstr "Pobladores" #: src/OR_TOWN.cpp:86 src/OTOWNIF.cpp:295 msgid "Peasants" -msgstr "Campesinos" +msgstr "Campes." #: src/OR_TOWN.cpp:88 msgid "Races" @@ -3583,11 +3583,11 @@ msgstr "Estructura" #: src/OR_TOWN.cpp:113 msgid "Unit Cost" -msgstr "Costo unitario" +msgstr "Costo unidad" #: src/OR_TOWN.cpp:117 msgid "No. of Structures" -msgstr "Nro. de estructuras" +msgstr "N. estructuras" #: src/OR_TOWN.cpp:202 #, c-format @@ -5278,7 +5278,7 @@ msgstr "Resistencia" #: src/OTOWNIF.cpp:322 msgid "Avg" -msgstr "Promedio" +msgstr "Prom." #: src/OTOWNIF.cpp:356 msgid "Controlled by Rebels" diff --git a/src/AM.cpp b/src/AM.cpp index c520e0e6..a201230c 100644 --- a/src/AM.cpp +++ b/src/AM.cpp @@ -312,7 +312,7 @@ int main(int argc, char **argv) } config_adv.init(); if( config_adv.locale[0] ) - locale_res.load(); + locale_res.load(config_adv.locale); //----- read command line arguments -----// diff --git a/src/ConfigAdv.cpp b/src/ConfigAdv.cpp index 13039449..80da73cf 100644 --- a/src/ConfigAdv.cpp +++ b/src/ConfigAdv.cpp @@ -230,11 +230,15 @@ void ConfigAdv::reset() firm_mobilize_civilian_aggressive = 0; firm_migrate_stricter_rules = 1; + fix_path_blocked_by_team = 1; fix_recruit_dec_loyalty = 1; + fix_sea_travel_final_move = 1; fix_town_unjob_worker = 1; locale[0] = 0; + mine_unlimited_reserve = 0; + monster_alternate_attack_curve = 0; monster_attack_divisor = 4; @@ -257,6 +261,7 @@ void ConfigAdv::reset() town_loyalty_qol = 1; unit_ai_team_help = 1; + unit_allow_path_power_mode = 0; unit_finish_attack_move = 1; unit_loyalty_require_local_leader = 1; unit_spy_fixed_target_loyalty = 0; @@ -305,12 +310,24 @@ int ConfigAdv::set(char *name, char *value) return 0; update_check_sum(name, value); } + else if( !strcmp(name, "fix_path_blocked_by_team") ) + { + if( !read_bool(value, &fix_path_blocked_by_team) ) + return 0; + update_check_sum(name, value); + } else if( !strcmp(name, "fix_recruit_dec_loyalty") ) { if( !read_bool(value, &fix_recruit_dec_loyalty) ) return 0; update_check_sum(name, value); } + else if( !strcmp(name, "fix_sea_travel_final_move") ) + { + if( !read_bool(value, &fix_sea_travel_final_move) ) + return 0; + update_check_sum(name, value); + } else if( !strcmp(name, "fix_town_unjob_worker") ) { if( !read_bool(value, &fix_town_unjob_worker) ) @@ -322,6 +339,12 @@ int ConfigAdv::set(char *name, char *value) strncpy(locale, value, LOCALE_LEN); locale[LOCALE_LEN] = 0; } + else if( !strcmp(name, "mine_unlimited_reserve") ) + { + if( !read_bool(value, &mine_unlimited_reserve) ) + return 0; + update_check_sum(name, value); + } else if( !strcmp(name, "monster_alternate_attack_curve") ) { if( !read_bool(value, &monster_alternate_attack_curve) ) @@ -442,6 +465,12 @@ int ConfigAdv::set(char *name, char *value) return 0; update_check_sum(name, value); } + else if( !strcmp(name, "unit_allow_path_power_mode") ) + { + if( !read_bool(value, &unit_allow_path_power_mode) ) + return 0; + update_check_sum(name, value); + } else if( !strcmp(name, "unit_spy_fixed_target_loyalty") ) { if( !read_bool(value, &unit_spy_fixed_target_loyalty) ) diff --git a/src/LocaleRes.cpp b/src/LocaleRes.cpp index 2ad79f20..ec6bccef 100644 --- a/src/LocaleRes.cpp +++ b/src/LocaleRes.cpp @@ -21,6 +21,7 @@ //Filename : LocaleRes.cpp //Description : Locale Resources +#include #ifdef ENABLE_NLS #include #include @@ -28,9 +29,24 @@ #include #include -#include #include + +#ifndef HAVE_SETENV +static String lc_all_str; +int setenv(const char *name, const char *value, int overwrite) +{ + if( !value ) + return putenv(name); + + lc_all_str = name; + lc_all_str += "="; + lc_all_str += value; + return putenv(lc_all_str); +} +#endif + + //------------- End of function Constructor -------// // LocaleRes::LocaleRes() @@ -65,16 +81,15 @@ LocaleRes::~LocaleRes() void LocaleRes::init() { #ifdef ENABLE_NLS - const char *env_locale_dir; - if( misc.is_file_exist("locale") ) - bindtextdomain(PACKAGE, "locale"); - else if( env_locale_dir = getenv("SKLOCALE") ) - bindtextdomain(PACKAGE, env_locale_dir); - else - bindtextdomain(PACKAGE, LOCALE_DIR); + const char *locale_dir; + locale_dir = get_locale_dir(); + if( locale_dir ) + { + bindtextdomain(PACKAGE, locale_dir); + } textdomain(PACKAGE); - - load(); + setlocale(LC_ALL, ""); + load(getenv("SKMESSAGES")); in_buf = mem_add(INIT_BUF_SIZE+1); in_buf_size = INIT_BUF_SIZE; @@ -110,24 +125,34 @@ void LocaleRes::deinit() //------------- End of function LocaleRes::deinit ---------// -//----------- Start of function LocaleRes::change_locale ---------// +//----------- Start of function LocaleRes::load ---------// +// +// Performs setlocale and initializes codeset conversion. // -void LocaleRes::load() +void LocaleRes::load(const char *locale) { #ifdef ENABLE_NLS - const char *ctype; - if( config_adv.locale[0] ) + if( locale && locale[0] ) { - if( !setlocale(LC_ALL, config_adv.locale) ) - return; - ctype = config_adv.locale; + setlocale(LC_MESSAGES, locale); + setlocale(LC_CTYPE, locale); + // The gettext team says setting the env var is the best way to + // inform gettext of the change. + setenv("LC_MESSAGES", locale, 1); } - else + locale = get_messages_locale(); + + if( !locale || !locale[0] ) { - setlocale(LC_ALL, ""); - ctype = setlocale(LC_CTYPE, NULL); - if( !ctype ) - return; + // The platform doesn't have full POSIX localization, and the + // user did not specify a locale in the game config. Default to + // English. The reason why to do this is if gettext does end up + // mapping the locale internally, we don't know what font to + // use. English is a safe choice. + locale = "en_US"; + setlocale(LC_MESSAGES, locale); + setlocale(LC_CTYPE, locale); + setenv("LC_MESSAGES", locale, 1); } LocaleRec *localeRec; @@ -147,7 +172,7 @@ void LocaleRes::load() localeRec = (LocaleRec*) dbLocale->read(i+1); misc.rtrim_fld( lang, localeRec->lang, localeRec->LANG_LEN ); - if( !misc.str_icmpx(ctype, lang) ) + if( !misc.str_icmpx(locale, lang) ) continue; misc.rtrim_fld( fontset, localeRec->fontset, localeRec->FONTSET_LEN ); @@ -173,7 +198,7 @@ void LocaleRes::load() cd_from_sdl = iconv_open("ISO-8859-1//TRANSLIT//IGNORE", "UTF-8"); #endif } -//------------- End of function LocaleRes::change_locale ---------// +//------------- End of function LocaleRes::load ---------// #ifdef ENABLE_NLS @@ -216,3 +241,54 @@ const char *LocaleRes::conv_str(iconv_t cd, const char *s) return out_buf; } #endif + + +//-------- Begin of function LocaleRes::get_locale_dir -----------// +// +const char *LocaleRes::get_locale_dir() +{ + if( misc.is_file_exist("locale") ) + return "locale"; + if( misc.is_file_exist(getenv("SKLOCALE")) ) + return getenv("SKLOCALE"); +#ifdef LOCALE_DIR + if( misc.is_file_exist(LOCALE_DIR) ) + return LOCALE_DIR; +#endif + return NULL; +} +//---------- End of function LocaleRes::get_locale_dir ----------// + + +//-------- Begin of function LocaleRes::get_messages_locale -----------// +// +const char *LocaleRes::get_messages_locale() +{ + const char *locale; + +#ifdef HAVE_LC_MESSAGES + /* setlocale(LC_ALL, "") has been done previously */ + locale = setlocale(LC_MESSAGES, NULL); + if( locale && locale[0] ) + return locale; +#endif + + locale = getenv("LC_ALL"); + if( locale && locale[0] ) + return locale; + + locale = getenv("LC_MESSAGES"); + if( locale && locale[0] ) + return locale; + + locale = getenv("LANG"); + if( locale && locale[0] ) + return locale; + + // We don't spend the time to map what Windows uses for locales. And + // some platforms don't have a POSIX setlocale, so if the user does not + // manually set an option in this case, we don't know the locale. + + return NULL; +} +//---------- End of function LocaleRes::get_messages_locale ----------// diff --git a/src/OAI_ACT2.cpp b/src/OAI_ACT2.cpp index d6d5b43a..28f6d08b 100644 --- a/src/OAI_ACT2.cpp +++ b/src/OAI_ACT2.cpp @@ -369,10 +369,13 @@ int Nation::ai_settle_to_other_town(ActionNode* actionNode) if( !raceId ) return -1; - //---- if cannot recruit because the loyalty is too low ---// + //---- if cannot recruit because the loyalty is too low, try reward ---// - if( !townPtr->can_recruit(raceId) && townPtr->has_linked_own_camp ) + if( !townPtr->can_recruit(raceId) ) { + if( !townPtr->has_linked_own_camp ) // need overseer to reward + return 0; + int minRecruitLoyalty = MIN_RECRUIT_LOYALTY + townPtr->recruit_dec_loyalty(raceId, 0); //--- if cannot recruit because of low loyalty, reward the town people now ---// @@ -387,8 +390,11 @@ int Nation::ai_settle_to_other_town(ActionNode* actionNode) if( !townPtr->can_recruit(raceId) ) // if still cannot be recruited, return 0 now return 0; } - - return 0; + else + { + // can't recruit for some other reason + return 0; + } } //------------------------------------------------------// @@ -421,15 +427,19 @@ int Nation::ai_settle_to_other_town(ActionNode* actionNode) // action_x_loc, action_y_loc - location of the destination town. // ref_x_loc, ref_y_loc - location of the origin town. // +// Note: When the action is processed successfully, it will only be +// cleared via an action_failure() because the unit doesn't have a scout +// action mode for scout processing. The unit will be placed in the +// standard move action mode to accomplish the task. +// int Nation::ai_scout(ActionNode* actionNode) { if(!seek_path.total_node_avail) return 0; - //------- check if both towns are ready first --------// + //------- check if the town is ready --------// - if(!check_town_ready(actionNode->action_x_loc, actionNode->action_y_loc) || - !check_town_ready(actionNode->ref_x_loc, actionNode->ref_y_loc)) + if( !check_town_ready(actionNode->ref_x_loc, actionNode->ref_y_loc) ) { return -1; } @@ -440,8 +450,6 @@ int Nation::ai_scout(ActionNode* actionNode) Location* locPtr = world.get_loc(actionNode->ref_x_loc, actionNode->ref_y_loc); - err_when(!locPtr->is_town() || town_array.is_deleted(locPtr->town_recno())); - Town* townPtr = town_array[locPtr->town_recno()]; // point to the old town int raceId = townPtr->pick_random_race(0, 1); // 0-don't pick has job unit, 1-pick spies @@ -451,7 +459,7 @@ int Nation::ai_scout(ActionNode* actionNode) //---- if cannot recruit because the loyalty is too low ---// - if( !townPtr->can_recruit(raceId) && townPtr->has_linked_own_camp ) + if( !townPtr->can_recruit(raceId) ) return 0; //------------------------------------------------------// diff --git a/src/OAI_CAPT.cpp b/src/OAI_CAPT.cpp index e87fe8a5..900ef107 100644 --- a/src/OAI_CAPT.cpp +++ b/src/OAI_CAPT.cpp @@ -450,12 +450,16 @@ int Nation::find_best_capturer(int townRecno, int raceId, int& bestTargetResista // int Nation::mobilize_capturer(int unitRecno) { - //--- if the picked unit is an overseer of an existng camp ---// Unit* unitPtr = unit_array[unitRecno]; if( unitPtr->unit_mode == UNIT_MODE_OVERSEE ) { + //--- if the picked unit is an overseer of an existing camp ---// + + if( cash < EXPENSE_TRAIN_UNIT ) // training a replacement costs money + return 0; + Firm* firmPtr = firm_array[unitPtr->unit_mode_para]; Town* townPtr; diff --git a/src/OAI_GRAN.cpp b/src/OAI_GRAN.cpp index 25ae3433..db7ec3d5 100644 --- a/src/OAI_GRAN.cpp +++ b/src/OAI_GRAN.cpp @@ -334,6 +334,9 @@ int Nation::think_surrender() if( nation_array.is_deleted(i) || i==nation_recno ) continue; + if( !get_relation(i)->has_contact ) // don't surrender to a nation without contact + continue; + nationPtr = nation_array[i]; if( nationPtr->cash <= 300 ) // don't surrender to an economically handicapped nation diff --git a/src/OAI_MAR2.cpp b/src/OAI_MAR2.cpp index 6e98c63b..cdb17a64 100644 --- a/src/OAI_MAR2.cpp +++ b/src/OAI_MAR2.cpp @@ -26,6 +26,7 @@ #include #include #include +#include //-------- Begin of function Nation::ai_sea_travel -------// // @@ -206,9 +207,10 @@ int Nation::ai_sea_travel3(ActionNode* actionNode) unitMarine->unload_all_units(COMMAND_AI); // unload all units now - return 1; // finish the action. + if( !config_adv.fix_sea_travel_final_move ) + return 1; // finish the action. + -/* //---------- 5. Validate all units ----------// for( int i=unitCount-1 ; i>=0 ; i-- ) @@ -290,7 +292,6 @@ int Nation::ai_sea_travel3(ActionNode* actionNode) actionNode->instance_count = actionNode->processing_instance_count+1; // set the instance count so process_action() won't cause error. return 1; -*/ } //-------- End of function Nation::ai_sea_travel3 -------// diff --git a/src/OAI_MARI.cpp b/src/OAI_MARI.cpp index 5fb8cbb2..28f629b7 100644 --- a/src/OAI_MARI.cpp +++ b/src/OAI_MARI.cpp @@ -216,7 +216,7 @@ int Nation::ai_build_harbor(int landRegionId, int seaRegionId) if( !locPtr->can_build_whole_harbor() ) continue; - if( !world.is_adjacent_region(xLoc, yLoc, seaRegionId) ) + if( !world.is_harbor_region(xLoc, yLoc, landRegionId, seaRegionId) ) continue; if( !world.can_build_firm(xLoc, yLoc, FIRM_HARBOR) ) diff --git a/src/OAI_SEEK.cpp b/src/OAI_SEEK.cpp index f765ef86..9d5a23c6 100644 --- a/src/OAI_SEEK.cpp +++ b/src/OAI_SEEK.cpp @@ -126,7 +126,8 @@ int Nation::seek_mine(short& xLoc, short& yLoc, short& refXLoc, short& refYLoc) if(siteLocPtr->region_id!=locPtr->region_id) continue; // not on the same territory - dist = misc.points_distance(sitePtr->map_x_loc, sitePtr->map_y_loc, townPtr->center_x, townPtr->center_y); + dist = misc.rects_distance(sitePtr->map_x_loc, sitePtr->map_y_loc, sitePtr->map_x_loc, sitePtr->map_y_loc, + townPtr->loc_x1, townPtr->loc_y1, townPtr->loc_x2, townPtr->loc_y2); //-------------------------------------------------------------------------// // check whether a mine is already connected to this town, if so, use it diff --git a/src/OAI_UNIT.cpp b/src/OAI_UNIT.cpp index e598572c..55de6747 100644 --- a/src/OAI_UNIT.cpp +++ b/src/OAI_UNIT.cpp @@ -372,6 +372,9 @@ int Nation::hire_unit(int skillId, int raceId, short destX, short destY) // int Nation::train_unit(int skillId, int raceId, short destX, short destY, int& trainTownRecno, int actionId) { + if( skillId && cash < EXPENSE_TRAIN_UNIT ) // training costs money + return 0; + //----- locate the best town for training the unit -----// int i; diff --git a/src/OCOLTBL.cpp b/src/OCOLTBL.cpp index c34bcd98..c3c52045 100644 --- a/src/OCOLTBL.cpp +++ b/src/OCOLTBL.cpp @@ -191,7 +191,7 @@ void ColorTable::generate_table(int absScale, PalDesc & palD, RGBColor (*fp)(RGB { int palSize = palD.pal_size; - err_when(absScale < 0 || palD.reserved_color < 0 || palD.pal == NULL); + err_when(absScale < 0 || palD.reserved_count < 0 || palD.pal == NULL); err_when(palSize > MAX_COLOUR_TABLE_SIZE); deinit(); diff --git a/src/OCONFIG.cpp b/src/OCONFIG.cpp index 4d39d97a..0a804038 100644 --- a/src/OCONFIG.cpp +++ b/src/OCONFIG.cpp @@ -460,7 +460,7 @@ int Config::single_player_difficulty() score += 7; if( fog_of_war ) score += 7; - score += (7 - start_up_raw_site) * 5; + score += (7 - MAX(start_up_raw_site, 7)) * 5; // if( start_up_cash <= SMALL_STARTUP_RESOURCE ) // score += 16; diff --git a/src/OFIRM.cpp b/src/OFIRM.cpp index 4a60414a..1bfd7984 100644 --- a/src/OFIRM.cpp +++ b/src/OFIRM.cpp @@ -1098,8 +1098,8 @@ int Firm::assign_settle(int raceId, int unitLoyalty, int isOverseer) if( world.locate_space( &xLoc, &yLoc, loc_x2, loc_y2, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, UNIT_LAND, region_id, 1 ) ) // the town must be in the same region as this firm. { - if( misc.points_distance( center_x, center_y, xLoc+(STD_TOWN_LOC_WIDTH-1)/2, - yLoc+(STD_TOWN_LOC_HEIGHT-1)/2 ) <= EFFECTIVE_FIRM_TOWN_DISTANCE ) + if( misc.rects_distance(xLoc, yLoc, xLoc+STD_TOWN_LOC_WIDTH-1, yLoc+STD_TOWN_LOC_HEIGHT-1, + loc_x1, loc_y1, loc_x2, loc_y2) <= EFFECTIVE_FIRM_TOWN_DISTANCE ) { int townRecno = town_array.add_town( nation_recno, raceId, xLoc, yLoc ); @@ -1142,7 +1142,8 @@ int Firm::find_settle_town() if( townPtr->nation_recno != nation_recno ) continue; - townDistance = misc.points_distance( townPtr->center_x, townPtr->center_y, center_x, center_y ); + townDistance = misc.rects_distance(townPtr->loc_x1, townPtr->loc_y1, townPtr->loc_x2, townPtr->loc_y2, + loc_x1, loc_y1, loc_x2, loc_y2); if( townDistance < minDistance ) { @@ -2875,8 +2876,8 @@ void Firm::worker_migrate(int workerId, int destTownRecno, int newLoyalty) Town* destTown = town_array[destTownRecno]; err_when( !raceId ); - err_when( misc.points_distance( center_x, center_y, destTown->center_x, - destTown->center_y ) > EFFECTIVE_FIRM_TOWN_DISTANCE ); + err_when( misc.rects_distance(loc_x1, loc_y1, loc_x2, loc_y2, destTown->loc_x1, destTown->loc_y1, + destTown->loc_x2, destTown->loc_y2) > EFFECTIVE_FIRM_TOWN_DISTANCE ); //------------- add news --------------// @@ -3071,8 +3072,8 @@ void Firm::setup_link() //---------- check if the firm is close enough to this firm -------// - if( misc.points_distance( firmPtr->center_x, firmPtr->center_y, - center_x, center_y ) > EFFECTIVE_FIRM_FIRM_DISTANCE ) + if( misc.rects_distance(firmPtr->loc_x1, firmPtr->loc_y1, firmPtr->loc_x2, firmPtr->loc_y2, + loc_x1, loc_y1, loc_x2, loc_y2) > EFFECTIVE_FIRM_FIRM_DISTANCE ) { continue; } @@ -3158,8 +3159,8 @@ void Firm::setup_link() //------ check if the town is close enough to this firm -------// - if( misc.points_distance( townPtr->center_x, townPtr->center_y, - center_x, center_y ) > EFFECTIVE_FIRM_TOWN_DISTANCE ) + if( misc.rects_distance(townPtr->loc_x1, townPtr->loc_y1, townPtr->loc_x2, townPtr->loc_y2, + loc_x1, loc_y1, loc_x2, loc_y2) > EFFECTIVE_FIRM_TOWN_DISTANCE ) { continue; } diff --git a/src/OFIRMIF.cpp b/src/OFIRMIF.cpp index ad99bc4a..1aa26f57 100644 --- a/src/OFIRMIF.cpp +++ b/src/OFIRMIF.cpp @@ -261,7 +261,7 @@ void Firm::disp_basic_info(int dispY1, int refreshFlag) int showRepairIcon = builder_recno && !under_construction && should_show_info(); int showReqRepairIcon = !builder_recno && !under_construction && should_show_info() && own_firm() && find_idle_builder(0); - err_when( showRepairIcon && showReqRepairIcon ) + err_when( showRepairIcon && showReqRepairIcon ); if( refreshFlag == INFO_REPAINT ) { diff --git a/src/OF_CAMP2.cpp b/src/OF_CAMP2.cpp index 5d721c2b..78fb2dff 100644 --- a/src/OF_CAMP2.cpp +++ b/src/OF_CAMP2.cpp @@ -450,7 +450,10 @@ int FirmCamp::ai_recruit(int recruitCombatLevel) if( townPtr->jobless_race_pop_array[raceId-1] > 0 && townPtr->race_loyalty_array[raceId-1] < 40 ) { - if( townPtr->accumulated_reward_penalty > 30 ) // if the reward penalty is too high, do reward + if( townPtr->accumulated_reward_penalty > 30 ) // if the reward penalty is too high, don't reward + break; + + if( nation_array[nation_recno]->cash <= 0 ) // must have cash to reward break; townPtr->reward(COMMAND_AI); diff --git a/src/OF_INN.cpp b/src/OF_INN.cpp index 5b6ec998..66ee3921 100644 --- a/src/OF_INN.cpp +++ b/src/OF_INN.cpp @@ -715,7 +715,8 @@ void FirmInn::auto_defense(short targetRecno) if(townPtr->nation_recno!=nation_recno) continue; - dist = misc.points_distance(center_x, center_y, townPtr->center_x, townPtr->center_y); + dist = misc.rects_distance(loc_x1, loc_y1, loc_x2, loc_y2, + townPtr->loc_x1, townPtr->loc_y1, townPtr->loc_x2, townPtr->loc_y2); if(dist <= EFFECTIVE_FIRM_TOWN_DISTANCE) townPtr->auto_defense(targetRecno); } diff --git a/src/OF_INN2.cpp b/src/OF_INN2.cpp index d11f7d49..3ec1856e 100644 --- a/src/OF_INN2.cpp +++ b/src/OF_INN2.cpp @@ -81,8 +81,9 @@ int FirmInn::think_del() if( townPtr->nation_recno == nation_recno ) { - if( misc.points_distance( townPtr->center_x, townPtr->center_y, - center_x, center_y ) <= EFFECTIVE_FIRM_TOWN_DISTANCE ) + if( misc.rects_distance(townPtr->loc_x1, townPtr->loc_y1, + townPtr->loc_x2, townPtr->loc_y2, + loc_x1, loc_y1, loc_x2, loc_y2) <= EFFECTIVE_FIRM_TOWN_DISTANCE ) { return 0; } diff --git a/src/OF_MARK2.cpp b/src/OF_MARK2.cpp index 1b4b90d0..93a26b63 100644 --- a/src/OF_MARK2.cpp +++ b/src/OF_MARK2.cpp @@ -599,7 +599,9 @@ int FirmMarket::think_export_product() if( townPtr->no_neighbor_space ) // if there is no space in the neighbor area for building a new firm. continue; - if( misc.points_distance( center_x, center_y, townPtr->center_x, center_y ) > MAX_WORLD_X_LOC/4 ) // don't consider if it is too far away + if( misc.rects_distance(loc_x1, loc_y1, loc_x2, loc_y2, + townPtr->loc_x1, townPtr->loc_y1, + townPtr->loc_x2, townPtr->loc_y2) > MAX_WORLD_X_LOC/4 ) // don't consider if it is too far away continue; //-----------------------------------------// diff --git a/src/OF_MINE.cpp b/src/OF_MINE.cpp index fa878b90..01cc8843 100644 --- a/src/OF_MINE.cpp +++ b/src/OF_MINE.cpp @@ -37,6 +37,7 @@ #include #include #include "gettext.h" +#include //------- define static vars -------// @@ -404,6 +405,8 @@ void FirmMine::produce_raw() produceQty = MIN( produceQty, max_stock_qty-stock_qty ); reserve_qty -= produceQty; + if( config_adv.mine_unlimited_reserve && reserve_qty < 1500 ) + reserve_qty = 1500; stock_qty += produceQty; cur_month_production += produceQty; diff --git a/src/OGAME.cpp b/src/OGAME.cpp index 0b9a6c1b..99d134e2 100644 --- a/src/OGAME.cpp +++ b/src/OGAME.cpp @@ -242,6 +242,7 @@ void Game::deinit(int loadGameCall) { if( !init_flag ) return; + game_mode = GAME_POSTGAME; power.disable(); // disable power, which handle mouse inputs diff --git a/src/OGAMEMP.cpp b/src/OGAMEMP.cpp index a55be824..e9349df7 100644 --- a/src/OGAMEMP.cpp +++ b/src/OGAMEMP.cpp @@ -3645,16 +3645,16 @@ int Game::mp_select_option(NewNationPara *nationPara, int *mpPlayerCount) { if( rawSiteInc.detect() ) { - if( ++tempConfig.start_up_raw_site > 7 ) - tempConfig.start_up_raw_site = 7; + if( ++tempConfig.start_up_raw_site > MAX_RAW_RES_SITE ) + tempConfig.start_up_raw_site = MAX_RAW_RES_SITE; tempConfig.difficulty_level = OPTION_CUSTOM; configChange = 1; refreshFlag |= SGOPTION_RAW | SGOPTION_DIFFICULTY; } else if( rawSiteDec.detect() ) { - if( --tempConfig.start_up_raw_site < 1 ) - tempConfig.start_up_raw_site = 1; + if( --tempConfig.start_up_raw_site < MIN_RAW_RES_SITE ) + tempConfig.start_up_raw_site = MIN_RAW_RES_SITE; tempConfig.difficulty_level = OPTION_CUSTOM; configChange = 1; refreshFlag |= SGOPTION_RAW | SGOPTION_DIFFICULTY; diff --git a/src/OGAMEND.cpp b/src/OGAMEND.cpp index 1b094592..5a4d0477 100644 --- a/src/OGAMEND.cpp +++ b/src/OGAMEND.cpp @@ -77,9 +77,12 @@ static void split_line(char *line); // void Game::game_end(int winNationRecno, int playerDestroyed, int surrenderToNationRecno, int retireFlag) { - //--- set scenario as complete if they didn't retire ---// - if(!retireFlag && !playerDestroyed) + //--- set scenario as complete if the player wins ---// + if( nation_array.player_recno && winNationRecno == nation_array.player_recno ) + { + err_when( playerDestroyed || surrenderToNationRecno || retireFlag ); playerStats.set_scenario_play_status(scenario_file_name, nsPlayerStats::PlayStatus::COMPLETED); + } //--- skip all game ending screens if in demo mode ---// diff --git a/src/OGAMSING.cpp b/src/OGAMSING.cpp index 7cf09c49..ae87cadc 100644 --- a/src/OGAMSING.cpp +++ b/src/OGAMSING.cpp @@ -815,15 +815,15 @@ static int select_option() { if( rawSiteInc.detect() ) { - if( ++tempConfig.start_up_raw_site > 7 ) - tempConfig.start_up_raw_site = 7; + if( ++tempConfig.start_up_raw_site > MAX_RAW_RES_SITE ) + tempConfig.start_up_raw_site = MAX_RAW_RES_SITE; tempConfig.difficulty_level = OPTION_CUSTOM; refreshFlag |= SGOPTION_RAW | SGOPTION_DIFFICULTY; } else if( rawSiteDec.detect() ) { - if( --tempConfig.start_up_raw_site < 1 ) - tempConfig.start_up_raw_site = 1; + if( --tempConfig.start_up_raw_site < MIN_RAW_RES_SITE ) + tempConfig.start_up_raw_site = MIN_RAW_RES_SITE; tempConfig.difficulty_level = OPTION_CUSTOM; refreshFlag |= SGOPTION_RAW | SGOPTION_DIFFICULTY; diff --git a/src/OMISC.cpp b/src/OMISC.cpp index 93a9900d..08ad50db 100644 --- a/src/OMISC.cpp +++ b/src/OMISC.cpp @@ -608,7 +608,7 @@ int Misc::str_icmpx( const char* str1, const char* str2 ) err_when( !str1 || !str2 ); int i; - register int a,b; + REGISTER int a,b; for (i=0 ; (a=str1[i]) != '\0' && (b=str2[i]) != '\0' ; i++) @@ -1003,6 +1003,16 @@ int Misc::diagonal_distance(int x1, int y1, int x2, int y2) // x1, y1 = the starting point of the diagonal line // x2, y2 = the ending point of the diagonal line // +// This function can be used for measuring distances between +// two points in space. It can also be used to measure between +// shapes, but it is unreliable if the shape has one dimension +// size that is evenly divisible. Because the formula frequently +// used to calculate the center of a shape is a simple (x1+x2)/2, +// this means the center is often not precise in game logic. +// +// For a more accurate measurement, use rects_distance() as that +// will pick a group of coordinates that represent a center, then +// calculates a distance. int Misc::points_distance(int x1, int y1, int x2, int y2) { int x = abs(x1-x2); @@ -1013,6 +1023,54 @@ int Misc::points_distance(int x1, int y1, int x2, int y2) //---------- End of function Misc::points_distance ---------// +//------- Begin of function Misc::rects_distance ---------// +// +// Given two rectangles 'A' and 'B' in a pair of x and y coordinates, find the +// distance between the two rectanges, returning the maximum of the horizontal +// and vertical directions. +// +// ax1, ay1, ax2, ay2 = edge coordinates of rectangle A +// bx1, by1, bx2, by2 = edge coordinates of rectangle B +// edgeA = if not true measure to center of rectange A +// edgeB = if not true measure to center of rectange B +// +// If measuring to an edge, then the provided coordinates are used. Otherwise, +// when a rectangle size is evenly divisible, the center four coordinates are +// equally considered the center. If it is odd, there will only be one center +// coordinate to the shape. +// +int Misc::rects_distance(int ax1, int ay1, int ax2, int ay2, int bx1, int by1, int bx2, int by2, int edgeA, int edgeB) +{ + int x,y; + + if( !edgeA ) + { + int dx = (ax2-ax1)/2; + int dy = (ay2-ay1)/2; + ax1 += dx; + ax2 -= dx; + ay1 += dy; + ay2 -= dy; + } + + if( !edgeB ) + { + int dx = (bx2-bx1)/2; + int dy = (by2-by1)/2; + bx1 += dx; + bx2 -= dx; + by1 += dy; + by2 -= dy; + } + + x = MIN(abs(ax1-bx2),abs(ax2-bx1)); + y = MIN(abs(ay1-by2),abs(ay2-by1)); + + return MAX(x, y); +} +//---------- End of function Misc::rects_distance ---------// + + //------- Begin of function Misc::get_random_seed --------// // long Misc::get_random_seed() diff --git a/src/OMONSRES.cpp b/src/OMONSRES.cpp index cad1ba8e..f11f7843 100644 --- a/src/OMONSRES.cpp +++ b/src/OMONSRES.cpp @@ -232,8 +232,9 @@ int MonsterInfo::create_firm_monster() Town* townPtr = town_array[townRecno]; - if( misc.points_distance(xLoc, yLoc, townPtr->center_x, - townPtr->center_y) < MIN_MONSTER_CIVILIAN_DISTANCE ) + if( misc.rects_distance(xLoc, yLoc, xLoc+firmInfo->loc_width, yLoc+firmInfo->loc_height, + townPtr->loc_x1, townPtr->loc_y1, + townPtr->loc_x2, townPtr->loc_y2) < MIN_MONSTER_CIVILIAN_DISTANCE ) { return 0; } diff --git a/src/ONATIONB.cpp b/src/ONATIONB.cpp index 8734d886..2fa60128 100644 --- a/src/ONATIONB.cpp +++ b/src/ONATIONB.cpp @@ -236,8 +236,8 @@ void NationBase::deinit() // so there will be no more spies of this nation. //-----------------------------------------------------// - if( spyPtr->true_nation_recno == nation_recno ) // drop spy identities of spies in towns, firms and mobile ones - spyPtr->drop_spy_identity(); + if( spyPtr->true_nation_recno == nation_recno ) // retire counter-spies immediately + spyPtr->drop_spy_identity(); //-----------------------------------------------------// // For spies of other nation cloaked as this nation, @@ -246,10 +246,22 @@ void NationBase::deinit() //-----------------------------------------------------// else if( spyPtr->cloaked_nation_recno == nation_recno ) - spyPtr->change_cloaked_nation(spyPtr->true_nation_recno); + { + // changing cloak is normally only allowed when mobile - err_when( spyPtr->true_nation_recno == nation_recno || // there should be no more spies associated with this nation - spyPtr->cloaked_nation_recno == nation_recno ); + if( spyPtr->spy_place == SPY_FIRM ) + { + // at least try to return spoils before it goes poof + if( !spyPtr->can_capture_firm() || !spyPtr->capture_firm() ) + spyPtr->mobilize_firm_spy(); + } + else if( spyPtr->spy_place == SPY_TOWN ) + spyPtr->mobilize_town_spy(); + if( spyPtr->spy_place == SPY_MOBILE ) // what about on transport?? + spyPtr->change_cloaked_nation(spyPtr->true_nation_recno); + + err_when( spyPtr->cloaked_nation_recno == nation_recno ); // there should be no more spies associated with this nation + } } //----- deinit all units belonging to this nation -----// @@ -1533,34 +1545,58 @@ int NationBase::total_tech_level(int unitClass) // 0 - all races, when a Caravan is killed, 0 will // be passed, the loyalty of all races will be decreased. // -// penaltyLevel - positive value if this nation caused the death -// negative value if this nation suffered the death -// any nonzero value means loyalty will be decreased by -// by that absolute amount +// isAttacker - 1 if attacker nation, 0 if casualty nation +// +// penaltyType - the penalty to apply based on the damage incured +// 0 - mobile civilian recruit +// 1 - civilian in defense of a town +// 2 - civilian residing in town +// 3 - civilian trade unit // -// Reputation penalties are based on severity coded below. -// (Attacker,Defender) -// Killed caravan: (-10,-3) -// Killed town connected civilian: (-1,-0.3) -// Killed any other non-combat mobile unit: (-0.3,-0.3) -void NationBase::civilian_killed(int civilianRaceId, int penaltyLevel) +void NationBase::civilian_killed(int civilianRaceId, int isAttacker, int penaltyType) { - if( penaltyLevel ) - change_all_people_loyalty(-abs(penaltyLevel), civilianRaceId); - - if( penaltyLevel > 0 ) // caused the death by attacking a town or caravan + if( isAttacker ) { - if( civilianRaceId==0 ) // a caravan - change_reputation(-(float)10); - else - change_reputation(-(float)1); + if( penaltyType == 0 ) // mobile civilian + { + change_reputation(-0.3f); + } + else if( penaltyType == 1 ) // town defender + { + change_all_people_loyalty(-1.0f, civilianRaceId); + change_reputation(-1.0f); + } + else if( penaltyType == 2 ) // town resident + { + change_all_people_loyalty(-2.0f, civilianRaceId); + change_reputation(-1.0f); + } + else if( penaltyType == 3 ) // trader + { + change_all_people_loyalty(-2.0f, civilianRaceId); + change_reputation(-10.0f); + } } - else // suffered the death or minor low-combat civilian death + else // is casualty { - if( civilianRaceId==0 ) // a caravan - change_reputation(-(float)3); - else - change_reputation(-(float)0.3); + if( penaltyType == 0 ) // mobile civilian + { + change_reputation(-0.3f); + } + else if( penaltyType == 1 ) // town defender + { + change_reputation(-0.3f); + } + else if( penaltyType == 2 ) // town resident + { + change_all_people_loyalty(-1.0f, civilianRaceId); + change_reputation(-0.3f); + } + else if( penaltyType == 3 ) // trader + { + change_all_people_loyalty(-0.6f, civilianRaceId); + change_reputation(-2.0f); + } } } //----------- End of function NationBase::civilian_killed ---------// @@ -1801,11 +1837,11 @@ void NationBase::defeated() // // Change the loyalty of all the people in your nation. // -// loyaltyChange - degree of loyalty change +// loyaltyChange - degree of loyalty change // [int] raceId - if this is given, then only people of this race // will be affected. (default: 0) // -void NationBase::change_all_people_loyalty(int loyaltyChange, int raceId) +void NationBase::change_all_people_loyalty(float loyaltyChange, int raceId) { //---- update loyalty of units in this nation ----// @@ -1828,7 +1864,7 @@ void NationBase::change_all_people_loyalty(int loyaltyChange, int raceId) //--------- update loyalty change ----------// if( !raceId || unitPtr->race_id == raceId ) - unitPtr->change_loyalty(loyaltyChange); + unitPtr->change_loyalty((int)loyaltyChange); } //---- update loyalty of units in camps ----// @@ -1854,7 +1890,7 @@ void NationBase::change_all_people_loyalty(int loyaltyChange, int raceId) for(int j=firmPtr->worker_count-1 ; j>=0 ; j--, workerPtr++ ) { if( !raceId || workerPtr->race_id == raceId ) - workerPtr->change_loyalty(loyaltyChange); + workerPtr->change_loyalty((int)loyaltyChange); } } } @@ -1878,7 +1914,7 @@ void NationBase::change_all_people_loyalty(int loyaltyChange, int raceId) if( raceId ) // decrease loyalty of a specific race { if( townPtr->race_pop_array[raceId-1] > 0 ) - townPtr->change_loyalty(raceId, (float) loyaltyChange); + townPtr->change_loyalty(raceId, loyaltyChange); } else // decrease loyalty of all races { @@ -1887,7 +1923,7 @@ void NationBase::change_all_people_loyalty(int loyaltyChange, int raceId) if( townPtr->race_pop_array[j]==0 ) continue; - townPtr->change_loyalty(j+1, (float) loyaltyChange); + townPtr->change_loyalty(j+1, loyaltyChange); } } } diff --git a/src/OREBEL.cpp b/src/OREBEL.cpp index 695649bd..317eb245 100644 --- a/src/OREBEL.cpp +++ b/src/OREBEL.cpp @@ -749,8 +749,8 @@ int Rebel::think_capture_attack_town() if( world.get_region_id(townPtr->loc_x1, townPtr->loc_y1) != curRegionId ) continue; - townDistance = misc.points_distance( leaderXLoc, leaderYLoc, - townPtr->center_x, townPtr->center_y ); + townDistance = misc.rects_distance(leaderXLoc, leaderYLoc, leaderXLoc, leaderYLoc, + townPtr->loc_x1, townPtr->loc_y1, townPtr->loc_x2, townPtr->loc_y2); if( townDistance < closestTownDistance ) { diff --git a/src/OREMOTEM.cpp b/src/OREMOTEM.cpp index 0a00a20b..d1b6a0eb 100644 --- a/src/OREMOTEM.cpp +++ b/src/OREMOTEM.cpp @@ -2832,6 +2832,9 @@ void RemoteMsg::nation_set_should_attack() short *shortPtr = (short *)data_buf; err_when( *shortPtr != remote.nation_processing ); + if( *shortPtr != remote.nation_processing ) + return; + if( !nation_array.is_deleted(*shortPtr) && !nation_array.is_deleted(shortPtr[1]) ) { #ifdef DEBUG_LONG_LOG diff --git a/src/OR_NAT.cpp b/src/OR_NAT.cpp index 7af283aa..13c447ef 100644 --- a/src/OR_NAT.cpp +++ b/src/OR_NAT.cpp @@ -627,6 +627,9 @@ static void disp_nation_info() // static void detect_nation_info() { + if( !nation_array.player_recno || nation_array.player_recno != info.viewing_nation_recno ) + return; + int nationRecno = nation_filter(browse_nation.recno()); Nation* viewingNation = nation_array[info.viewing_nation_recno]; diff --git a/src/OSPATHBT.cpp b/src/OSPATHBT.cpp index db448c5e..0ddb3cee 100644 --- a/src/OSPATHBT.cpp +++ b/src/OSPATHBT.cpp @@ -50,7 +50,7 @@ void NodePriorityQueue::reset_priority_queue() void NodePriorityQueue::insert_node(Node *insertNode) { unsigned int i = ++size; - register int f=insertNode->node_f; + REGISTER int f=insertNode->node_f; Node **localElements = elements; while(i>1 && localElements[i/2]->node_f > f) diff --git a/src/OSPY.cpp b/src/OSPY.cpp index a9388ea9..7f1c222c 100644 --- a/src/OSPY.cpp +++ b/src/OSPY.cpp @@ -278,7 +278,6 @@ void Spy::next_day() if( true_nation_recno == nation_array.player_recno ) { - Unit* unitPtr = unit_array[spy_place_para]; if( spy_place == SPY_TOWN ) { Town* townPtr = town_array[spy_place_para]; @@ -289,31 +288,39 @@ void Spy::next_day() Firm* firmPtr = firm_array[spy_place_para]; world.visit( firmPtr->loc_x1, firmPtr->loc_y1, firmPtr->loc_x2, firmPtr->loc_y2, EXPLORE_RANGE-1 ); } - else if( unitPtr->unit_mode == UNIT_MODE_CONSTRUCT ) + else if( spy_place == SPY_MOBILE ) { - Firm* firmPtr = firm_array[unitPtr->unit_mode_para]; - world.visit( firmPtr->loc_x1, firmPtr->loc_y1, firmPtr->loc_x2, firmPtr->loc_y2, EXPLORE_RANGE-1 ); - } - else if( unitPtr->unit_mode == UNIT_MODE_ON_SHIP ) - { - Unit* shipPtr = unit_array[unitPtr->unit_mode_para]; - if( shipPtr->unit_mode == UNIT_MODE_IN_HARBOR ) + Unit* unitPtr = unit_array[spy_place_para]; + if( unitPtr->unit_mode == UNIT_MODE_CONSTRUCT ) { - Firm* firmPtr = firm_array[shipPtr->unit_mode_para]; + Firm* firmPtr = firm_array[unitPtr->unit_mode_para]; world.visit( firmPtr->loc_x1, firmPtr->loc_y1, firmPtr->loc_x2, firmPtr->loc_y2, EXPLORE_RANGE-1 ); } - else + else if( unitPtr->unit_mode == UNIT_MODE_ON_SHIP ) { - int xloc1 = shipPtr->next_x_loc(); - int yloc1 = shipPtr->next_y_loc(); - int xloc2 = xloc1+shipPtr->sprite_info->loc_width-1; - int yloc2 = yloc1+shipPtr->sprite_info->loc_height-1; - int range = unit_res[shipPtr->unit_id]->visual_range; - - world.unveil(xloc1, yloc1, xloc2, yloc2); - world.visit(xloc1, yloc1, xloc2, yloc2, range); + Unit* shipPtr = unit_array[unitPtr->unit_mode_para]; + if( shipPtr->unit_mode == UNIT_MODE_IN_HARBOR ) + { + Firm* firmPtr = firm_array[shipPtr->unit_mode_para]; + world.visit( firmPtr->loc_x1, firmPtr->loc_y1, firmPtr->loc_x2, firmPtr->loc_y2, EXPLORE_RANGE-1 ); + } + else + { + int xloc1 = shipPtr->next_x_loc(); + int yloc1 = shipPtr->next_y_loc(); + int xloc2 = xloc1+shipPtr->sprite_info->loc_width-1; + int yloc2 = yloc1+shipPtr->sprite_info->loc_height-1; + int range = unit_res[shipPtr->unit_id]->visual_range; + + world.unveil(xloc1, yloc1, xloc2, yloc2); + world.visit(xloc1, yloc1, xloc2, yloc2, range); + } } } + else + { + err_here(); + } } //---------- debug code -----------// @@ -922,25 +929,15 @@ int Spy::capture_firm() if( spy_place != SPY_FIRM ) return 0; + if( !can_capture_firm() ) + return 0; + Firm* firmPtr = firm_array[spy_place_para]; //------- if the spy is the overseer of the firm --------// if( firm_res[firmPtr->firm_id]->need_overseer ) { - //-----------------------------------------------------// - // - // If the firm needs an overseer, the firm can only be - // captured if the spy is the overseer of the firm. - // - //-----------------------------------------------------// - - if( !firmPtr->overseer_recno || - unit_array[firmPtr->overseer_recno]->spy_recno != spy_recno ) - { - return 0; - } - //---------------------------------------------------// // // For those soldiers who disagree with the spy general will @@ -1006,19 +1003,6 @@ int Spy::capture_firm() { //------ otherwise the spy is a worker of the firm -------// - //---- check whether it's true that the only units in the firms are our spies ---// - - Worker* workerPtr = firmPtr->worker_array; - - for( int i=0 ; iworker_count ; i++, workerPtr++ ) - { - if( !workerPtr->spy_recno ) // this worker is not a spy - return 0; - - if( spy_array[workerPtr->spy_recno]->true_nation_recno != true_nation_recno ) - return 0; // this worker is a spy, but not belong to the same nation - } - //--------- add news message --------// if( firmPtr->nation_recno == nation_array.player_recno ) @@ -1039,6 +1023,57 @@ int Spy::capture_firm() //---------- End of function Spy::capture_firm ----------// +//--------- Begin of function Spy::can_capture_firm ----------// +// +// Report if the spy can capture the firm. +// +int Spy::can_capture_firm() +{ + if( spy_place != SPY_FIRM ) + return 0; + + Firm* firmPtr = firm_array[spy_place_para]; + + //------- if the spy is the overseer of the firm --------// + + if( firm_res[firmPtr->firm_id]->need_overseer ) + { + //-----------------------------------------------------// + // + // If the firm needs an overseer, the firm can only be + // captured if the spy is the overseer of the firm. + // + //-----------------------------------------------------// + + if( !firmPtr->overseer_recno || + unit_array[firmPtr->overseer_recno]->spy_recno != spy_recno ) + { + return 0; + } + + return 1; + } + + //------ otherwise the spy is a worker of the firm -------// + + //---- check whether it's true that the only units in the firms are our spies ---// + + Worker* workerPtr = firmPtr->worker_array; + + for( int i=0 ; iworker_count ; i++, workerPtr++ ) + { + if( !workerPtr->spy_recno ) // this worker is not a spy + return 0; + + if( spy_array[workerPtr->spy_recno]->true_nation_recno != true_nation_recno ) + return 0; // this worker is a spy, but not belong to the same nation + } + + return 1; +} +//---------- End of function Spy::can_capture_firm ----------// + + //-------- Begin of function Spy::mobilize_spy ------// // // return: recno of the mobilized unit. diff --git a/src/OTOWN.cpp b/src/OTOWN.cpp index 3aa828a6..9b070184 100644 --- a/src/OTOWN.cpp +++ b/src/OTOWN.cpp @@ -2232,7 +2232,9 @@ void Town::think_migrate() if( townPtr->population>=MAX_TOWN_POPULATION ) continue; - townDistance = misc.points_distance(center_x, center_y, townPtr->center_x, townPtr->center_y); + townDistance = misc.rects_distance(loc_x1, loc_y1, loc_x2, loc_y2, + townPtr->loc_x1, townPtr->loc_y1, + townPtr->loc_x2, townPtr->loc_y2); #ifndef ENABLE_LONG_DISTANCE_MIGRATION if( townDistance > EFFECTIVE_TOWN_TOWN_DISTANCE ) @@ -2531,8 +2533,8 @@ bool Town::can_migrate(int destTownRecno, bool migrateNow, int raceId) //---- if the target town is within the effective range of this firm ----// - if( misc.points_distance( destTown->center_x, destTown->center_y, - firmPtr->center_x, firmPtr->center_y ) > EFFECTIVE_FIRM_TOWN_DISTANCE ) + if( misc.rects_distance(destTown->loc_x1, destTown->loc_y1, destTown->loc_x2, destTown->loc_y2, + firmPtr->loc_x1, firmPtr->loc_y1, firmPtr->loc_x2, firmPtr->loc_y2) > EFFECTIVE_FIRM_TOWN_DISTANCE ) { continue; } @@ -2702,8 +2704,9 @@ void Town::being_attacked(int attackerUnitRecno, float attackDamage) // only call out defender when the attacking unit is within the effective defending distance - if( misc.points_distance( attackerUnit->cur_x_loc(), attackerUnit->cur_y_loc(), - center_x, center_y ) <= EFFECTIVE_DEFEND_TOWN_DISTANCE ) + if( misc.rects_distance(attackerUnit->cur_x_loc(), attackerUnit->cur_y_loc(), + attackerUnit->cur_x_loc(), attackerUnit->cur_y_loc(), + loc_x1, loc_y1, loc_x2, loc_y2) <= EFFECTIVE_DEFEND_TOWN_DISTANCE ) { int loopCount=0; @@ -3042,10 +3045,10 @@ void Town::kill_town_people(int raceId, int attackerNationRecno) //---- killing civilian people decreases loyalty -----// if( nation_recno && attackerNationRecno ) // your people's loyalty decreases because you cannot protect them. - nation_array[nation_recno]->civilian_killed(raceId, -1); // but only when your units are killed by enemies, neutral disasters are not counted + nation_array[nation_recno]->civilian_killed(raceId, 0, 2); // but only when your units are killed by enemies, neutral disasters are not counted if( attackerNationRecno ) // the attacker's people's loyalty decreases because of the killing actions. - nation_array[attackerNationRecno]->civilian_killed(raceId, 2); // the nation is the attacking one + nation_array[attackerNationRecno]->civilian_killed(raceId, 1, 2); // the nation is the attacking one // -------- sound effect ---------// @@ -3312,8 +3315,9 @@ void Town::setup_link() //---------- check if the firm is close enough to this firm -------// - if( misc.points_distance( firmPtr->center_x, firmPtr->center_y, - center_x, center_y ) > EFFECTIVE_FIRM_TOWN_DISTANCE ) + if( misc.rects_distance(firmPtr->loc_x1, firmPtr->loc_y1, + firmPtr->loc_x2, firmPtr->loc_y2, + loc_x1, loc_y1, loc_x2, loc_y2) > EFFECTIVE_FIRM_TOWN_DISTANCE ) { continue; } @@ -3388,10 +3392,11 @@ void Town::setup_link() townPtr = town_array[townRecno]; - //------ check if the town is close enough to this firm -------// + //------ check if the town is close enough to this town -------// - if( misc.points_distance( townPtr->center_x, townPtr->center_y, - center_x, center_y ) > EFFECTIVE_TOWN_TOWN_DISTANCE ) + if( misc.rects_distance(townPtr->loc_x1, townPtr->loc_y1, + townPtr->loc_x2, townPtr->loc_y2, + loc_x1, loc_y1, loc_x2, loc_y2) > EFFECTIVE_TOWN_TOWN_DISTANCE ) { continue; } @@ -4586,8 +4591,9 @@ int Town::closest_own_camp() continue; } - curDistance = misc.points_distance( center_x, center_y, - firmPtr->center_x, firmPtr->center_y ); + curDistance = misc.rects_distance(loc_x1, loc_y1, loc_x2, loc_y2, + firmPtr->loc_x1, firmPtr->loc_y1, + firmPtr->loc_x2, firmPtr->loc_y2); if( curDistance < minDistance ) { diff --git a/src/OTOWNA.cpp b/src/OTOWNA.cpp index 97c6ac68..a9092796 100644 --- a/src/OTOWNA.cpp +++ b/src/OTOWNA.cpp @@ -458,8 +458,9 @@ int TownArray::think_town_loc(int maxTries, int& xLoc, int& yLoc) townPtr = town_array[townRecno]; - if( misc.points_distance(xLoc+1, yLoc+1, townPtr->center_x, // xLoc+1 and yLoc+1 to take the center location of the town - townPtr->center_y) < MIN_INTER_TOWN_DISTANCE ) + if( misc.rects_distance(xLoc, yLoc, xLoc+STD_TOWN_LOC_WIDTH-1, yLoc+STD_TOWN_LOC_HEIGHT-1, + townPtr->loc_x1, townPtr->loc_y1, + townPtr->loc_x2, townPtr->loc_y2) < MIN_INTER_TOWN_DISTANCE ) { break; } @@ -477,8 +478,9 @@ int TownArray::think_town_loc(int maxTries, int& xLoc, int& yLoc) firmPtr = firm_array[firmRecno]; - if( misc.points_distance(xLoc+1, yLoc+1, firmPtr->center_x, - firmPtr->center_y) < MONSTER_ATTACK_NEIGHBOR_RANGE ) + if( misc.rects_distance(xLoc, yLoc, xLoc+STD_TOWN_LOC_WIDTH-1, yLoc+STD_TOWN_LOC_HEIGHT-1, + firmPtr->loc_x1, firmPtr->loc_y1, + firmPtr->loc_x2, firmPtr->loc_y2) < MONSTER_ATTACK_NEIGHBOR_RANGE ) { break; } @@ -647,7 +649,7 @@ int TownArray::find_nearest_town(int xLoc, int yLoc, int nationRecno) townPtr = town_array[i]; - curDistance = misc.points_distance( xLoc, yLoc, townPtr->center_x, townPtr->center_y ); + curDistance = misc.rects_distance(xLoc, yLoc, xLoc, yLoc, townPtr->loc_x1, townPtr->loc_y1, townPtr->loc_x2, townPtr->loc_y2); if( nationRecno && townPtr->nation_recno != nationRecno ) continue; diff --git a/src/OTOWNAI.cpp b/src/OTOWNAI.cpp index 57d9822b..01a4fdce 100644 --- a/src/OTOWNAI.cpp +++ b/src/OTOWNAI.cpp @@ -1253,8 +1253,8 @@ int Town::ai_settle_new(int raceId) //------- it must be within the effective town-to-town distance ---// - if( misc.points_distance( center_x, center_y, xLoc+1+(STD_TOWN_LOC_WIDTH-1)/2, - yLoc+1+(STD_TOWN_LOC_HEIGHT-1)/2 ) > EFFECTIVE_TOWN_TOWN_DISTANCE ) + if( misc.rects_distance(loc_x1, loc_y1, loc_x2, loc_y2, xLoc, yLoc, xLoc+STD_TOWN_LOC_WIDTH-1, + yLoc+STD_TOWN_LOC_HEIGHT-1) > EFFECTIVE_TOWN_TOWN_DISTANCE ) { return 0; } @@ -1778,23 +1778,45 @@ int Town::think_scout() //-------------------------------------------// - int destX, destY; + int destX, destY, dir; - if( misc.random(2)==0 ) - destX = center_x + 50 + misc.random(50); - else - destX = center_x - 50 - misc.random(50); - - if( misc.random(2)==0 ) - destY = center_y + 50 + misc.random(50); - else - destY = center_y - 50 - misc.random(50); + dir = misc.random(4); - destX = MAX(0, destX); - destX = MIN(MAX_WORLD_X_LOC-1, destX); - - destY = MAX(0, destY); - destY = MIN(MAX_WORLD_Y_LOC-1, destY); + switch(dir) + { + case 0: + destX = misc.random(MAX_WORLD_X_LOC-1-20) + 10; + if( center_x - destX > 100 ) + destX = center_x - (center_x - destX) % 100; + if( destX - center_x > 100 ) + destX = center_x + (destX - center_x) % 100; + destY = MAX(center_y-100,10); + break; + case 1: + destX = MIN(center_x+100,MAX_WORLD_X_LOC-1-10); + destY = misc.random(MAX_WORLD_Y_LOC-1-20) + 10; + if( center_y - destY > 100 ) + destY = center_y - (center_y - destY) % 100; + if( destY - center_y > 100 ) + destY = center_y + (destY - center_y) % 100; + break; + case 2: + destX = misc.random(MAX_WORLD_X_LOC-1-20) + 10; + if( center_x - destX > 100 ) + destX = center_x - (center_x - destX) % 100; + if( destX - center_x > 100 ) + destX = center_x + (destX - center_x) % 100; + destY = MIN(center_y+100,MAX_WORLD_Y_LOC-1-10); + break; + case 3: + destX = MAX(center_x-100,10); + destY = misc.random(MAX_WORLD_Y_LOC-1-20) + 10; + if( center_y - destY > 100 ) + destY = center_y - (center_y - destY) % 100; + if( destY - center_y > 100 ) + destY = center_y + (destY - center_y) % 100; + break; + } ownNation->add_action( destX, destY, loc_x1, loc_y1, ACTION_AI_SCOUT, 0); diff --git a/src/OTOWNIND.cpp b/src/OTOWNIND.cpp index 5836ede2..ed0f0f36 100644 --- a/src/OTOWNIND.cpp +++ b/src/OTOWNIND.cpp @@ -280,6 +280,8 @@ int Town::form_new_nation() break; } + nation_array.update_statistic(); + return nationRecno; } //----------- End of function Town::form_new_nation ---------// diff --git a/src/OUNIT.cpp b/src/OUNIT.cpp index 988bd440..dae97894 100644 --- a/src/OUNIT.cpp +++ b/src/OUNIT.cpp @@ -2445,8 +2445,8 @@ void Unit::del_team_member(int unitRecno) // are any units with hit_points <= 0, delete them. // // Those unit may just be killed, so soon that the Unit's set_die() -// function hsa been called yet. validate_team() function must -// be called before all issunig any new team actions. +// function hasn't been called yet. The validate_team() function must +// be called before issuing any new team actions. // void Unit::validate_team() { diff --git a/src/OUNITAC.cpp b/src/OUNITAC.cpp index dca943a9..d8d4907c 100644 --- a/src/OUNITAC.cpp +++ b/src/OUNITAC.cpp @@ -476,7 +476,7 @@ void Unit::assign(int assignXLoc, int assignYLoc, short curAssignUnitNum) return; //----------- BUGHERE : cannot assign when on a ship -----------// - err_when(!is_visible()) + err_when(!is_visible()); if(!is_visible()) return; diff --git a/src/OUNITAT.cpp b/src/OUNITAT.cpp index a1c32610..e3c8b6ad 100644 --- a/src/OUNITAT.cpp +++ b/src/OUNITAT.cpp @@ -178,13 +178,13 @@ void Unit::hit_target(Unit* parentUnit, Unit* targetUnit, float attackDamage, sh { if( targetNationRecno ) { - targetNationPtr->civilian_killed(targetUnit->race_id, 0); + targetNationPtr->civilian_killed(targetUnit->race_id, 0, 1); targetNationPtr->own_civilian_killed++; } if( parentNationPtr ) { - parentNationPtr->civilian_killed(targetUnit->race_id, 1); + parentNationPtr->civilian_killed(targetUnit->race_id, 1, 1); parentNationPtr->enemy_civilian_killed++; } } @@ -192,13 +192,13 @@ void Unit::hit_target(Unit* parentUnit, Unit* targetUnit, float attackDamage, sh { if( targetNationRecno ) { - targetNationPtr->civilian_killed(targetUnit->race_id, 0); + targetNationPtr->civilian_killed(targetUnit->race_id, 0, 0); targetNationPtr->own_civilian_killed++; } if( parentNationPtr ) { - parentNationPtr->civilian_killed(targetUnit->race_id, 0); + parentNationPtr->civilian_killed(targetUnit->race_id, 1, 0); parentNationPtr->enemy_civilian_killed++; } } @@ -243,10 +243,10 @@ void Unit::hit_target(Unit* parentUnit, Unit* targetUnit, float attackDamage, sh { // Race-Id of 0 means a loyalty penalty applied for all races if( targetNationRecno ) - targetNationPtr->civilian_killed(0, -1); + targetNationPtr->civilian_killed(0, 0, 3); if( parentNationPtr ) - parentNationPtr->civilian_killed(0, 3); + parentNationPtr->civilian_killed(0, 1, 3); } } @@ -394,8 +394,7 @@ void Unit::unit_auto_guarding(Unit *attackUnit) changeToAttack++; //else continue to attack the target unit else { - err_when(!action_para); - if(unit_array.is_deleted(action_para)) + if(!action_para || unit_array.is_deleted(action_para)) changeToAttack++; // attack new target } } diff --git a/src/OUNITAT2.cpp b/src/OUNITAT2.cpp index 60a66bd0..ad4ea5e1 100644 --- a/src/OUNITAT2.cpp +++ b/src/OUNITAT2.cpp @@ -259,7 +259,6 @@ void Unit::attack_unit(short targetRecno, int xOffset, int yOffset, int resetBlo { //------------ old order ------------// err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); - err_when(action_mode==ACTION_ATTACK_UNIT && !action_para); if(cur_action!=SPRITE_IDLE) { diff --git a/src/OUNITHB.cpp b/src/OUNITHB.cpp index dcbfeb0f..314e029b 100644 --- a/src/OUNITHB.cpp +++ b/src/OUNITHB.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef NO_DEBUG_UNIT #undef err_when @@ -261,7 +262,10 @@ void Unit::handle_blocked_move_s11(Unit *unitPtr) } else if((unitPtr->next_x_loc() != move_to_x_loc || unitPtr->next_y_loc() != move_to_y_loc) && (unitPtr->cur_action==SPRITE_IDLE && unitPtr->action_mode2==ACTION_STOP)) - move_to_my_loc(unitPtr); // push the blocking unit and exchange their destination + if( config_adv.fix_path_blocked_by_team ) + handle_blocked_by_idle_unit(unitPtr); + else + move_to_my_loc(unitPtr); // push the blocking unit and exchange their destination else if(unitPtr->action_mode == ACTION_SETTLE) set_wait(); // wait for the settler else if(waiting_term>MAX_WAITING_TERM_SAME) diff --git a/src/OUNITI.cpp b/src/OUNITI.cpp index d2565e32..347bb79b 100644 --- a/src/OUNITI.cpp +++ b/src/OUNITI.cpp @@ -206,14 +206,12 @@ void Unit::process_idle() } err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); - err_when(action_mode==ACTION_ATTACK_UNIT && action_para==0); //--------- reactivate action -----------// if(reactivate_idle_action()) { err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); - err_when(action_mode==ACTION_ATTACK_UNIT && action_para==0); return; // true if an action is reactivated } @@ -239,7 +237,6 @@ void Unit::process_idle() //-**************** simulate aat ********************-// err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); - err_when(action_mode==ACTION_ATTACK_UNIT && action_para==0); //----------- for ai unit idle -----------// @@ -251,7 +248,6 @@ void Unit::process_idle() err_when(!can_attack()); err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); - err_when(action_mode==ACTION_ATTACK_UNIT && action_para==0); //--- only detect attack if in aggressive mode or the unit is a monster ---// @@ -264,12 +260,10 @@ void Unit::process_idle() if( idle_detect_attack() ) { err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); - err_when(action_mode==ACTION_ATTACK_UNIT && action_para==0); return; // target detected } err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK); - err_when(action_mode==ACTION_ATTACK_UNIT && action_para==0); } //------------------------------------------------------------------// diff --git a/src/OUNITM.cpp b/src/OUNITM.cpp index 2b30860f..d92d656c 100644 --- a/src/OUNITM.cpp +++ b/src/OUNITM.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef NO_DEBUG_UNIT #undef err_when @@ -654,8 +655,13 @@ int Unit::search(int destXLoc, int destYLoc, int preserveAction, short searchMod // void Unit::select_search_sub_mode(int sx, int sy, int dx, int dy, short nationRecno, short searchMode) { - //seek_path.set_sub_mode(); // cancel the selection - //return; + if( !config_adv.unit_allow_path_power_mode ) + { + // cancel the selection + seek_path.set_sub_mode(); + seek_path_reuse.set_sub_mode(); + return; + } err_when(mobile_type!=UNIT_LAND); diff --git a/src/OU_GOD.cpp b/src/OU_GOD.cpp index 1f4e240b..c9377a51 100644 --- a/src/OU_GOD.cpp +++ b/src/OU_GOD.cpp @@ -290,6 +290,9 @@ void UnitGod::cast_power(int xLoc, int yLoc) { err_when( !god_res[god_id]->can_cast_power ); + if( firm_array.is_deleted(base_firm_recno) ) + return; + //------- consumer pray points --------// /* This must be done here to avoid an exploit where a human player * can cast an ability and then order the god to move within a @@ -297,7 +300,8 @@ void UnitGod::cast_power(int xLoc, int yLoc) * used for the Chinese and Norman dragons so the function is also * called in UnitGod::process_attack() for the dragons. */ - consume_power_pray_points(); + if( !consume_power_pray_points() ) + return; //---- viking god does not need a range for casting power ----// @@ -678,26 +682,25 @@ void UnitGod::maya_cast_power(Worker* workerPtr, int nationRecno, int divider) //--------- Begin of function UnitGod::consume_power_pray_points ---------// // -void UnitGod::consume_power_pray_points() +// return one if points consumed, otherwise zero. +// +int UnitGod::consume_power_pray_points() { + if( firm_array.is_deleted(base_firm_recno) ) + return 0; + FirmBase* firmBase = (FirmBase*) firm_array[base_firm_recno]; err_when( firmBase->firm_id != FIRM_BASE ); - //--- if the seat of power supporting this unit is destroyed, this unit dies ---// - - if( !firmBase ) - { - hit_points = (float)0; - return; - } - firmBase->pray_points -= god_res[god_id]->power_pray_points; if( firmBase->pray_points < 0 ) firmBase->pray_points = (float) 0; hit_points = (short) firmBase->pray_points; + + return 1; } //---------- End of function UnitGod::consume_power_pray_points ----------// diff --git a/src/OU_MARIT.cpp b/src/OU_MARIT.cpp index 74908ea6..211650fe 100644 --- a/src/OU_MARIT.cpp +++ b/src/OU_MARIT.cpp @@ -382,6 +382,8 @@ void UnitMarine::pre_process() if(curXLocloc_x1-moveStep || curXLoc>firmPtr->loc_x2+moveStep || curYLocloc_y1-moveStep || curYLoc>firmPtr->loc_y2+moveStep) { + if(!is_visible()) + return; // may get here if player manually ordered ship to dock //### begin alex 6/10 ###// /*if((move_to_x_loc>=firmPtr->loc_x1-moveStep || move_to_x_loc<=firmPtr->loc_x2+moveStep) && (move_to_y_loc>=firmPtr->loc_y1-moveStep || move_to_y_loc<=firmPtr->loc_y2+moveStep)) diff --git a/src/OVGA.cpp b/src/OVGA.cpp index 36a0583b..f5fdca5c 100644 --- a/src/OVGA.cpp +++ b/src/OVGA.cpp @@ -439,7 +439,7 @@ void Vga::handle_messages() real_x = bound_x1; logical_x = mouse.bound_x1; } - else if( real_x >= bound_x2 ) + else if( real_x > bound_x2 ) { do_warp = 1; real_x = bound_x2; @@ -451,7 +451,7 @@ void Vga::handle_messages() real_y = bound_y1; logical_y = mouse.bound_y1; } - else if( real_y >= bound_y2 ) + else if( real_y > bound_y2 ) { do_warp = 1; real_y = bound_y2; @@ -547,6 +547,9 @@ void Vga::handle_messages() case SDL_TEXTINPUT: mouse.add_typing_event(event.text.text, misc.get_time()); break; + case SDL_RENDER_TARGETS_RESET: + sys.need_redraw_flag = 1; + break; case SDL_TEXTEDITING: case SDL_JOYAXISMOTION: case SDL_JOYBALLMOTION: @@ -554,7 +557,7 @@ void Vga::handle_messages() case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: default: - MSG("unhandled event %d\n", event.type); + MSG("unhandled event %x\n", event.type); break; } } diff --git a/src/OWORLD.cpp b/src/OWORLD.cpp index 158703f3..d957236e 100644 --- a/src/OWORLD.cpp +++ b/src/OWORLD.cpp @@ -1336,8 +1336,8 @@ void World::draw_link_line(int srcFirmId, int srcTownRecno, int srcXLoc1, //-------- check the distance --------// - if( misc.points_distance( townPtr->center_x, townPtr->center_y, - srcXLoc, srcYLoc ) > effectiveDis ) + if( misc.rects_distance(townPtr->loc_x1, townPtr->loc_y1, townPtr->loc_x2, townPtr->loc_y2, + srcXLoc1, srcYLoc1, srcXLoc2, srcYLoc2) > effectiveDis ) { continue; } @@ -1396,8 +1396,8 @@ void World::draw_link_line(int srcFirmId, int srcTownRecno, int srcXLoc1, //-------- check the distance --------// - if( misc.points_distance( firmPtr->center_x, firmPtr->center_y, - srcXLoc, srcYLoc ) > effectiveDis ) + if( misc.rects_distance(firmPtr->loc_x1, firmPtr->loc_y1, firmPtr->loc_x2, firmPtr->loc_y2, + srcXLoc1, srcYLoc1, srcXLoc2, srcYLoc2) > effectiveDis ) { continue; } @@ -2176,6 +2176,7 @@ uint8_t World::get_region_id(int xLoc, int yLoc) // ####### begin Gilbert 25/7 #########// // return true if any location adjacent to (x,y) is on a particular region +// jesse May 7, 2023: this used to be used in Nation::ai_build_harbor but now replaced with is_harbor_region() int World::is_adjacent_region(int x, int y, int regionId) { if( y > 0 ) @@ -2221,3 +2222,29 @@ int World::is_adjacent_region(int x, int y, int regionId) return 0; } // ####### end Gilbert 25/7 #########// + + +//--------- Begin of function World::is_harbor_region --------// +// +// return true selected build location is in the designated regions +int World::is_harbor_region(int xLoc, int yLoc, int landRegionId, int seaRegionId) +{ + if( xLoc+2 >= max_x_loc || yLoc+2 >= max_y_loc ) + return 0; + + int x,y; + for( y = 0; y < 3; y++ ) + { + for( x = 0; x < 3; x++ ) + { + int regionId = get_region_id( xLoc+x, yLoc+y ); + if( regionId != landRegionId && + regionId != seaRegionId ) + { + return 0; + } + } + } + return 1; +} +//----------- End of function World::is_harbor_region --------// diff --git a/tools/libdb b/tools/libdb index 856b1c09..3d051105 100755 --- a/tools/libdb +++ b/tools/libdb @@ -31,8 +31,12 @@ use File::Spec; use dbf; if (@ARGV < 5) { - print "Usage: $0 ptr.dbf file.res input_dir filename_field ptr_field file_ext\n"; - print "Puts all files defined by dbf in res. Input_dir must have all the files.\n"; + print <