This fixes a mistake introduced in commit 4be1556, which in turn followed b02814b
The problem is, that CCStaticArray does not work as intended, and seems won't (at
least not without some extra workarounds).
When the script compiler is told to get an Nth element of a global struct array, such
as character[n], it calculates the memory address as
Character* ptr = (array address + sizeof(Character) * n).
If this address is used for the read/write operations, these ops can be intercepted by
interpreter and remapped into the real fields (see IScriptObject::ReadN, WriteN
interface).
But if this address is used IN POINTER COMPARISON BY VALUE, then we cannot do
anything. And if our real struct in the engine is stored on a different relative memory
offset than one expected by compiler, then this pointer comparison will fail.
This breaks script expressions like e.g.:
if (player == character[n])
From upstream 97ed18e95b587544ae47497f0a5f1d1ba00a7e29
Done for more consistency, so long as CharacterInfo and CharacterExtras are
separated structs.
WARNING: this breaks the saves made in 3.6.1.14 (Beta 15)...
Additionally, done so that legacy scriptnames are not loaded from current saves,
since these are supposed to stay fixed throughout the game (at least unless
characters are created dynamically, which they currently are not).
From upstream c15603adface26d3ea44519f07f4992c3201ad53
Because _displayspeech() was calling _display_at(), there happen two consecutive
calls to try_auto_play_speech().
If text contains more "&" characters that might lead to an unexpected scripting
error, or even an overriding voice-over.
Instead made _displayspeech() call display_main() directly, and simplified
display_at() to work strictly as a message box starter.
From upstream 1899fad4c4df0e2ddce7eb04699eb262e3638674
NOTE 1: we *must* keep the old fixed-sized fields for the time being,
for compaibility with the plugin API. Would the plugin API be adjusted
and have direct access to a character data struct removed, then these
fields may be removed as well.
NOTE 2: we still read these old fields from game data, avoid changing the
data format in the middle (in the sake of both backward and forward
compatibility). These fixed-sized values are assigned to the character
properties first. For unrestricted values we'll have to add a data extension,
appended to the end of data format.
From upstream b02814b8bb3bb7a2cd00110466e2bd3047e772d1
This refers to:
* DisplayAtY();
* DrawingSurface.DrawStringWrapped();
* Character.SayAt();
* Character.SayBackground();
From upstream e90f366b5abc2f7a89f16a40f24ccdc63fbe3601
Avoid query gfxDriver's properties all the time, instead save them once in init_draw_method() and use saved values.
From upstream db535512af65119d50ae3d6fb06c221d56f42d85
This complements the previous commits related to the upstream commit
9221ea54c1a81b9f37829d7fafc90ac2806d4eb1:
Engine: replaced script API registration with cleaner array tables
The benefits are:
1. Cleaner registration view, an array initializer instead of myriads of function calls.
2. Implicit distinction between static and object member functions based on prototype
detection, no need to explicitly pass a parameter or call respective registration function.
3. Enforced function registration for plugins, now combined with the regular registration
in one table entry, so more difficult to skip plugin variant
This is an attempt to keep character moving seamlessly when a new walking order
is made while the character is already walking.
Historically, engine had a problem with this, because of how a walking step is calculated.
In short, a MoveList struct increments a number of "steps", but these "steps" may be less
than pixel, in which case it takes >1 frames to make a visual change.
When a new walking order is made, this step counter is reset. This means that if player,
for example, keeps clicking around, the character will be "stuttering".
In this commit we try following solution: if the character is already walking, then save
last value of a fraction of "unfinished" pixel step, and apply it to the new movelist as
a starting step counter.
This works pretty well for in case of manual orders.
I must note however, that still, due to the nature of this counter, there may be issues
if a new Walk order is assigned each game frame. This may be done e.g. in script.
In this case, depending on various factors (relation between x and y distance,
walking speed, linking to animation, etc) the character may visually walk in a "ladder"
instead of a straight line.
This is probably will not be noticed when commanded by a player, as players commonly
do not click that frequently.
At this point I'm uncertain whether fixing the above would be only a matter of changing
the types of variables (fixed -> float, in attempt to reduce conversion mistakes), or a matter
of changing the core movelist mechanics.
From upstream a56e62ba65f16628265244a2da217c591b2a1271
Make MoveList::onpart a fixed point value too, allow more precise "current progress"
recalculation when the moving speed factor changes.
Possible TODO: on move update, the first step after recalculation should bring `onpart`
the the nearest integer, to make the movement progress more consistent.
From upstream b28ca9f86b8b70a73e4f6fa6f1c72ce76f29ecf6
Historically, neither Character.z (vertical offset), nor picture offsets (ones set by Character.LockViewAligned() and Character.LockViewOffset())
were not scaled along with the character's sprite.
Although it seems like that would be a right thing to do in a majority of practical applications of these properties.
This change introduces a separate zoom factor for these parameters. It's done separately to be able to maintain backwards compatibility.
In backwards mode this factor is always 100 (%), in the new mode it is always set equal to regular character's zoom (whether got from
a manual property, or a walkable area scaling).
The switch between modes is controlled by OPT_SCALECHAROFFSETS. This supposed to be always set in the new games. But this is also
a backup opportunity to disable this behavior, if a user finds it making it impossible to achieve a previously possible effect: in such case
one may disable this when compiling a game, or call SetGameOption(OPT_SCALECHAROFFSETS, 0) in script.
Code-wise, I had to move get_effective_y() method to CharacterExtras class, which makes more sense, as that's a runtime character class,
as opposed to CharacterInfo which is a game data serialization class, shared with the Editor.
There's still alot of potential for refactor and tidying the code, but I'd leave that for another task.
From upstream a2b0c88379f37fdaf44155e37f372b7de725db21
Keep ScreenOverlays in std::vector, but do not erase elements
in the middle and invalidate them instead. Record free indexes
in a helper stack.
When creating a new overlay, first check for the recorded free indexes.
Overlay's type now equals storage index.
This speeds up both creation/deletion of overlays, and their access.
Removed the gap between "fixed" overlay types and custom ones,
to save space. If we ever need more special overlays, these could
be created as custom and their ids saved in a variable (similar to
how background speech works). Previously present special overlay
types are left for backwards compatibility (and to simplify the transition).
From upstream f7d2f162fa55aa1b6f37195d890ebe047a204154
The spriteset's [] operator loads a sprite, but some operations may
omit that and check the preloaded information instead.
This also makes it more certain where the actual sprite's bitmap is necessary.
From upstream df30fc1edd30d4f334addaf7883286e745dea2c3
The idea is that the old variants have internal names with number
(signifying number of args), while the latest variant has a name without number.
Make sure there's a distinct function for each variant, and older vars are calling later ones in a sequence.
These calls likely to be inlined.
From upstream ca48926a37e848a1bcc162f77cc81e63ec7a1ca0
Separated internal RoomObject's storage values for ANIM_* types into OBJANIM_ constants.
Use common ANIM_* constants in shared code, such as ValidateViewAnimParams() and CycleViewAnim().
The internal storage values of objects, characters and buttons are converted from and to ANIM_ values
as necessary.
This fixes Character.AddWaypoint not applying room<->mask resolution conversion,
which result in character's speed being different if room has non 1:1 mask resolution.
Hide calculate_move_stage() inside pathfinder, and expose add_waypoint_direct()
in the pathfinder interface instead.
From upstream 093354d78849dc3b4f13a244d4400c4e71f7d687
These variables had to be set using set_route_move_speed() call in order for
the find_route() and calculate_move_stage() work properly.
But it's not obvious, and easy to forget. So turn them into function arguments instead.
This fixes Character.AddWaypoint potentially using wrong walkspeed, if there are
multiple characters or objects moving simultaneously.
An example of a script that would cause a bug:
cEgo.AddWaypoint(20, 20);
oObject0.Move(0, 160, 1, eNoBlock, eAnywhere);
cEgo.AddWaypoint(200, 200);
from upstream 9a00255a2699845bd0e53054d81c24e6955f663e
This fixes repeated post-state on/off switching, and as a consequence - endless loop
in cause of a "..." sentence, that is run until messagetime reaches -1 on its own,
which did not happen because of repeated post-state.
NOTE: looks like an original bug introduced along with the DisplayPostTimeMs property.
From upstream 37360990b22a79380f2a5b34e686a2d2fbcf7de1
if called again
This makes Character.WalkStraight() have the same animation
keeping logic as Character.Walk().
Also reduce code duplication by calling walk_or_move_character()
which handles blocking movement already.
From upstream c5b04eb0c8991026ebca593d6f3254dfe96fd290
This fixes idle animation getting reset to frame 0 at the blocking speech start
if there's no speech view set. In such case the idle anim is expected to continue
playing seamlessly.
From upstream 7b399933a291a05e868cd9589b02d83d05f33314
Since older commit 5f3b8eb the properties are stored in vectors,
strictly resized to the number of characters and objects.
But the script functions that access these do not do any assertion
whether the object or char is valid, which could cause bad mem
access in case script loops over a array of objects of MAX_OBJECTS
size, or tries to access something using Object* pointer from another room.
From upstream 6ad4b220d75a32ea8df959e9a7b7f1ecb21d0c26