1 /*
2  *  gamemap.h - Game map data.
3  *
4  *  Copyright (C) 1998-1999  Jeffrey S. Freedman
5  *  Copyright (C) 2000-2013  The Exult Team
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 
22 #ifndef GAMEMAP_H
23 #define GAMEMAP_H
24 
25 #include "chunks.h"
26 #include "exult_constants.h"
27 #include "flags.h"
28 #include "tiles.h"
29 
30 #include <cassert>
31 #include <fstream>
32 #include <iostream>
33 #include <memory>
34 #include <string>    // STL string
35 #include <vector>
36 
37 class Chunk_terrain;
38 class Map_patch_collection;
39 class Game_object;
40 class Ireg_game_object;
41 class Ifix_game_object;
42 class Egg_object;
43 class Shape_info;
44 class Shapes_vga_file;
45 class IDataSource;
46 class ODataSource;
47 class Shape;
48 using Ireg_game_object_shared = std::shared_ptr<Ireg_game_object>;
49 using Ifix_game_object_shared = std::shared_ptr<Ifix_game_object>;
50 
51 #define IREG_EXTENDED   254     // For shape #'s > 1023.
52 #define IREG_EXTENDED2  253     // For lift > 15.
53 
54 /*
55  *  The game map:
56  */
57 class Game_map {
58 	int num;            // Map #.  Index in gwin->maps.
59 	// Flat chunk areas:
60 	static std::vector<Chunk_terrain *> *chunk_terrains;
61 	static std::ifstream *chunks;   // "u7chunks" file.
62 	static bool v2_chunks;      // True if 3 bytes/entry.
63 	static bool read_all_terrain;   // True if we've read them all.
64 	static bool chunk_terrains_modified;
65 	bool didinit;
66 	bool map_modified;      // True if any map changes from
67 	//   map-editing.
68 	// Chunk_terrain index for each chunk:
69 	short terrain_map[c_num_chunks][c_num_chunks];
70 	// A list of objects in each chunk:
71 	std::unique_ptr<Map_chunk> objects[c_num_chunks][c_num_chunks];
72 	bool schunk_read[144];      // Flag for reading in each "ifix".
73 	bool schunk_modified[144];  // Flag for modified "ifix".
74 	char *schunk_cache[144];
75 	int  schunk_cache_sizes[144];
76 	int caching_out;        // >0 in 'cache_out_schunk'.
77 	std::unique_ptr<Map_patch_collection> map_patches;
78 
79 	Map_chunk *create_chunk(int cx, int cy);
80 	static Chunk_terrain *read_terrain(int chunk_num);
81 
82 	// Create a 192x192 viewable map.
83 	void create_minimap(Shape *minimaps, const unsigned char *chunk_pixels);
84 	void cache_out_schunk(int schunk);
85 public:
86 	Game_map(int n);
87 	~Game_map();
88 	static void init_chunks();
89 	void init();            // Set up map.
90 	static void clear_chunks();
91 	void clear();           // Clear out old map.
92 	void read_map_data();       // Read in 'ifix', 'ireg', etc.
is_v2_chunks()93 	static bool is_v2_chunks() {
94 		return v2_chunks;
95 	}
is_caching_out()96 	bool is_caching_out() const {
97 		return caching_out > 0;
98 	}
get_num()99 	int get_num() const {
100 		return num;
101 	}
get_terrain_num(int cx,int cy)102 	inline short get_terrain_num(int cx, int cy) const {
103 		return terrain_map[cx][cy];
104 	}
get_map_patches()105 	inline Map_patch_collection& get_map_patches() {
106 		return *map_patches;
107 	}
set_map_modified()108 	void set_map_modified() {
109 		map_modified = true;
110 	}
was_map_modified()111 	bool was_map_modified() const {
112 		return map_modified;
113 	}
was_chunk_terrain_modified()114 	static bool was_chunk_terrain_modified() {
115 		return chunk_terrains_modified;
116 	}
set_chunk_terrains_modified()117 	static void set_chunk_terrains_modified() {
118 		chunk_terrains_modified = true;
119 	}
is_chunk_read(int cx,int cy)120 	bool is_chunk_read(int cx, int cy) {
121 		return cx < c_num_chunks && cy < c_num_chunks &&
122 		       schunk_read[12 * (cy / c_chunks_per_schunk) +
123 		                   cx / c_chunks_per_schunk];
124 	}
ensure_chunk_read(int cx,int cy)125 	void ensure_chunk_read(int cx, int cy) {
126 		if (cx < c_num_chunks && cy < c_num_chunks) {
127 			int sc = 12 * (cy/c_chunks_per_schunk) + cx/c_chunks_per_schunk;
128 			if (!schunk_read[sc])
129 				get_superchunk_objects(sc);
130 		}
131 	}
set_ifix_modified(int cx,int cy)132 	void set_ifix_modified(int cx, int cy) {
133 		map_modified = true;
134 		schunk_modified[12 * (cy / c_chunks_per_schunk) +
135 		                cx / c_chunks_per_schunk] = true;
136 	}
137 	// Get objs. list for a chunk.
get_chunk_unsafe(int cx,int cy)138 	Map_chunk *get_chunk_unsafe(int cx, int cy) {
139 		return objects[cx][cy].get();
140 	}
141 	// Get/create objs. list for a chunk.
get_chunk_unchecked(int cx,int cy)142 	Map_chunk *get_chunk_unchecked(int cx, int cy) {
143 		Map_chunk *list = get_chunk_unsafe(cx, cy);
144 		return list ? list : create_chunk(cx, cy);
145 	}
146 	// Get/create objs. list for a chunk.
get_chunk(int cx,int cy)147 	Map_chunk *get_chunk(int cx, int cy) {
148 		assert((cx >= 0) && (cx < c_num_chunks) &&
149 		       (cy >= 0) && (cy < c_num_chunks));
150 		return get_chunk_unchecked(cx, cy);
151 	}
get_chunk_safely(int cx,int cy)152 	Map_chunk *get_chunk_safely(int cx, int cy) {
153 		if (cx >= 0 && cx < c_num_chunks &&
154 		    cy >= 0 && cy < c_num_chunks) {
155 			return get_chunk_unchecked(cx, cy);
156 		}
157 		return nullptr;
158 	}
159 	// Get "map" superchunk objs/scenery.
160 	void get_map_objects(int schunk);
161 	// Get "chunk" objects/scenery.
162 	void get_chunk_objects(int cx, int cy);
163 	static void get_all_terrain();  // Read in all terrains.
164 	// Get desired terrain.
get_terrain(int tnum)165 	static Chunk_terrain *get_terrain(int tnum) {
166 		Chunk_terrain *ter = (*chunk_terrains)[tnum];
167 		return ter ? ter : read_terrain(tnum);
168 	}
get_num_chunk_terrains()169 	inline int get_num_chunk_terrains() const {
170 		return chunk_terrains->size();
171 	}
172 	// Set new terrain chunk.
173 	void set_chunk_terrain(int cx, int cy, int chunknum);
174 	char *get_mapped_name(const char *from, char *to);
175 	// Get ifixxxx/iregxx name.
176 	char *get_schunk_file_name(const char *prefix, int schunk, char *fname);
177 	static void write_chunk_terrains();
178 	void write_static();        // Write to 'static' directory.
179 	// Write (static) map objects.
180 	void write_ifix_objects(int schunk);
181 	// Get "ifix" objects for a superchunk.
182 	void get_ifix_objects(int schunk);
183 	// Get "ifix" objs. for given chunk.
184 	void get_ifix_chunk_objects(IDataSource *ifix, int vers,
185 	                            long filepos, int len, int cx, int cy);
186 	static void write_attributes(ODataSource *ireg,
187 	                             std::vector<std::pair<const char *, int> > &attlist);
188 	// Write scheduled script for obj.
189 	static void write_scheduled(ODataSource *ireg, Game_object *obj,
190 	                            bool write_mark = false);
191 	static int write_string(ODataSource *ireg, const char *str);
192 	void write_ireg();      // Write modified ireg files.
193 	// Write moveable objects to file.
194 	void write_ireg_objects(int schunk);
195 	// Write moveable objects to datasource.
196 	void write_ireg_objects(int schunk, ODataSource *ireg);
197 	// Get moveable objects.
198 	void get_ireg_objects(int schunk);
199 	// Read scheduled script(s) for obj.
200 	void read_special_ireg(IDataSource *ireg, Game_object *obj);
201 	void read_ireg_objects(IDataSource *ireg, int scx, int scy,
202 	                       Game_object *container = nullptr,
203 	                       unsigned long flags = (1 << Obj_flags::okay_to_take));
204 	Ireg_game_object_shared create_ireg_object(const Shape_info &info, int shnum,
205 	                                     int frnum, int tilex, int tiley, int lift);
206 	Ireg_game_object_shared create_ireg_object(int shnum, int frnum);
207 	Ifix_game_object_shared create_ifix_object(int shnum, int frnum);
208 	// Get all superchunk objects.
209 	void get_superchunk_objects(int schunk);
210 	bool is_tile_occupied(Tile_coord const &tile);
211 	// Locate chunk with desired terrain.
212 	bool locate_terrain(int tnum, int &cx, int &cy, bool upwards = false);
213 	static bool swap_terrains(int tnum);    // Swap adjacent terrain #'s.
214 	// Insert new terrain after 'tnum'.
215 	static bool insert_terrain(int tnum, bool dup = false);
216 	static bool delete_terrain(int tnum);
217 	static void commit_terrain_edits(); // End terrain-editing mode.
218 	static void abort_terrain_edits();
219 	// Search entire game for unused.
220 	void find_unused_shapes(unsigned char *found, int foundlen);
221 	// Locate shape (for EStudio).
222 	Game_object *locate_shape(int shapenum, bool upwards,
223 	                          Game_object *start, int frnum, int qual);
224 	static bool write_minimap();
225 
226 	// Do a cache out. (cx, cy) is the center
227 	void cache_out(int cx, int cy);
228 };
229 
230 #endif
231