/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "ags/engine/ac/dynobj/cc_character.h" #include "ags/engine/ac/dynobj/dynobj_manager.h" #include "ags/shared/ac/character_info.h" #include "ags/engine/ac/global_character.h" #include "ags/shared/ac/game_setup_struct.h" #include "ags/shared/script/cc_common.h" // cc_error #include "ags/shared/util/stream.h" #include "ags/globals.h" namespace AGS3 { using namespace AGS::Shared; // return the type name of the object const char *CCCharacter::GetType() { return "Character"; } // serialize the object into BUFFER (which is BUFSIZE bytes) // return number of bytes used size_t CCCharacter::CalcSerializeSize(const void * /*address*/) { return sizeof(int32_t); } // serialize the object into BUFFER (which is BUFSIZE bytes) // return number of bytes used void CCCharacter::Serialize(const void *address, Stream *out) { const CharacterInfo *chaa = static_cast(address); out->WriteInt32(chaa->index_id); } void CCCharacter::Unserialize(int index, Stream *in, size_t data_sz) { int num = in->ReadInt32(); ccRegisterUnserializedObject(index, &_GP(game).chars[num], this); } uint8_t CCCharacter::ReadInt8(void *address, intptr_t offset) { const CharacterInfo *ci = static_cast(address); const int on_offset = 28 * sizeof(int32_t) /* first var group */ + 301 * sizeof(int16_t) /* inventory */ + sizeof(int16_t) * 2 /* two shorts */ + 40 /* name */ + 20 /* scrname */; if (offset == on_offset) return ci->on; cc_error("ScriptCharacter: unsupported 'char' variable offset %d", offset); return 0; } void CCCharacter::WriteInt8(void *address, intptr_t offset, uint8_t val) { CharacterInfo *ci = static_cast(address); const int on_offset = 28 * sizeof(int32_t) /* first var group */ + 301 * sizeof(int16_t) /* inventory */ + sizeof(int16_t) * 2 /* two shorts */ + 40 /* name */ + 20 /* scrname */; if (offset == on_offset) ci->on = val; else cc_error("ScriptCharacter: unsupported 'char' variable offset %d", offset); } int16_t CCCharacter::ReadInt16(void *address, intptr_t offset) { const CharacterInfo *ci = static_cast(address); // Handle inventory fields const int invoffset = 112; if (offset >= invoffset && offset < (uint)(invoffset + MAX_INV * sizeof(short))) { return ci->inv[(offset - invoffset) / sizeof(short)]; } switch (offset) { // +9 int32 = 36 case 36: return ci->following; case 38: return ci->followinfo; // 40 +1 int32 = 44 case 44: return ci->idletime; case 46: return ci->idleleft; case 48: return ci->transparency; case 50: return ci->baseline; // 52 +3 int32 = 64 case 64: return ci->blinkview; case 66: return ci->blinkinterval; case 68: return ci->blinktimer; case 70: return ci->blinkframe; case 72: return ci->walkspeed_y; case 74: return ci->pic_yoffs; // 76 +2 int32 = 84 case 84: return ci->speech_anim_speed; case 86: return ci->idle_anim_speed; case 88: return ci->blocking_width; case 90: return ci->blocking_height; // 92 +1 int32 = 96 case 96: return ci->pic_xoffs; case 98: return ci->walkwaitcounter; case 100: return ci->loop; case 102: return ci->frame; case 104: return ci->walking; case 106: return ci->animating; case 108: return ci->walkspeed; case 110: return ci->animspeed; // 112 +301 int16 = 714 (skip inventory) case 714: return ci->actx; case 716: return ci->acty; default: cc_error("ScriptCharacter: unsupported 'short' variable offset %d", offset); return 0; } } void CCCharacter::WriteInt16(void *address, intptr_t offset, int16_t val) { CharacterInfo *ci = static_cast(address); // Detect when a game directly modifies the inventory, which causes the displayed // and actual inventory to diverge since 2.70. Force an update of the displayed // inventory for older games that rely on this behaviour. const int invoffset = 112; if (offset >= invoffset && offset < (uint)(invoffset + MAX_INV * sizeof(short))) { ci->inv[(offset - invoffset) / sizeof(short)] = val; update_invorder(); return; } // TODO: for safety, find out which of the following fields // must be readonly, and add assertions for them, i.e.: // cc_error("ScriptCharacter: attempt to write readonly 'short' variable at offset %d", offset); switch (offset) { // +9 int32 = 36 case 36: ci->following = val; break; case 38: ci->followinfo = val; break; // 40 +1 int32 = 44 case 44: ci->idletime = val; break; case 46: ci->idleleft = val; break; case 48: ci->transparency = val; break; case 50: ci->baseline = val; break; // 52 +3 int32 = 64 case 64: ci->blinkview = val; break; case 66: ci->blinkinterval = val; break; case 68: ci->blinktimer = val; break; case 70: ci->blinkframe = val; break; case 72: ci->walkspeed_y = val; break; case 74: ci->pic_yoffs = val; break; // 76 +2 int32 = 84 case 84: ci->speech_anim_speed = val; break; case 86: ci->idle_anim_speed = val; break; case 88: ci->blocking_width = val; break; case 90: ci->blocking_height = val; break; // 92 +1 int32 = 96 case 96: ci->pic_xoffs = val; break; case 98: ci->walkwaitcounter = val; break; case 100: ci->loop = val; break; case 102: ci->frame = val; break; case 104: ci->walking = val; break; case 106: ci->animating = val; break; case 108: ci->walkspeed = val; break; case 110: ci->animspeed = val; break; // 112 +301 int16 = 714 (skip inventory) case 714: ci->actx = val; break; case 716: ci->acty = val; break; default: cc_error("ScriptCharacter: unsupported 'short' variable offset %d", offset); break; } } int32_t CCCharacter::ReadInt32(void *address, intptr_t offset) { const CharacterInfo *ci = static_cast(address); switch (offset) { case 0: return ci->defview; case 4: return ci->talkview; case 8: return ci->view; case 12: return ci->room; case 16: return ci->prevroom; case 20: return ci->x; case 24: return ci->y; case 28: return ci->wait; case 32: return ci->flags; // 36 +2 int16 = 40 case 40: return ci->idleview; // 44 +4 int16 = 52 case 52: return ci->activeinv; case 56: return ci->talkcolor; case 60: return ci->thinkview; // 64 +6 int16 = 76 case 76: return ci->z; case 80: return ci->walkwait; // 84 +4 int16 = 100 case 92: return ci->index_id; default: cc_error("ScriptCharacter: unsupported 'int' variable offset %d", offset); return 0; } } void CCCharacter::WriteInt32(void *address, intptr_t offset, int32_t val) { CharacterInfo *ci = static_cast(address); // TODO: for safety, find out which of the following fields // must be readonly, and add assertions for them, i.e.: // cc_error("ScriptCharacter: attempt to write readonly 'int' variable at offset %d", offset); switch (offset) { case 0: ci->defview = val; break; case 4: ci->talkview = val; break; case 8: ci->view = val; break; case 12: ci->room = val; break; case 16: ci->prevroom = val; break; case 20: ci->x = val; break; case 24: ci->y = val; break; case 28: ci->wait = val; break; case 32: ci->flags = val; break; // 36 +2 int16 = 40 case 40: ci->idleview = val; break; // 44 +4 int16 = 52 case 52: ci->activeinv = val; break; case 56: ci->talkcolor = val; break; case 60: ci->thinkview = val; break; // 64 +6 int16 = 76 case 76: ci->z = val; break; case 80: ci->walkwait = val; break; // 84 +4 int16 = 100 case 92: ci->index_id = val; break; default: cc_error("ScriptCharacter: unsupported 'int' variable offset %d", offset); break; } } } // namespace AGS3