1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "ags/shared/ac/common.h"
24 #include "ags/shared/ac/game_version.h"
25 #include "ags/engine/ac/room_status.h"
26 #include "ags/shared/game/custom_properties.h"
27 #include "ags/engine/game/savegame_components.h"
28 #include "ags/shared/util/aligned_stream.h"
29 #include "ags/globals.h"
30
31 namespace AGS3 {
32
33 using namespace AGS::Shared;
34 using namespace AGS::Engine;
35
RoomStatus()36 RoomStatus::RoomStatus() {
37 beenhere = 0;
38 numobj = 0;
39 memset(&flagstates, 0, sizeof(flagstates));
40 tsdatasize = 0;
41 tsdata = nullptr;
42
43 memset(&hotspot_enabled, 0, sizeof(hotspot_enabled));
44 memset(®ion_enabled, 0, sizeof(region_enabled));
45 memset(&walkbehind_base, 0, sizeof(walkbehind_base));
46 memset(&interactionVariableValues, 0, sizeof(interactionVariableValues));
47 }
48
~RoomStatus()49 RoomStatus::~RoomStatus() {
50 if (tsdata)
51 delete[] tsdata;
52 }
53
FreeScriptData()54 void RoomStatus::FreeScriptData() {
55 if (tsdata)
56 delete[] tsdata;
57 tsdata = nullptr;
58 tsdatasize = 0;
59 }
60
FreeProperties()61 void RoomStatus::FreeProperties() {
62 roomProps.clear();
63 for (int i = 0; i < MAX_ROOM_HOTSPOTS; ++i) {
64 hsProps[i].clear();
65 }
66 for (int i = 0; i < MAX_ROOM_OBJECTS; ++i) {
67 objProps[i].clear();
68 }
69 }
70
ReadFromFile_v321(Stream * in)71 void RoomStatus::ReadFromFile_v321(Stream *in) {
72 beenhere = in->ReadInt32();
73 numobj = in->ReadInt32();
74 ReadRoomObjects_Aligned(in);
75 in->ReadArrayOfInt16(flagstates, MAX_FLAGS);
76 tsdatasize = in->ReadInt32();
77 in->ReadInt32(); // tsdata
78 for (int i = 0; i < MAX_ROOM_HOTSPOTS; ++i) {
79 intrHotspot[i].ReadFromSavedgame_v321(in);
80 }
81 for (int i = 0; i < MAX_ROOM_OBJECTS; ++i) {
82 intrObject[i].ReadFromSavedgame_v321(in);
83 }
84 for (int i = 0; i < MAX_ROOM_REGIONS; ++i) {
85 intrRegion[i].ReadFromSavedgame_v321(in);
86 }
87 intrRoom.ReadFromSavedgame_v321(in);
88 in->ReadArrayOfInt8((int8_t *)hotspot_enabled, MAX_ROOM_HOTSPOTS);
89 in->ReadArrayOfInt8((int8_t *)region_enabled, MAX_ROOM_REGIONS);
90 in->ReadArrayOfInt16(walkbehind_base, MAX_WALK_BEHINDS);
91 in->ReadArrayOfInt32(interactionVariableValues, MAX_GLOBAL_VARIABLES);
92
93 if (_G(loaded_game_file_version) >= kGameVersion_340_4) {
94 Properties::ReadValues(roomProps, in);
95 for (int i = 0; i < MAX_ROOM_HOTSPOTS; ++i) {
96 Properties::ReadValues(hsProps[i], in);
97 }
98 for (int i = 0; i < MAX_ROOM_OBJECTS; ++i) {
99 Properties::ReadValues(objProps[i], in);
100 }
101 }
102 }
103
ReadRoomObjects_Aligned(Shared::Stream * in)104 void RoomStatus::ReadRoomObjects_Aligned(Shared::Stream *in) {
105 AlignedStream align_s(in, Shared::kAligned_Read);
106 for (int i = 0; i < MAX_ROOM_OBJECTS; ++i) {
107 obj[i].ReadFromFile(&align_s);
108 align_s.Reset();
109 }
110 }
111
ReadFromSavegame(Stream * in)112 void RoomStatus::ReadFromSavegame(Stream *in) {
113 FreeScriptData();
114 FreeProperties();
115
116 beenhere = in->ReadInt8();
117 numobj = in->ReadInt32();
118 for (int i = 0; i < numobj; ++i) {
119 obj[i].ReadFromFile(in);
120 Properties::ReadValues(objProps[i], in);
121 if (_G(loaded_game_file_version) <= kGameVersion_272)
122 SavegameComponents::ReadInteraction272(intrObject[i], in);
123 }
124 for (int i = 0; i < MAX_ROOM_HOTSPOTS; ++i) {
125 hotspot_enabled[i] = in->ReadInt8();
126 Properties::ReadValues(hsProps[i], in);
127 if (_G(loaded_game_file_version) <= kGameVersion_272)
128 SavegameComponents::ReadInteraction272(intrHotspot[i], in);
129 }
130 for (int i = 0; i < MAX_ROOM_REGIONS; ++i) {
131 region_enabled[i] = in->ReadInt8();
132 if (_G(loaded_game_file_version) <= kGameVersion_272)
133 SavegameComponents::ReadInteraction272(intrRegion[i], in);
134 }
135 for (int i = 0; i < MAX_WALK_BEHINDS; ++i) {
136 walkbehind_base[i] = in->ReadInt32();
137 }
138
139 Properties::ReadValues(roomProps, in);
140 if (_G(loaded_game_file_version) <= kGameVersion_272) {
141 SavegameComponents::ReadInteraction272(intrRoom, in);
142 in->ReadArrayOfInt32(interactionVariableValues, MAX_GLOBAL_VARIABLES);
143 }
144
145 tsdatasize = in->ReadInt32();
146 if (tsdatasize) {
147 tsdata = new char[tsdatasize];
148 in->Read(tsdata, tsdatasize);
149 }
150 }
151
WriteToSavegame(Stream * out) const152 void RoomStatus::WriteToSavegame(Stream *out) const {
153 out->WriteInt8(beenhere);
154 out->WriteInt32(numobj);
155 for (int i = 0; i < numobj; ++i) {
156 obj[i].WriteToFile(out);
157 Properties::WriteValues(objProps[i], out);
158 if (_G(loaded_game_file_version) <= kGameVersion_272)
159 SavegameComponents::WriteInteraction272(intrObject[i], out);
160 }
161 for (int i = 0; i < MAX_ROOM_HOTSPOTS; ++i) {
162 out->WriteInt8(hotspot_enabled[i]);
163 Properties::WriteValues(hsProps[i], out);
164 if (_G(loaded_game_file_version) <= kGameVersion_272)
165 SavegameComponents::WriteInteraction272(intrHotspot[i], out);
166 }
167 for (int i = 0; i < MAX_ROOM_REGIONS; ++i) {
168 out->WriteInt8(region_enabled[i]);
169 if (_G(loaded_game_file_version) <= kGameVersion_272)
170 SavegameComponents::WriteInteraction272(intrRegion[i], out);
171 }
172 for (int i = 0; i < MAX_WALK_BEHINDS; ++i) {
173 out->WriteInt32(walkbehind_base[i]);
174 }
175
176 Properties::WriteValues(roomProps, out);
177 if (_G(loaded_game_file_version) <= kGameVersion_272) {
178 SavegameComponents::WriteInteraction272(intrRoom, out);
179 out->WriteArrayOfInt32(interactionVariableValues, MAX_GLOBAL_VARIABLES);
180 }
181
182 out->WriteInt32(tsdatasize);
183 if (tsdatasize)
184 out->Write(tsdata, tsdatasize);
185 }
186
187 // JJS: Replacement for the global roomstats array in the original engine.
188
189 RoomStatus *room_statuses[MAX_ROOMS];
190
191 // Replaces all accesses to the roomstats array
getRoomStatus(int room)192 RoomStatus *getRoomStatus(int room) {
193 if (room_statuses[room] == nullptr) {
194 // First access, allocate and initialise the status
195 room_statuses[room] = new RoomStatus();
196 }
197 return room_statuses[room];
198 }
199
200 // Used in places where it is only important to know whether the player
201 // had previously entered the room. In this case it is not necessary
202 // to initialise the status because a player can only have been in
203 // a room if the status is already initialised.
isRoomStatusValid(int room)204 bool isRoomStatusValid(int room) {
205 return (room_statuses[room] != nullptr);
206 }
207
resetRoomStatuses()208 void resetRoomStatuses() {
209 for (int i = 0; i < MAX_ROOMS; i++) {
210 if (room_statuses[i] != nullptr) {
211 delete room_statuses[i];
212 room_statuses[i] = nullptr;
213 }
214 }
215 }
216
217 } // namespace AGS3
218