Merge branch 'Wargus:master' into master

This commit is contained in:
Simone Starace 2022-07-31 10:54:36 +02:00 committed by GitHub
commit 75d523d819
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 544 additions and 87 deletions

3
.gitignore vendored
View file

@ -1,4 +1,7 @@
.cache
debian/tmp/*
gmon.*
valgrind.*
debian/*.debhelper
debian/*.log
debian/*.substvars

View file

@ -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

332
debian/changelog vendored
View file

@ -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 <timfelgentreff@gmail.com> Sat, 25 Dec 2021 06:45:52 +0100
[ Northfear ]
* Fix build with enabled DYNAMIC_LOAD
-- Tim Felgentreff <timfelgentreff@gmail.com> 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 <timfelgentreff@gmail.com> Wed, 27 Jul 2022 14:16:51 +0200
stratagus (3.2.0) focal; urgency=medium

4
debian/copyright vendored
View file

@ -6,11 +6,11 @@ Copyright:
© 2004 David Martínez Moreno <ender@debian.org>
© 2010-2012 Pali Rohár <pali.rohar@gmail.com>
© 2015 cybermind <iddqd_mail@mail.ru>
© 2016-2021 Tim Felgentreff <timfelgentreff@gmail.com>
© 2016-2022 Tim Felgentreff <timfelgentreff@gmail.com>
License: GPL-2+
Files: *
© 1998-2021 by The Stratagus Project, including, among others:
© 1998-2022 by The Stratagus Project, including, among others:
Jimmy Salmon <jsalmon3@users.sourceforge.net>
Russel Smith <mr-russ@users.sourceforge.net>
Nehal Mistry <nehalmistry@users.sourceforge.net>

137
doc/BuildingComplexMaps.md Normal file
View file

@ -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.

View file

@ -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

View file

@ -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<CUnitType *>(type));
}
#endif
DrawUnitType(*type, type->Sprite, i, 0, startScreenPos);
} else { // Draw a cross
DrawCross(startScreenPos, Map.Tileset->getPixelTileSize(), Players[i].Color);

View file

@ -157,6 +157,8 @@ public:
CMap();
~CMap();
void AllocateTileset();
unsigned int getIndex(int x, int y) const
{
return x + y * this->Info.MapWidth;

View file

@ -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<std::vector<CColor>> PlayerColorsRGB; /// Player colors
extern std::vector<std::vector<SDL_Color>> PlayerColorsSDL; /// Player colors
extern std::vector<std::string> PlayerColorNames; /// Player color names
extern PlayerRace PlayerRaces; /// Player races

View file

@ -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

View file

@ -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.

View file

@ -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; }

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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;

View file

@ -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();
}
/*----------------------------------------------------------------------------

View file

@ -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<SDL_Color>(PlayerColorsRGB[i].begin(), PlayerColorsRGB[i].end()));
}
}

View file

@ -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<SDL_Color>(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<SDL_Color>(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;
}

View file

@ -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();

View file

@ -37,6 +37,8 @@ class CPreference
bool HardwareCursor;
bool SelectionRectangleIndicatesDamage;
unsigned int FrameSkip;
unsigned int ShowOrders;
unsigned int ShowNameDelay;
unsigned int ShowNameTime;

View file

@ -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;
}

View file

@ -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) {

View file

@ -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<CUnit &>(unit));

View file

@ -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) {