1 /*
2  *  Copyright (C) 2000-2013  The Exult Team
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 #ifndef SHAPEID_H
20 #define SHAPEID_H   1
21 
22 #include "exult_constants.h"
23 #include "shapevga.h"
24 #include "fontvga.h"
25 #include "singles.h"
26 #include <vector>
27 #include <memory>
28 
29 
30 class Shape_frame;
31 class Shape_info;
32 class Font;
33 class Image_buffer8;
34 struct Cursor_info;
35 
36 enum ShapeFile {
37     SF_SHAPES_VGA = 0,  // <STATIC>/shapes.vga.  MUST be first.
38     SF_GUMPS_VGA,       // <STATIC>/gumps.vga
39     SF_PAPERDOL_VGA,    // <STATIC>/paperdol.vga
40     SF_SPRITES_VGA,     // <STATIC>/sprites.vga
41     SF_FACES_VGA,       // <STATIC>/faces.vga
42     SF_EXULT_FLX,       // <DATA>/exult.flx
43     SF_GAME_FLX,        // <DATA>/bg_data.flx or <DATA>/si_data.flx
44     // Not yet
45     //SF_FONTS_VGA,     // <STATIC>/fonts.vga
46     SF_OTHER,       // Other unknown FLX
47     SF_COUNT        // # of preceding entries.
48 };
49 
50 // Special pixels.
51 enum Pixel_colors {POISON_PIXEL = 0, PROTECT_PIXEL, CURSED_PIXEL,
52                    CHARMED_PIXEL, HIT_PIXEL, PARALYZE_PIXEL, BLACK_PIXEL, NPIXCOLORS
53                   };
54 
55 /*
56  *  Manage the set of shape files.
57  */
58 class Shape_manager : public Game_singletons {
59 	static Shape_manager *instance; // There shall be only one.
60 	Shapes_vga_file shapes;     // Main 'shapes.vga' file.
61 	Vga_file files[static_cast<int>(SF_COUNT)]; // The files we manage.
62 	std::unique_ptr<Fonts_vga_file> fonts = nullptr;      // "fonts.vga" file.
63 	std::vector<Xform_palette> xforms;  // Transforms translucent colors
64 	//   0xf4 through 0xfe.
65 	Xform_palette *invis_xform; // For showing invisible NPC's.
66 	unsigned char special_pixels[NPIXCOLORS];   // Special colors.
67 	bool can_have_paperdolls = false;   // Set true if the SI paperdoll file
68 	//   is found when playing BG
69 	bool paperdolls_enabled = false;    // True if paperdolls are on.
70 	bool got_si_shapes = false; // Set true if the SI shapes file
71 	//   is found when playing BG
72 	void read_shape_info();
73 
74 public:
75 	friend class ShapeID;
76 	Shape_manager();
77 	~Shape_manager();
get_instance()78 	static Shape_manager *get_instance() {
79 		return instance;
80 	}
81 	void load();            // Read in files.
82 	bool load_gumps_minimal();          // Read in files needed to display gumps.
83 	void reload_shapes(int dragtype);   // Reload a shape file.
84 	void reload_shape_info();
get_file(ShapeFile f)85 	Vga_file &get_file(ShapeFile f) {
86 		return files[static_cast<int>(f)];
87 	}
get_shapes()88 	Shapes_vga_file &get_shapes() {
89 		return shapes;
90 	}
get_xform(int i)91 	inline Xform_palette &get_xform(int i) {
92 		return xforms[i];
93 	}
94 	// BG Only
can_use_paperdolls()95 	inline bool can_use_paperdolls() const {
96 		return can_have_paperdolls;
97 	}
98 
are_paperdolls_enabled()99 	inline bool are_paperdolls_enabled() const {
100 		return paperdolls_enabled;
101 	}
102 
set_paperdoll_status(bool p)103 	inline void set_paperdoll_status(bool p) {
104 		paperdolls_enabled = p;
105 	}
106 
have_si_shapes()107 	inline bool have_si_shapes() const {
108 		return got_si_shapes;
109 	}
110 
111 	// Paint shape in window.
112 	void paint_shape(int xoff, int yoff, Shape_frame *shape,
113 	                 bool translucent = false, unsigned char *trans = nullptr) {
114 		if (!shape || !shape->get_data())
115 			CERR("nullptr SHAPE!!!");
116 		else if (!shape->is_rle())
117 			shape->paint(xoff, yoff);
118 		else if (trans)
119 			shape->paint_rle_remapped(xoff, yoff, trans);
120 		else if (!translucent)
121 			shape->paint_rle(xoff, yoff);
122 		else
123 			shape->paint_rle_translucent(xoff, yoff, &xforms[0], xforms.size());
124 	}
125 
paint_invisible(int xoff,int yoff,Shape_frame * shape)126 	inline void paint_invisible(int xoff, int yoff, Shape_frame *shape) {
127 		if (shape) shape->paint_rle_transformed(
128 			    xoff, yoff, *invis_xform);
129 	}
130 	// Paint outline around a shape.
paint_outline(int xoff,int yoff,Shape_frame * shape,Pixel_colors pix)131 	inline void paint_outline(int xoff, int yoff, Shape_frame *shape,
132 	                          Pixel_colors pix) {
133 		if (shape) shape->paint_rle_outline(
134 			    xoff, yoff, special_pixels[static_cast<int>(pix)]);
135 	}
get_special_pixel(Pixel_colors pix)136 	unsigned char get_special_pixel(Pixel_colors pix) {
137 		return special_pixels[static_cast<int>(pix)];
138 	}
139 
140 	// Paint text using "fonts.vga".
141 	int paint_text_box(int fontnum, const char *text, int x, int y, int w,
142 	                   int h, int vert_lead = 0, bool pbreak = false,
143 	                   bool center = false, int shading = -1, Cursor_info *cursor = nullptr);
144 	int paint_text(int fontnum, const char *text, int xoff, int yoff);
145 	int paint_text(int fontnum, const char *text, int textlen,
146 	               int xoff, int yoff);
147 	// Get text width.
148 	int get_text_width(int fontnum, const char *text);
149 	int get_text_width(int fontnum, const char *text, int textlen);
150 	// Get text height, baseline.
151 	int get_text_height(int fontnum);
152 	int get_text_baseline(int fontnum);
153 	int find_cursor(int fontnum, const char *text, int x, int y,
154 	                int w, int h, int cx, int cy, int vert_lead);
155 	Font *get_font(int fontnum);
get_xforms_cnt()156 	size_t get_xforms_cnt() const {
157 		return xforms.size();
158 	}
159 };
160 
161 /*
162  *  A shape ID contains a shape # and a frame # within the shape encoded
163  *  as a 2-byte quantity.
164  */
165 class ShapeID : public Game_singletons {
166 	short shapenum = -1;             // Shape #.
167 	signed char framenum = -1;       // Frame # within shape.
168 	mutable bool has_trans = false;
169 	ShapeFile shapefile = SF_SHAPES_VGA;
170 	mutable Shape_frame *shape = nullptr;
171 	mutable Shape_info *info = nullptr;
172 
173 	Shape_frame *cache_shape() const;
174 
175 public:
176 	// Read from buffer & incr. ptr.
ShapeID(unsigned char * & data)177 	ShapeID(unsigned char  *&data) {
178 		unsigned char l = *data++;
179 		unsigned char h = *data++;
180 		shapenum = l + 256 * (h & 0x3);
181 		framenum = h >> 2;
182 	}
183 	// Create "end-of-list"/invalid entry.
184 	ShapeID() = default;
185 
186 	ShapeID(const ShapeID&) = default;
187 	ShapeID& operator=(const ShapeID&) = default;
188 	ShapeID(ShapeID&&) noexcept = default;
189 	ShapeID& operator=(ShapeID&&) noexcept = default;
190 	virtual ~ShapeID() = default;
191 	// End-of-list or invalid?
is_invalid()192 	bool is_invalid() const {
193 		return shapenum == -1;
194 	}
is_eol()195 	bool is_eol() const {
196 		return is_invalid();
197 	}
198 
get_shapenum()199 	inline int get_shapenum() const {
200 		return shapenum;
201 	}
get_framenum()202 	inline int get_framenum() const {
203 		return framenum;
204 	}
get_shapefile()205 	inline ShapeFile get_shapefile() const {
206 		return shapefile;
207 	}
get_shape()208 	inline Shape_frame *get_shape() const {
209 		if (shape == nullptr) {
210 			cache_shape();
211 		}
212 		return shape;
213 	}
set_translucent(bool trans)214 	inline void set_translucent(bool trans) {
215 		has_trans = trans;
216 	}
is_translucent()217 	inline bool is_translucent() const {
218 		if (shape == nullptr) {
219 			cache_shape();
220 		}
221 		return has_trans;
222 	}
223 	// Set to given shape.
set_shape(int shnum,int frnum)224 	void set_shape(int shnum, int frnum) {
225 		shapenum = shnum;
226 		framenum = frnum;
227 		shape = nullptr;
228 		info = nullptr;
229 	}
230 	ShapeID(int shnum, int frnum, ShapeFile shfile = SF_SHAPES_VGA) :
shapenum(shnum)231 		shapenum(shnum), framenum(frnum), shapefile(shfile)
232 	{  }
233 
set_shape(int shnum)234 	void set_shape(int shnum) { // Set shape, but keep old frame #.
235 		shapenum = shnum;
236 		shape = nullptr;
237 		info = nullptr;
238 	}
set_frame(int frnum)239 	void set_frame(int frnum) { // Set to new frame.
240 		framenum = frnum;
241 		shape = nullptr;
242 	}
set_file(ShapeFile shfile)243 	void set_file(ShapeFile shfile) { // Set to new flex
244 		shapefile = shfile;
245 		shape = nullptr;
246 	}
247 
248 	void paint_shape(int xoff, int yoff, bool force_trans = false) {
249 		sman->paint_shape(xoff, yoff, get_shape(),
250 		                  has_trans || force_trans);
251 	}
paint_invisible(int xoff,int yoff)252 	void paint_invisible(int xoff, int yoff) {
253 		sman->paint_invisible(xoff, yoff, get_shape());
254 	}
255 	// Paint outline around a shape.
paint_outline(int xoff,int yoff,Pixel_colors pix)256 	inline void paint_outline(int xoff, int yoff, Pixel_colors pix) {
257 		sman->paint_outline(xoff, yoff, get_shape(), pix);
258 	}
259 	int get_num_frames() const;
260 	bool is_frame_empty() const;
get_info()261 	const Shape_info &get_info() const {  // Get info. about shape.
262 		return *(info ? info : info =
263 		             &Shape_manager::instance->shapes.get_info(shapenum));
264 	}
get_info()265 	Shape_info &get_info() { // Get info. about shape.
266 		return *(info ? info : info =
267 		             &Shape_manager::instance->shapes.get_info(shapenum));
268 	}
get_info(int shnum)269 	static Shape_info &get_info(int shnum) { // Get info. about shape.
270 		return Shape_manager::instance->shapes.get_info(shnum);
271 	}
272 };
273 
274 /*
275  *  An interface used in Get_click():
276  */
277 class Paintable {
278 public:
279 	virtual void paint() = 0;
280 	virtual ~Paintable() = default;
281 };
282 
283 #endif
284