Skip to content

Commit

Permalink
Engine: store character following params as 32-bit values
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-mogilko committed Dec 19, 2024
1 parent 024b183 commit 0192539
Show file tree
Hide file tree
Showing 11 changed files with 86 additions and 47 deletions.
8 changes: 4 additions & 4 deletions Common/ac/characterinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ void CharacterInfo::ReadBaseFields(Stream *in)
y = in->ReadInt32();
wait = in->ReadInt32();
flags = in->ReadInt32();
following = in->ReadInt16();
followinfo = in->ReadInt16();
legacy_following = in->ReadInt16();
legacy_followinfo = in->ReadInt16();
idleview = in->ReadInt32();
idletime = in->ReadInt16();
idleleft = in->ReadInt16();
Expand Down Expand Up @@ -78,8 +78,8 @@ void CharacterInfo::WriteBaseFields(Stream *out) const
out->WriteInt32(y);
out->WriteInt32(wait);
out->WriteInt32(flags);
out->WriteInt16(following);
out->WriteInt16(followinfo);
out->WriteInt16(0); // legacy_following
out->WriteInt16(0); // legacy_followinfo
out->WriteInt32(idleview);
out->WriteInt16(idletime);
out->WriteInt16(idleleft);
Expand Down
20 changes: 12 additions & 8 deletions Common/ac/characterinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ enum CharacterSvgVersion
kCharSvgVersion_36025 = 2, // animation volume
kCharSvgVersion_36109 = 3, // removed movelists, save externally
kCharSvgVersion_36115 = 4, // no limit on character name's length
kCharSvgVersion_36205 = 3060205, // 32-bit "following" parameters
};


Expand Down Expand Up @@ -121,8 +122,8 @@ struct CharacterInfo
int y = 0;
int wait = 0;
int flags = 0; // CHF_* flags
int16_t following = -1;
int16_t followinfo = 0;
int16_t legacy_following = -1; // deprecated 16-bit values that store follow params
int16_t legacy_followinfo = 0; // -- left for the script and plugin compatibility only
int idleview = 0; // the loop will be randomly picked
int16_t idletime = 0;
int16_t idleleft = 0; // num seconds idle before playing anim
Expand Down Expand Up @@ -186,32 +187,35 @@ struct CharacterInfo
((delay & 0xFF) << 8);
}

// Gets legacy follow distance, limited to a 8-bit unsigned value
inline int get_follow_distance() const
{
return (followinfo == FOLLOW_ALWAYSONTOP) ? FOLLOW_ALWAYSONTOP : (followinfo >> 8);
return (legacy_followinfo == FOLLOW_ALWAYSONTOP) ? FOLLOW_ALWAYSONTOP : (legacy_followinfo >> 8);
}
// Gets legacy follow eagerness, limited to a 8-bit unsigned value
inline int get_follow_eagerness() const
{
return (followinfo == FOLLOW_ALWAYSONTOP) ? 0 : (followinfo & 0xFF);
return (legacy_followinfo == FOLLOW_ALWAYSONTOP) ? 0 : (legacy_followinfo & 0xFF);
}
inline bool get_follow_sort_behind() const
{
return (flags & CHF_BEHINDSHEPHERD) != 0;
}

// Sets "following" flags and followinfo values
// Sets "following" flags;
// sets legacy "followinfo" values: this is for plugin API and old script API compatibility
void set_following(int16_t follow_whom, int dist = 0, int eagerness = 0, bool sort_behind = false)
{
following = follow_whom;
legacy_following = follow_whom;
if (dist == FOLLOW_ALWAYSONTOP)
{
flags = (flags & ~CHF_BEHINDSHEPHERD) | (CHF_BEHINDSHEPHERD * sort_behind);
followinfo = FOLLOW_ALWAYSONTOP;
legacy_followinfo = FOLLOW_ALWAYSONTOP;
}
else
{
flags = (flags & ~CHF_BEHINDSHEPHERD);
followinfo = (std::min<int>(UINT8_MAX, dist) << 8) | std::min<int>(UINT8_MAX, eagerness);
legacy_followinfo = (std::min<int>(UINT8_MAX, dist) << 8) | std::min<int>(UINT8_MAX, eagerness);
}
}

Expand Down
22 changes: 6 additions & 16 deletions Engine/ac/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -516,37 +516,27 @@ void Character_FollowCharacter(CharacterInfo *chaa, CharacterInfo *tofollow, int
debug_script_log("%s: Stop following other character", chaa->scrname);
}

if ((chaa->following >= 0) &&
(chaa->followinfo == FOLLOW_ALWAYSONTOP))
CharacterExtras *chex = &charextra[chaa->index_id];
if ((chex->following >= 0) &&
(chex->follow_dist == FOLLOW_ALWAYSONTOP))
{
// if this character was following always-on-top, its baseline will
// have been changed, so release it.
chaa->baseline = -1;
}

if (tofollow == nullptr)
{
chaa->set_following(-1, 0, 0, false);
}
else if (distaway == FOLLOW_ALWAYSONTOP)
{
chaa->set_following(tofollow->index_id, FOLLOW_ALWAYSONTOP, 0, (eagerness == 1));
}
else
{
chaa->set_following(tofollow->index_id, distaway, eagerness, false);
}
chex->SetFollowing(chaa, tofollow ? tofollow->index_id : -1, distaway, eagerness, (eagerness == 1));

if (chaa->animating & CHANIM_REPEAT)
debug_script_warn("Warning: FollowCharacter called but the sheep is currently animating looped. It may never start to follow.");
}

CharacterInfo* Character_GetFollowing(CharacterInfo* chaa)
{
if (chaa->following < 0)
if (charextra[chaa->index_id].following < 0)
return nullptr;

return &game.chars[chaa->following];
return &game.chars[charextra[chaa->index_id].following];
}

int Character_IsCollidingWithChar(CharacterInfo *char1, CharacterInfo *char2) {
Expand Down
30 changes: 30 additions & 0 deletions Engine/ac/characterextras.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,25 @@ void CharacterExtras::CheckViewFrame(CharacterInfo *chi)
::CheckViewFrame(chi->view, chi->loop, chi->frame, GetFrameSoundVolume(chi));
}

void CharacterExtras::SetFollowing(CharacterInfo *chi, int follow_who, int distance, int eagerness, bool sort_behind)
{
if (follow_who < 0)
{
following = -1;
follow_dist = 0;
follow_eagerness = 0;
}
else
{
following = follow_who;
follow_dist = distance;
follow_eagerness = (distance == FOLLOW_ALWAYSONTOP) ? 0 : eagerness;
}

// Set Character's following flags, and legacy fields, for backwards compatibility
chi->set_following(following, follow_dist, follow_eagerness, sort_behind);
}

void CharacterExtras::ReadFromSavegame(Stream *in, CharacterSvgVersion save_ver)
{
in->ReadArrayOfInt16(invorder, MAX_INVORDER);
Expand All @@ -59,6 +78,12 @@ void CharacterExtras::ReadFromSavegame(Stream *in, CharacterSvgVersion save_ver)
in->ReadInt8(); // reserved to fill int32
in->ReadInt8();
}
if (save_ver >= kCharSvgVersion_36205)
{
following = in->ReadInt32();
follow_dist = in->ReadInt32();
follow_eagerness = in->ReadInt32();
}
}

void CharacterExtras::WriteToSavegame(Stream *out) const
Expand All @@ -78,8 +103,13 @@ void CharacterExtras::WriteToSavegame(Stream *out) const
out->WriteInt8(process_idle_this_time);
out->WriteInt8(slow_move_counter);
out->WriteInt16(animwait);
// kCharSvgVersion_36025
out->WriteInt8(static_cast<uint8_t>(anim_volume));
out->WriteInt8(static_cast<uint8_t>(cur_anim_volume));
out->WriteInt8(0); // reserved to fill int32
out->WriteInt8(0);
// kCharSvgVersion_36205
out->WriteInt32(following);
out->WriteInt32(follow_dist);
out->WriteInt32(follow_eagerness);
}
9 changes: 7 additions & 2 deletions Engine/ac/characterextras.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,20 +56,25 @@ struct CharacterExtras
short animwait = 0;
int anim_volume = 100; // default animation volume (relative factor)
int cur_anim_volume = 100; // current animation sound volume (relative factor)
int following = -1; // whom do we follow (character id)
int follow_dist = 0; // follow distance, in pixels
int follow_eagerness = 0; // follow reaction

// Following fields are deriatives of the above (calculated from these
// and other factors), and hence are not serialized.
//
// zoom factor of sprite offsets, fixed at 100 in backwards compatible mode
int zoom_offs = 100;

int GetEffectiveY(CharacterInfo *chi) const; // return Y - Z

// Get visual Y position, which is calculated as Y - Z (scaled)
int GetEffectiveY(CharacterInfo *chi) const;
// Calculate wanted frame sound volume based on multiple factors
int GetFrameSoundVolume(CharacterInfo *chi) const;
// Process the current animation frame for the character:
// play linked sounds, and so forth.
void CheckViewFrame(CharacterInfo *chi);
// Setups following another character (follow_who)
void SetFollowing(CharacterInfo *chi, int follow_who, int distance = 0, int eagerness = 0, bool sort_behind = false);

// Read character extra data from saves.
void ReadFromSavegame(Common::Stream *in, CharacterSvgVersion save_ver);
Expand Down
9 changes: 5 additions & 4 deletions Engine/ac/characterinfo_engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ void UpdateCharacterMoveAndAnim(CharacterInfo *chi, CharacterExtras *chex, std::

void UpdateFollowingExactlyCharacter(CharacterInfo *chi)
{
const auto &following = game.chars[chi->following];
const auto &following = game.chars[charextra[chi->index_id].following];
chi->x = following.x;
chi->y = following.y;
chi->z = following.z;
Expand Down Expand Up @@ -363,9 +363,10 @@ bool UpdateCharacterAnimating(CharacterInfo *chi, CharacterExtras *chex, int &do

void UpdateCharacterFollower(CharacterInfo *chi, std::vector<int> &followingAsSheep, int &doing_nothing)
{
const int following = chi->following;
const int distaway = chi->get_follow_distance();
const int eagerness = chi->get_follow_eagerness();
const CharacterExtras *chex = &charextra[chi->index_id];
const int following = chex->following;
const int distaway = chex->follow_dist;
const int eagerness = chex->follow_eagerness;

if ((following >= 0) && (distaway == FOLLOW_ALWAYSONTOP)) {
// an always-on-top follow
Expand Down
4 changes: 2 additions & 2 deletions Engine/ac/dynobj/cc_character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ int16_t CCCharacter::ReadInt16(const void *address, intptr_t offset)
switch (offset)
{
// +9 int32 = 36
case 36: return ci->following;
case 38: return ci->followinfo;
case 36: return ci->legacy_following;
case 38: return ci->legacy_followinfo;
// 40 +1 int32 = 44
case 44: return ci->idletime;
case 46: return ci->idleleft;
Expand Down
14 changes: 8 additions & 6 deletions Engine/ac/room.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ extern int in_new_room, new_room_was; // 1 in new room, 2 first time in new roo
extern ScriptHotspot scrHotspot[MAX_ROOM_HOTSPOTS];
extern int in_leaves_screen;
extern CharacterInfo*playerchar;
extern std::vector<CharacterExtras> charextra;
extern int starting_room;
extern unsigned int loopcounter;
extern IDriverDependantBitmap* roomBackgroundBmp;
Expand Down Expand Up @@ -719,14 +720,14 @@ void load_new_room(int newnum, CharacterInfo*forchar) {
// if a following character is still waiting to come into the
// previous room, force it out so that the timer resets
for (int ff = 0; ff < game.numcharacters; ff++) {
if ((game.chars[ff].following >= 0) && (game.chars[ff].room < 0)) {
if ((game.chars[ff].following == game.playercharacter) &&
if ((charextra[ff].following >= 0) && (game.chars[ff].room < 0)) {
if ((charextra[ff].following == game.playercharacter) &&
(forchar->prevroom == newnum))
// the player went back to the previous room, so make sure
// the following character is still there
game.chars[ff].room = newnum;
else
game.chars[ff].room = game.chars[game.chars[ff].following].room;
game.chars[ff].room = game.chars[charextra[ff].following].room;
}
}

Expand Down Expand Up @@ -947,11 +948,12 @@ void new_room(int newnum,CharacterInfo*forchar) {
newnum = in_leaves_screen;
in_leaves_screen = -1;

if ((playerchar->following >= 0) &&
(game.chars[playerchar->following].room != newnum)) {
CharacterExtras *player_ex = &charextra[playerchar->index_id];
if ((player_ex->following >= 0) &&
(game.chars[player_ex->following].room != newnum)) {
// the player character is following another character,
// who is not in the new room. therefore, abort the follow
playerchar->set_following(-1);
player_ex->SetFollowing(playerchar, -1);
}

// change rooms
Expand Down
13 changes: 10 additions & 3 deletions Engine/game/savegame_components.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -674,8 +674,15 @@ HSaveError ReadCharacters(Stream *in, int32_t cmp_ver, soff_t cmp_size, const Pr

for (uint32_t i = 0; i < characters_read; ++i)
{
game.chars[i].ReadFromSavegame(in, game.chars2[i], static_cast<CharacterSvgVersion>(cmp_ver));
charextra[i].ReadFromSavegame(in, static_cast<CharacterSvgVersion>(cmp_ver));
auto &chi = game.chars[i];
auto &chex = charextra[i];
chi.ReadFromSavegame(in, game.chars2[i], static_cast<CharacterSvgVersion>(cmp_ver));
chex.ReadFromSavegame(in, static_cast<CharacterSvgVersion>(cmp_ver));
// re-assign legacy following params (for old saves)
if (cmp_ver < kCharSvgVersion_36205)
{
charextra[i].SetFollowing(&chi, chi.legacy_following, chi.get_follow_distance(), chi.get_follow_eagerness(), chi.get_follow_sort_behind());
}
Properties::ReadValues(play.charProps[i], in);
if (loaded_game_file_version <= kGameVersion_272)
ReadTimesRun272(*game.intrChar[i], in);
Expand Down Expand Up @@ -1703,7 +1710,7 @@ ComponentHandler ComponentHandlers[] =
},
{
"Characters",
kCharSvgVersion_36115,
kCharSvgVersion_36205,
kCharSvgVersion_350, // skip pre-alpha 3.5.0 ver
kSaveCmp_Characters,
WriteCharacters,
Expand Down
2 changes: 1 addition & 1 deletion Engine/main/engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@ void engine_init_game_settings()
for (ee=0;ee<game.numcharacters;ee++) {
memset(&game.chars[ee].inv[0],0,MAX_INV*sizeof(short));
game.chars[ee].activeinv=-1;
game.chars[ee].set_following(-1, 10, 97, false);
game.chars[ee].set_following(-1, 10, 97, false); // some legacy def values, not sure if necessary
if (loaded_game_file_version < kGameVersion_360)
game.chars[ee].idletime=20; // default to 20 seconds
game.chars[ee].idleleft=game.chars[ee].idletime;
Expand Down
2 changes: 1 addition & 1 deletion Engine/main/game_run.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ bool run_service_key_controls(KeyInput &out_key)
game.chars[chd].scrname, game.chars[chd].view + 1, game.chars[chd].loop, game.chars[chd].frame,
game.chars[chd].x, game.chars[chd].y, game.chars[chd].z,
game.chars[chd].idleview, game.chars[chd].idletime, game.chars[chd].idleleft,
game.chars[chd].walking, game.chars[chd].animating, game.chars[chd].following,
game.chars[chd].walking, game.chars[chd].animating, charextra[chd].following,
game.chars[chd].flags, game.chars[chd].wait, charextra[chd].zoom);
}
DisplayMB(buffer.GetCStr());
Expand Down

0 comments on commit 0192539

Please sign in to comment.