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(&region_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