diff --git a/.gitignore b/.gitignore index 844d529f4..226738946 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ .cache +debian/tmp/* +gmon.* +valgrind.* debian/*.debhelper debian/*.log debian/*.substvars diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f2fee2a1..0a5ec4ff1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,7 @@ # Stratagus major version set(STRATAGUS_MAJOR_VERSION 3) # Stratagus minor version (maximum 99) -set(STRATAGUS_MINOR_VERSION 2) +set(STRATAGUS_MINOR_VERSION 3) # Stratagus patch level (maximum 99) set(STRATAGUS_PATCH_LEVEL 1) # Stratagus patch level 2 diff --git a/debian/changelog b/debian/changelog index 4ae50e339..e5b564473 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,334 @@ -stratagus (3.2.1) UNRELEASED; urgency=medium +stratagus (3.3.1) UNRELEASED; urgency=medium - * + [ Tim Felgentreff ] + * fix potential crash in editor with dynamic load + * ony draw references on units with debug print + * fix wrong assert, compilation on ubuntu 22.04 - -- Tim Felgentreff Sat, 25 Dec 2021 06:45:52 +0100 + [ Northfear ] + * Fix build with enabled DYNAMIC_LOAD + + -- Tim Felgentreff Sat, 30 Jul 2022 13:22:22 +0200 + +stratagus (3.3.0) focal; urgency=medium + + [ Alex Grant Benedict ] + * Update stratagus-tinyfiledialogs.h + + [ Tim Felgentreff ] + * On windows, prefer stratagus from PATH over registry + + [ Alyokhin ] + * Fixed fog for non-square maps + + [ Tim Felgentreff ] + * workaround a few crashes in the online service + * add password flag to text fields + * HACK: make ctrl+keys work again in guichan + * add a lua function to restart the game + * guard against potential crashes due to bad lua coding of menus + * allow immediate reconnect to online service + * guard against lost network callbacks + * return success/failure from LoadStratagusMapInfo + * compile with c++17 filesystem support + * implement transmitting maps from server to client during join + * fix idle crash when online + * expose full file path in __file__; add disabled filesystem listing lua function + * allow unit selection in editor + * use ChangeOwner in SetUnitVariable(..."Player") + * add ability to change unit color in SetUnitVariable + * editor fixes + * add CopyUnitType function + * fix SetUnitVariable("Color") + * add GiveUnitsToPlayer function + * use lookup tables for cp437 and cp866 font graphics + * add support for mapping between codepages + + [ Simone Starace ] + * Changed the body of function ChangeUnitsOwner. + + [ Tim Felgentreff ] + * better docs for SetFontCodePage + * avoid useless utf8 work for numbers + * update codepoint mapping to allow multichar subst + * rename mobdebug.h, not a real header + * allow setting NumBounces for missile-clip-to-target + * draw missile cliptotarget centered on top left corner of target + * add animated sprite decoration + * add button check units-nor and fix CopyUnitType + * fix walls disappearing when changing surroundings + * use sdl hardware cursor to decouple the cursor speed from the game speed + * fix cursor drawing, now only the offset may be wrong + * fix mouse event coordinates for vertical pixel stretching + * make hardware cursor a preference + * fix scaled cursor hot pos + * deselect for list boxes + * try to clean up a bit better + * allow using bool flags for enable/disable decoration + * a bit more configurability for the decoration bar + * fix one more potential crash with font rendering + * add option to indicate damage in selection rect + * only show group if ShowOrders is true + * Make max messages configurable with SetMaxMessageCount and rework repeated message handling + * add a simple function to copy unit buttons to another unit + * add ability to set completely custom Colors for a unit + * add ability to define additional colors and set custom unit color + * fix a class of potential NPEs + * fix a crash in select script functions + * first attempt at a "randomizer" tool for the editor + * fix memory leak, thanks @Andrettin + * improve astar cleanup performance. thanks @Andrettin + * don't return depots unconditionally + * fix start location sticking to cursor + * tweak map randomize + * be backwards compatible with war1gus colorsets + * make randomize editor feature configurable + * add import + * expose Randomize map to lua + * Revert "improve astar cleanup performance. thanks @Andrettin" + * Revert "don't return depots unconditionally" + * tweak map randomization + * fix two potential crashes + * Revert "Revert "don't return depots unconditionally"" + * Revert "Revert "improve astar cleanup performance. thanks @Andrettin"" + * better random for random maps + * Add FindNextResource lua function + * make free workers icon clickable and hideable when no free workers available + * pause game when network is out of sync + * improve UnitDump logging + * improve logging of network out of sync + * SyncHash change logging + * ask for port for easy multiplayer debugging + * reduce backtrace size + * dump unit debug in dev launch + * more debugging and sync hashing + * sort the CUnit::Init variables as in the header + * workaround for not finding depot from mine + * port depot finder change from Wyrmgus that searches from outside mine + * add disabled astar overlay + * disable a bit of the extra much logging again + + [ sviscapi ] + * Changed boolean into bool in online_service.cpp + + [ Tim Felgentreff ] + * reuse game structures in replay types + * delete metaserver + * WIP: start unifying all GameSettings + * doc update for SetPlayerData + * fix SettingsPresets#Init + * more room for backtrace + * fix replay refactpring + * fix team assignments again + * fix build issues on linux + * don't use enum class until we remove tolua++ + * always use vendored lua + * cleanups + * make changes work with tolua++, trying to be backwards compatible + * since FoV is relevant for sync, make it part of GameSettings + * move sync-relevant preferences into GameSettings + * debugprint game settings, fix sign of some settings + * give games the opportunity to store custom settings in GameSettings that get synced across the network + * ensure we store team preferences in replay and always re-init GameSettings with user preferences where applicable + * Revert "always use vendored lua" + * AiChecksDependencies is now synced across network clients + * don't autosave during replay + * always use network command queue, even in single player, for replays to work + * fix wrong assert + * fixed another assert problem when game is cleaning up + + [ alyokhin ] + * fix compile error for gcc version >9.3.0 + + [ Tim Felgentreff ] + * dirty expansion to multiplayer random placement option + * fix server setup message size + * new idea for player order pref + * simplify network code + * ignore linux build + * fix game start, also serialize presets in server state + * fix wrong bounds for network commands after refactoring + * debug: try building with v142 toolset + * drop XP support from settings file + * show it as training when building from outside + * fix diagonal rule checks for buildings + * cancel building when building from outside and stopping + * make sure we cannot build nonsolid decorative buildings on water + * compact host array before game start + * send the new client index out to clients after compacting host array + * allow grayscale graphic loading + * debug print replay settings + * fix and document player team assignement via presets + * use references instead of copy of hosts + * avoid vectors as public static global members + * expose the boolean flags that moved to GameSettings + * set shared vision for teamed players + * newline in lua DebugPrint + * make SaveReplay work again + * minimum fix for "static initializer fiasco" + * don't reset NumDirections and Flip + * use std::bitset for user settings manipulation + * more flexibile default tile index + * implement terrain harvesting of other resources than wood. + * add "non-mixing" flag for solid tiles that don't need mixing + * ignore building rules when not in game (i.e. editor) + * don't count more than 10 repeats of a message + * fix checking of resource for terrain resources + * show buttons from *the* neutral player 16 + * push clicking player into button callback action + * allow terrain harvesters to return resources early + * fix outside builder for buildings + * make popups accept functions + * allow plain graphic as panel content + * 1-based player index for users + * add option for ellipse selection with y-stretch factor + * fix compiler warning + * make color cycling speed configurable + * make scroll margins configurable + * fix editor ui bug with 5x5 cursor + * fix transports getting stuck during unloading. fixes https://github.com/Wargus/wargus/issues/121 + * simplify upgrade_to check, give back resources when upgrade fails. fixes https://github.com/Wargus/wargus/issues/172 + * play shore sound only when really docking/undocking + * minor fix for transporter pathing + * use an external command to play midi music on windows + * exe name fix + * ship midiplayer to clients + * minor cleanup for movie playing + * let midiplayer work with non-standard windows midi + * fix linux build + * add some more flexibility for live reloading of ui, allow using frames in panel graphics + * fix negative condition for panel content on variable value + * fix a crash + * add a wiggle animation for ships and planes to have sub-tile movement + * fixup last commit + * Expose unit variables PosBottom and PosRight + * allow rotating towards building unit, take displacement into account + * implement displacement move towards a unit + * use GetDrawLevel() for map drawing order calculation + * fix potential crash when portraits are used, draw portrait of first selected unit in group + * add support for different icons drawn based on health for single, multi, and transport selection + * allow content type icon to select icon kind (group, single, button, transport) + * fix mng constructor + * add "talking" as a tag in portrait definitions to show when unit is playing sound + * add support for UI.DefaultUnitPortrait to draw when no selection is active + * do not randomly play talking animations + + [ Simone Starace ] + * Bold text on some examples. + * Added examples in shaders.cpp + + [ Tim Felgentreff ] + * use 32-bit alpha for fancy shadows + + [ Simone Starace ] + * Added more example codes for units scripts. + + [ Tim Felgentreff ] + * new code for palette changes in icons based on unit variables + * support alternative spritesheet for units below 50% health + * add a simple mechanism to combine graphics from lua with overlay/mask + * apply a shearing effect to generated shadows + * add shrinking for shadows + * clean up MakeShadow function a bit + * download/setup stargus + * support size in SDL_RWops from CFile + * share mngs + * let sdl mixer free our sdl_rwops + * allow dynamic load of sounds as well + * make dynamic load the default to start up faster + * don't overallocate mng array + * deal with a few minor errors + * make construction lazy loaded as well + * fix lazy loading of mng portraits + * keep units in transports sorted by size and give them space in UI + * fix ordering of units in transports by size + * extract arg quoting for iwndows + * make midiplayer more fancy with pipes for communication + * add missing stargus json + * download magick executable + * fix icon color palette swaps not being swapped back to default + * add assertions to avoid crash with wrongly indexed graphics + * update generate_index script to create api definition + * add a todo + * fix potential crash + * fix wrong assert + * fix missing semicolon + * make generated api better + * cache mapping of strings to filenames + * avoid runtime conversion to SDL_Color for font colors + * cache SDL colors for player colors at beginning of the game + * add simple benchmarking option + * fix a crash when freeing dynamically loaded sounds + * nicer fps bar + * set callback immediately when playing, not delayed + * port Wyrmgus change to FormatNumber, which has better performance + * fix a bunch of clang warnings + * make compilation without openmp work + * also build shared libraries of vendored lua + * fix omp_get_thread_num stub + * explicit sound channel initialization + * openmp cmake option + * add gprof linker flag + * make unit manager a global pointer, not a static global + * make FogOfWar a global pointer, not a static global + * check automatic attacks/spells fewer times to avoid performance penalty of AStar each cycle + * make vendored lua also work on windows + * dispatch audio callbacks to the event loop + * fixup failing music callback - don't let music play failure spam the event queue + * don't wait for vsync in benchmark mode + * allocate tileset on map creation, not statically + * fix lazy mng loading + * hackaround for mng free bug + * fix exit when no map was created + * make full black in mngs be transparent + * don't waste time drawing map tiles below fog of war + * fix debug printing with dummy renderer + * fix swapped mng sizes + * fix compile error + * fix wrong condition for mng lazy loading + * fix invalid sharing of mngs in copied unit type + * mng widgets are always dirty + * fix potential crash when lazily loading a sound that doesn't exist + * delete manually allocated UnitManager and FogOfWar + * expose Mng.MaxFPS to lua to set the max playback speed for mngs + * fix compilation without Mng support + * minor usability improvement for panel conditions + * no assert/debugprint in release builds + * XXX: do not crash on exit + * improve performance of AiEnemyUnitsInDistance + * reduce load on AI cycles by limiting how many forces may scan the map in one cycle + * change astar reset optimization to instead rely on memory alignment and the compiler optimizations for memset/memmove on aligned memory chunks with modern CPUs + * make max iterations for astar configurable + * comment unused cpu feature test code, align 512bits for AVX-512 + * report benchmark results with cycles + * no assert/debugprint in release builds + * XXX: do not crash on exit + * re-enable simd test functions + * re-order to fix compilation + * start skipping frames when we are too slow + * fix typo + * more frame skipping, to work decently on rpi without accelleration + * avoid free-cycle + + [ Sebastien Alaiwan ] + * Cleanup: dead local variables + * genversion: fix minor memory leak + + [ Tim Felgentreff ] + * minor tweaks to micro-optimize performance for really slow machines + * fix potential crash on map load + * add workaround for potential crash on load + * Revert "XXX: do not crash on exit" + * Revert "no assert/debugprint in release builds" + * make frame skip a preference + * fix loading games with units in containers that do not have a type yet + * move tileset allocation to the explicit list of globals allocated in stratagusMain + * fix accidental double-free + * (i think) fix an assertion + * fix crash when graphic for flipped missile is loaded already as sprite + * add a bit of documentation about complex map building + + -- Tim Felgentreff Wed, 27 Jul 2022 14:16:51 +0200 stratagus (3.2.0) focal; urgency=medium diff --git a/debian/copyright b/debian/copyright index ccfcb735a..b710aac87 100644 --- a/debian/copyright +++ b/debian/copyright @@ -6,11 +6,11 @@ Copyright: © 2004 David Martínez Moreno © 2010-2012 Pali Rohár © 2015 cybermind - © 2016-2021 Tim Felgentreff + © 2016-2022 Tim Felgentreff License: GPL-2+ Files: * - © 1998-2021 by The Stratagus Project, including, among others: + © 1998-2022 by The Stratagus Project, including, among others: Jimmy Salmon Russel Smith Nehal Mistry diff --git a/doc/BuildingComplexMaps.md b/doc/BuildingComplexMaps.md new file mode 100644 index 000000000..a0c2e73a8 --- /dev/null +++ b/doc/BuildingComplexMaps.md @@ -0,0 +1,137 @@ +# Building Complex Maps + +The Stratagus engine is very flexible when it comes to custom maps, even though +most of the flexibility is not exposed in the map editor. This document aims to +provide a bit of guidance if you want to create custom missions with complex +setups, triggers, and/or objectives. + +## 1. Build the map in the map editor + +#### 1.1 Create the basics + +The first step should be to build the basic map in the map editor. This includes +setting up how many factions you need and of which colors, their units, the +terrain etc. Basically, anything that can be done in the editor, should be done +in the editor + +#### 1.2 Touch up appearances + +The map editor comes with a feature to draw "decoration" tiles, that is, to draw +tiles without automatically changing and adjusting the tiles around it. This +feature is really for the last touch ups, since afterwards the tiles cannot be +reverted to automatic updates from the UI. So, if you are sure you are done with +the terrain, you can use this touch-up feature to draw single tiles of specific +variant to have the maximum control over the terrain. + +## 2. Adapt the Scripts + +A map is saved into two files a `.smp` and a `.sms` file. You should not touch +these files. Instead, you can create (if they do not already exist) two +additional files to write custom lua code that can enhance the map when it is +loaded. For example, if your map is called `my_map`, then you would have a file +`my_map.sms` and `my_map.smp`. You can add files `my_map.sms.preamble` and +`my_map.sms.postamble`. The first is loaded *before* the map is loaded (so you +can, for example, change how units are created by changing the definition of the +`CreateUnit` function). The second is loaded *after* the map, so you can add +additional custom events and objectives. Let's talk about this latter case +first. + +#### 2.1 Custom events and objectives + +In-game events and objectives are coded the same way. Open the `.sms.postamble` +file in an editor of your choice. All objectives and events are done using +"Triggers". Triggers are pairs of functions that are run at regular intervals by +the game. A complex victory condition trigger can look like this: + +``` +local victoryTimer = -1 + +AddTrigger( + function() + if GetNumUnitsAt( + GetThisPlayer(), "any", + {Map.Info.MapWidth / 2 - 5, Map.Info.MapHeight / 2 - 5}, + {Map.Info.MapWidth / 2 + 5, Map.Info.MapHeight / 2 + 5}) > 5 then + return true + else + return false + end + end, + function() + AddMessage("5 Units in the center!") + victoryTimer = 10 + return false + end +) + +AddTrigger( + function() + if victoryTimer > 0 then + victoryTimer = victoryTimer - 1 + AddMessage("Time remaining until victory: " .. victoryTimer) + end + return victoryTimer == 0 + end, + function() + return ActionVictory() + end +) +``` + +Let's unpack this. We are defining two triggers. The first function is the +"condition function" of the trigger. The second function is the actual +trigger. The first function is run at regular intervals during the game until it +returns `true`. Only then is the second function run. If the second function +returns `false`, then that trigger will be removed and will never run again. + +The first trigger condition here checks if the number of units of the active +player in the map center (in a 10x10 grid around the map center) is larger +than 5. If this is true, the condition returns true and the second function +runs. The second function shows a message that 5 units are now at the center and +sets the variable `victoryTimer` to 10. + +The second trigger just keeps checking the `victoryTimer` variable. As long as +that variable is less than 0, nothing happens. But when the first trigger has +fired and set the variable to 10, then the second trigger will start counting it +down and show that as an in-game message. Once the `victoryTimer` has counted +down to 0, the condition of the second trigger returns `true` and the action +function runs. The action function in this case just calls `ActionVictory`. What +that means is the game ends with a victory. + +For conditions where the game should be lost, `ActionDefeat` is used. + +Note how powerful this can be. Of course, now we are just using a trigger to +show some message and set a variable, but you could have triggers that spawn or +transform units, change diplomacy, scroll the map somewhere, pause the game and +show an "in-game dialogue", or even change tiles on the map to have something +like a "natural disaster event" that changes the face of the earth. For all the +things you can do, check the Lua functions that are available: +https://stratagus.com/lua_bindings.html + +#### 2.2 Custom alliances + +A common request for complex games is to be able to declare custom alliances, +like some AI players being in a team with the player or player co-op against +AI. This can be achieved using a custom startup function. + +After the game is loaded and everything is ready to start running, Stratagus +calls one last Lua function to do any last minute setup. This Lua function is +`GameStarting`. + +As an example, you can add this to your `.sms.preamble` file: + +``` +local OldGameStarting = GameStarting +function GameStarting() + OldGameStarting() + SetDiplomacy(0, "allied", 2) + SetSharedVision(0, true, 2) + SetDiplomacy(2, "allied", 0) + SetSharedVision(2, true, 0) + GameStarting = OldGameStarting +end +``` + +This will ensure that at the beginning of the game, players 0 and 2 are always +allied. Just as with triggers, all the Lua functions are available to you here, +so anything can be done at this point. diff --git a/src/action/action_attack.cpp b/src/action/action_attack.cpp index 17ececcac..f9f3ed428 100644 --- a/src/action/action_attack.cpp +++ b/src/action/action_attack.cpp @@ -460,12 +460,12 @@ void COrder_Attack::SetAutoTarget(CUnit &unit, CUnit *target) **/ bool COrder_Attack::AutoSelectTarget(CUnit &unit) { - // don't check if we want to switch targets each cycle, once every second is enough + // don't check if we want to switch targets each cycle, but not too rarely either, because then attack-move doesn't work properly anymore if (Sleep > 0) { Sleep -= 1; return true; } - Sleep = CYCLES_PER_SECOND / 2; + Sleep = CYCLES_PER_SECOND / 5; // if unit can't attack, or if unit is not bunkered and removed - exit, no targets if (unit.Type->CanAttack == false diff --git a/src/editor/editloop.cpp b/src/editor/editloop.cpp index 7c6b22fb8..674b1a9f4 100644 --- a/src/editor/editloop.cpp +++ b/src/editor/editloop.cpp @@ -938,6 +938,11 @@ static void DrawStartLocations() const PixelPos startScreenPos = vp->TilePosToScreen_TopLeft(Players[i].StartPos); if (type) { +#ifdef DYNAMIC_LOAD + if (!type->Sprite) { + LoadUnitTypeSprite(*const_cast(type)); + } +#endif DrawUnitType(*type, type->Sprite, i, 0, startScreenPos); } else { // Draw a cross DrawCross(startScreenPos, Map.Tileset->getPixelTileSize(), Players[i].Color); diff --git a/src/include/map.h b/src/include/map.h index 2ed67e0b4..d98d4ad7b 100644 --- a/src/include/map.h +++ b/src/include/map.h @@ -157,6 +157,8 @@ public: CMap(); ~CMap(); + void AllocateTileset(); + unsigned int getIndex(int x, int y) const { return x + y * this->Info.MapWidth; diff --git a/src/include/player.h b/src/include/player.h index 4ee079844..4e90a1511 100644 --- a/src/include/player.h +++ b/src/include/player.h @@ -349,6 +349,7 @@ extern CPlayer Players[PlayerMax]; /// All players extern CPlayer *ThisPlayer; /// Player on local computer extern bool NoRescueCheck; /// Disable rescue check extern std::vector> PlayerColorsRGB; /// Player colors +extern std::vector> PlayerColorsSDL; /// Player colors extern std::vector PlayerColorNames; /// Player color names extern PlayerRace PlayerRaces; /// Player races diff --git a/src/include/stratagus.h b/src/include/stratagus.h index 31315adeb..1c9ead09d 100644 --- a/src/include/stratagus.h +++ b/src/include/stratagus.h @@ -139,22 +139,14 @@ extern void PrintOnStdOut(const char *format, ...); /** ** Assert a condition. If cond is not true abort with file,line. */ -#ifdef DEBUG #define Assert(cond) \ do { if (EnableAssert && !(cond)) { AbortAt(__FILE__, __LINE__, __func__, #cond); }} while (0) -#else -#define Assert(cond) -#endif /** ** Print debug information with function name. */ -#ifdef DEBUG #define DebugPrint(args) \ do { if (EnableDebugPrint) { PrintFunction(); PrintOnStdOut(args); } } while (0) -#else -#define DebugPrint(args) -#endif /*============================================================================ == Definitions diff --git a/src/include/unit.h b/src/include/unit.h index 72c48208e..af9b7de33 100644 --- a/src/include/unit.h +++ b/src/include/unit.h @@ -469,6 +469,8 @@ public: bool HardwareCursor; /// If true, uses the hardware to draw the cursor. Shaders do no longer apply to the cursor, but this way it's decoupled from the game refresh rate bool SelectionRectangleIndicatesDamage; /// If true, the selection rectangle interpolates color to indicate damage + int FrameSkip; /// Mask used to skip rendering frames (useful for slow renderers that keep up with the game logic, but not the rendering to screen like e.g. original Raspberry Pi) + int ShowOrders; /// How many second show orders of unit on map. int ShowNameDelay; /// How many cycles need to wait until unit's name popup will appear. int ShowNameTime; /// How many cycles need to show unit's name popup. diff --git a/src/include/video.h b/src/include/video.h index 1cc9e3ca2..1505e229a 100644 --- a/src/include/video.h +++ b/src/include/video.h @@ -174,7 +174,7 @@ public: // minor programmatic editing features void OverlayGraphic(CGraphic *other, bool mask = false); - inline bool IsLoaded() const { return Surface != NULL; } + inline bool IsLoaded(bool flipped = false) const { return Surface != NULL && (!flipped || SurfaceFlip != NULL); } //guichan virtual void *_getData() const { return Surface; } diff --git a/src/map/map.cpp b/src/map/map.cpp index 98cdb9325..42dccc710 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -327,15 +327,17 @@ CMap::~CMap() delete Tileset; } +void CMap::AllocateTileset() +{ + Assert(!Tileset); + Tileset = new CTileset(); +} + /** ** Alocate and initialise map table */ void CMap::Create() { - if (!Tileset) { - Tileset = new CTileset; - } - Assert(!this->Fields); this->Fields = new CMapField[this->Info.MapWidth * this->Info.MapHeight]; @@ -363,9 +365,7 @@ void CMap::Clean(const bool isHardClean /* = false*/) this->Info.Clear(); this->Fields = NULL; this->NoFogOfWar = false; - if (Tileset) { - this->Tileset->clear(); - } + this->Tileset->clear(); this->TileModelsFileName.clear(); CGraphic::Free(this->TileGraphic); this->TileGraphic = NULL; diff --git a/src/map/minimap.cpp b/src/map/minimap.cpp index da79f1076..30d6df20b 100644 --- a/src/map/minimap.cpp +++ b/src/map/minimap.cpp @@ -501,8 +501,8 @@ void CMinimap::Destroy() MinimapSurface = NULL; } if (MinimapFogSurface && MinimapFogSurface->format != NULL) { - // SDL_FreeSurface(MinimapFogSurface); - MinimapSurface = NULL; + SDL_FreeSurface(MinimapFogSurface); + MinimapFogSurface = NULL; } delete[] Minimap2MapX; Minimap2MapX = NULL; diff --git a/src/map/script_map.cpp b/src/map/script_map.cpp index c276d47c5..acf30c06e 100644 --- a/src/map/script_map.cpp +++ b/src/map/script_map.cpp @@ -836,7 +836,6 @@ static int CclLoadTileModels(lua_State *l) */ static int CclDefineTileset(lua_State *l) { - Map.Create(); Map.Tileset->parse(l); // Load and prepare the tileset diff --git a/src/missile/missile.cpp b/src/missile/missile.cpp index 79879b509..035085965 100644 --- a/src/missile/missile.cpp +++ b/src/missile/missile.cpp @@ -83,7 +83,7 @@ extern NumberDesc *Damage; /// Damage calculation for missile. */ void MissileType::LoadMissileSprite() { - if (this->G && !this->G->IsLoaded()) { + if (this->G && !this->G->IsLoaded(this->Flip)) { this->G->Load(); if (this->Flip) { this->G->Flip(); @@ -495,7 +495,7 @@ static int MissileVisibleInViewport(const CViewport &vp, const Missile &missile) void MissileType::DrawMissileType(int frame, const PixelPos &pos) const { #ifdef DYNAMIC_LOAD - if (!this->G->IsLoaded()) { + if (!this->G->IsLoaded(this->Flip)) { ((MissileType*)this)->LoadMissileSprite(); } #endif @@ -540,7 +540,7 @@ void Missile::DrawMissile(const CViewport &vp) const // FIXME: I should copy SourcePlayer for second level missiles. if (sunit && sunit->Player) { #ifdef DYNAMIC_LOAD - if (!this->Type->G->IsLoaded()) { + if (!this->Type->G->IsLoaded(this->Type->Flip)) { ((MissileType*)this->Type)->LoadMissileSprite(); } #endif diff --git a/src/pathfinder/astar.cpp b/src/pathfinder/astar.cpp index f52f1f3ab..7b33e6d47 100644 --- a/src/pathfinder/astar.cpp +++ b/src/pathfinder/astar.cpp @@ -558,7 +558,7 @@ static inline int CostMoveTo(unsigned int index, const CUnit &unit) } *c = CostMoveToCallBack_Default(index, unit) + 1; #ifdef DEBUG - Assert(c >= 0); + Assert(*c >= 0); #endif return *c - 1; } diff --git a/src/sound/music.cpp b/src/sound/music.cpp index 735af36d4..b443d17bc 100644 --- a/src/sound/music.cpp +++ b/src/sound/music.cpp @@ -63,13 +63,6 @@ bool CallbackMusic; /// flag true callback ccl if stops */ static void MusicFinishedCallback() { - static long MusicCallbackDebounce = 0; - long ticks = SDL_GetTicks(); - if (MusicCallbackDebounce + 1000 < ticks) { - // only accept music finished callbacks for music playing longer than 1s - return; - } - MusicCallbackDebounce = ticks; SDL_Event event; SDL_zero(event); event.type = SDL_SOUND_FINISHED; diff --git a/src/sound/sound_server.cpp b/src/sound/sound_server.cpp index 74ae068e3..3a3c0a361 100644 --- a/src/sound/sound_server.cpp +++ b/src/sound/sound_server.cpp @@ -269,17 +269,10 @@ bool UnitSoundIsPlaying(Origin *origin) */ static void ChannelFinished(int channel) { - static long ChannelCallbackDebounce[MaxChannels] = {0}; if (channel < 0 || channel >= MaxChannels) { fprintf(stderr, "ERROR: Out of bounds channel (how?)\n"); return; } - long ticks = SDL_GetTicks(); - if (ChannelCallbackDebounce[channel] + 200 < ticks) { - // only accept sound finished callbacks for sounds playing longer than 0.2s - return; - } - ChannelCallbackDebounce[channel] = ticks; if (Channels[channel].FinishedCallback != NULL) { SDL_Event event; SDL_zero(event); @@ -387,18 +380,6 @@ static Mix_Music *LoadMusic(const char *name) return currentMusic; } -static Mix_Chunk *LoadSample(const char *name) -{ -#ifdef DYNAMIC_LOAD - Mix_Chunk *r = (Mix_Chunk *)calloc(sizeof(Mix_Chunk), 1); - r->allocated = 0xcafebeef; - r->abuf = (Uint8 *)(strdup(name)); - return r; -#else - return ForceLoadSample(name); -#endif -} - static Mix_Chunk *ForceLoadSample(const char *name) { Mix_Chunk *r = Mix_LoadWAV(name); @@ -414,6 +395,18 @@ static Mix_Chunk *ForceLoadSample(const char *name) return Mix_LoadWAV_RW(f->as_SDL_RWops(), 1); } +static Mix_Chunk *LoadSample(const char *name) +{ +#ifdef DYNAMIC_LOAD + Mix_Chunk *r = (Mix_Chunk *)calloc(sizeof(Mix_Chunk), 1); + r->allocated = 0xcafebeef; + r->abuf = (Uint8 *)(strdup(name)); + return r; +#else + return ForceLoadSample(name); +#endif +} + /** ** Load a music file ** @@ -650,7 +643,7 @@ bool IsMusicEnabled() */ bool IsMusicPlaying() { - return Mix_PlayingMusic(); + return Mix_PlayingMusic() || External_IsPlaying(); } /*---------------------------------------------------------------------------- diff --git a/src/stratagus/player.cpp b/src/stratagus/player.cpp index 98da1e65d..d4eda7003 100644 --- a/src/stratagus/player.cpp +++ b/src/stratagus/player.cpp @@ -398,6 +398,7 @@ void FreePlayerColors() Players[i].ClearUnitColors(); } PlayerColorsRGB.clear(); + PlayerColorsSDL.clear(); } /** @@ -1303,10 +1304,8 @@ void GraphicPlayerPixels(int colorIndex, const CGraphic &sprite) */ void SetPlayersPalette() { - PlayerColorsSDL.clear(); for (int i = 0; i < PlayerMax; ++i) { Players[i].SetUnitColors(PlayerColorsRGB[i]); - PlayerColorsSDL.push_back(std::vector(PlayerColorsRGB[i].begin(), PlayerColorsRGB[i].end())); } } diff --git a/src/stratagus/script_player.cpp b/src/stratagus/script_player.cpp index ade5c0427..731c3544b 100644 --- a/src/stratagus/script_player.cpp +++ b/src/stratagus/script_player.cpp @@ -868,6 +868,7 @@ static int CclDefinePlayerColors(lua_State *l) if (nargs < 2 || LuaToBoolean(l, 2)) { PlayerColorNames.clear(); PlayerColorsRGB.clear(); + PlayerColorsSDL.clear(); if (args / 2 < PlayerMax - 1) { // accept no color for neutral player LuaError(l, "You need to define at least %d colors" _C_ PlayerMax - 1); } @@ -896,6 +897,7 @@ static int CclDefinePlayerColors(lua_State *l) lua_pop(l, 1); } PlayerColorsRGB.push_back(newColors); + PlayerColorsSDL.push_back(std::vector(newColors.begin(), newColors.end())); } if (defaultNeutralPlayer) { @@ -906,6 +908,7 @@ static int CclDefinePlayerColors(lua_State *l) neutralColors.push_back(neutralColor); } PlayerColorsRGB.push_back(neutralColors); + PlayerColorsSDL.push_back(std::vector(neutralColors.begin(), neutralColors.end())); } return 0; @@ -936,6 +939,7 @@ static int CclDefinePlayerColorIndex(lua_State *l) PlayerColorIndexCount = LuaToNumber(l, 2); PlayerColorsRGB.clear(); + PlayerColorsSDL.clear(); return 0; } diff --git a/src/stratagus/stratagus.cpp b/src/stratagus/stratagus.cpp index 9748f71a5..b2a819a4f 100644 --- a/src/stratagus/stratagus.cpp +++ b/src/stratagus/stratagus.cpp @@ -405,7 +405,7 @@ void Exit(int err) FreeButtonStyles(); FreeAllContainers(); freeGuichan(); - fprintf(stdout, "Frames %lu, Slow frames %d = %ld%%\n", + fprintf(stdout, "Frames %lu, Slow frames %ld = %ld%%\n", FrameCounter, SlowFrameCounter, (SlowFrameCounter * 100) / (FrameCounter ? FrameCounter : 1)); lua_settop(Lua, 0); @@ -752,6 +752,8 @@ int stratagusMain(int argc, char **argv) InitMusic(); } + // init globals + Map.AllocateTileset(); UnitManager = new CUnitManager(); FogOfWar = new CFogOfWar(); diff --git a/src/tolua/unit.pkg b/src/tolua/unit.pkg index a51535f21..c1946ed86 100644 --- a/src/tolua/unit.pkg +++ b/src/tolua/unit.pkg @@ -37,6 +37,8 @@ class CPreference bool HardwareCursor; bool SelectionRectangleIndicatesDamage; + unsigned int FrameSkip; + unsigned int ShowOrders; unsigned int ShowNameDelay; unsigned int ShowNameTime; diff --git a/src/unit/script_unit.cpp b/src/unit/script_unit.cpp index 75537667b..9e219e3ed 100644 --- a/src/unit/script_unit.cpp +++ b/src/unit/script_unit.cpp @@ -331,6 +331,7 @@ static int CclUnit(lua_State *l) } CUnit *unit = &UnitManager->GetSlotUnit(slot); + bool hadType = unit->Type != NULL; CUnitType *type = NULL; CUnitType *seentype = NULL; CPlayer *player = NULL; @@ -645,6 +646,15 @@ static int CclUnit(lua_State *l) MapMarkUnitSight(*unit); } + if (!hadType && unit->Container) { + // this unit was assigned to a container before it had a type, so we + // need to actually add it now, since only with a type do we know the + // BoardSize it takes up in the container + CUnit *host = unit->Container; + unit->Container = NULL; + unit->AddInContainer(*host); + } + return 0; } diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp index 9c57f915b..5e2b837c1 100644 --- a/src/unit/unit.cpp +++ b/src/unit/unit.cpp @@ -377,7 +377,7 @@ extern int ExtraDeathIndex(const char *death); */ void CUnit::RefsIncrease() { - Assert(Refs && !Destroyed); + Assert(!Refs || (Refs && !Destroyed)); if (!SaveGameLoading) { ++Refs; } @@ -1093,16 +1093,21 @@ void CUnit::AddInContainer(CUnit &host) { Assert(Container == NULL); Container = &host; + if (!Type) { + // if we're loading a game, the Type may not have been initialized + // yet. so we ignore this and the unit gets added later when it is + // loaded via CclUnit + return; + } if (host.InsideCount == 0) { NextContained = PrevContained = this; host.UnitInside = this; } else { // keep sorted by size. - // FIXME: if we're loading a game, the Type may not have been initialized yet!! - int mySize = Type ? Type->BoardSize : 1; + int mySize = Type->BoardSize; NextContained = host.UnitInside; bool becomeFirst = true; - while (NextContained->Type ? NextContained->Type->BoardSize : 1 > mySize) { + while (NextContained->Type->BoardSize > mySize) { becomeFirst = false; NextContained = NextContained->NextContained; if (NextContained == host.UnitInside) { diff --git a/src/unit/unit_draw.cpp b/src/unit/unit_draw.cpp index bed37b5e3..f7eecdad8 100644 --- a/src/unit/unit_draw.cpp +++ b/src/unit/unit_draw.cpp @@ -630,7 +630,9 @@ static void DrawDecoration(const CUnit &unit, const CUnitType &type, const Pixel int y = screenPos.y; #ifdef DEBUG // Show the number of references. - CLabel(GetGameFont()).DrawClip(x + 1, y + 1, unit.Refs); + if (EnableDebugPrint) { + CLabel(GetGameFont()).DrawClip(x + 1, y + 1, unit.Refs); + } #endif UpdateUnitVariables(const_cast(unit)); diff --git a/src/video/sdl.cpp b/src/video/sdl.cpp index 7c8269d20..f956484a8 100644 --- a/src/video/sdl.cpp +++ b/src/video/sdl.cpp @@ -719,9 +719,6 @@ const EventCallback *GetCallbacks() return Callbacks; } -static int SkipFrameMask = 0; -static unsigned long NextSlowFrameReaction = FRAMES_PER_SECOND * 10; - /** ** Wait for interactive input event for one frame. ** @@ -741,23 +738,6 @@ void WaitEventsOneFrame() Uint32 ticks = SDL_GetTicks(); if (ticks > NextFrameTicks) { // We are too slow :( ++SlowFrameCounter; - if (SlowFrameCounter > NextSlowFrameReaction) { - unsigned long pct = (SlowFrameCounter * 100) / (FrameCounter ? FrameCounter : 1); - if (pct >= 60) { - SkipFrameMask = 0b111; - } else if (pct >= 40) { - SkipFrameMask = 0b101; - } else if (pct >= 20) { - SkipFrameMask = 0b11; - } else if (pct >= 10) { - SkipFrameMask = 0b1; - } - NextSlowFrameReaction += FRAMES_PER_SECOND * 10; - fprintf(stdout, "WARNING WARNING WARNING\n" - "Frames %lu, Slow frames %d = %lu%%, starting to render only every %d%s frame.\n", - FrameCounter, SlowFrameCounter, pct, SkipFrameMask + 1, SkipFrameMask == 1 ? "nd" : "th"); - fflush(stdout); - } } InputMouseTimeout(*GetCallbacks(), ticks); @@ -855,7 +835,7 @@ void RealizeVideoMemory() if (dummyRenderer) { return; } - if (FrameCounter & SkipFrameMask) { + if (Preference.FrameSkip && (FrameCounter & Preference.FrameSkip)) { return; } if (NumRects) {