1 /*
2  *  objs.h - Game objects.
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 OBJS_H
23 #define OBJS_H
24 
25 #include <string>   // STL string
26 #include <set>
27 #include <memory>
28 #include "exult_constants.h"
29 #include "common_types.h"
30 #include "flags.h"
31 #include "rect.h"
32 #include "shapeid.h"
33 #include "tqueue.h"
34 #include "tiles.h"
35 #include "objlist.h"
36 #include "ignore_unused_variable_warning.h"
37 
38 class Actor;
39 class Map_chunk;
40 class Container_game_object;
41 class Terrain_game_object;
42 class Egg_object;
43 class Barge_object;
44 class Game_window;
45 class Npc_actor;
46 class PathFinder;
47 class Schedule;
48 class TileRect;
49 class Usecode_machine;
50 class Vga_file;
51 class ODataSource;
52 class Game_map;
53 class Object_client;
54 class Spellbook_object;
55 class Virtue_stone_object;
56 class Dead_body;
57 class Ordering_info;
58 
59 template<class T>
60 class T_Object_list;
61 
62 using Game_object_vector = std::vector<Game_object *>;
63 using Egg_vector = std::vector<Egg_object *>;
64 using Actor_vector = std::vector<Actor *>;
65 using Game_object_shared = std::shared_ptr<Game_object>;
66 using Game_object_weak = std::weak_ptr<Game_object>;
67 using Game_object_shared_vector = std::vector<Game_object_shared>;
68 
69 /*
70  *  A game object is a shape from shapes.vga along with info. about its
71  *  position within its chunk.
72  */
73 class Game_object : public ShapeID,
74 					public std::enable_shared_from_this<Game_object> {
75 protected:
76 	static Game_object_shared editing;    // Obj. being edited by ExultStudio.
77 	Map_chunk *chunk = nullptr;       // Chunk we're in, or nullptr.
78 	unsigned char tx, ty;       // (X,Y) of shape within chunk, or if
79 	//   in a container, coords. within
80 	//   gump's rectangle.
81 
82 	unsigned char lift;     // Raise by 4* this number.
83 	short quality;          // Some sort of game attribute.
84 	int get_cxi() const;
85 	int get_cyi() const;
86 private:
87 	Game_object_shared next;   // ->next in chunk list or container.
88     Game_object *prev;
89 public:
90 	using Game_object_set = std::set<Game_object *>;
91 private:
92 	Game_object_set dependencies;   // Objects which must be painted before
93 	//   this can be rendered.
94 	Game_object_set dependors;  // Objects which must be painted after.
95 	static unsigned char rotate[8]; // For getting rotated frame #.
96 	std::vector <Object_client *> clients; // Notify when deleted.
97 public:
98 	uint32 render_seq = 0;      // Render sequence #.
99 	friend class T_Object_list<Game_object>;
100 	friend class T_Object_iterator<Game_object>;
101 	friend class T_Flat_object_iterator<Game_object, Map_chunk *>;
102 	friend class T_Object_iterator_backwards < Game_object,
103 			Map_chunk * >;
104 	friend class Map_chunk;
105 	Game_object(int shapenum, int framenum, unsigned int tilex,
106 	            unsigned int tiley, unsigned int lft = 0)
ShapeID(shapenum,framenum)107 		: ShapeID(shapenum, framenum), tx(tilex), ty(tiley),
108 		  lift(lft), quality(0)
109 	{  }
110 	// Copy constructor.
111 	Game_object(const Game_object &obj2) = delete;
112 	Game_object() = default; // Create fake entry.
113 	~Game_object() override = default;
weak_from_this()114     Game_object_weak weak_from_this() {
115 	    return std::weak_ptr<Game_object>(shared_from_this());
116 	}
get_tx()117 	int get_tx() const {    // Get tile (0-15) within chunk.
118 		return tx;
119 	}
get_ty()120 	int get_ty() const {
121 		return ty;
122 	}
get_lift()123 	int get_lift() const {
124 		return lift;
125 	}
126 	Tile_coord get_tile() const;    // Get location in abs. tiles.
127 	Tile_coord get_center_tile() const; // Get center location in abs. tiles.
128 	// Get missile start location in abs. tiles given dir.
129 	Tile_coord get_missile_tile(int dir) const;
130 	// Get distance to another object.
131 	int distance(const Game_object *o2) const;
132 	// Get direction to another object.
133 	int distance(Tile_coord t2) const;
134 	// Get direction to another object.
135 	int get_direction(Game_object *o2) const;
136 	int get_direction(Tile_coord const &t2) const;
137 	int get_facing_direction(Game_object *o2) const;
get_chunk()138 	Map_chunk *get_chunk() const {  // Get chunk this is in.
139 		return chunk;
140 	}
141 	Game_map *get_map() const; // Map we're on.
142 	int get_map_num() const; // Get map number this is in.
143 	int get_cx() const;
144 	int get_cy() const;
get_quality()145 	int get_quality() const {
146 		return quality;
147 	}
set_quality(int q)148 	void set_quality(int q) {
149 		quality = q;
150 	}
151 	int get_quantity() const;   // Like # of coins.
152 	int get_effective_obj_hp(int weapon_shape = 0) const;   // hitpoints for non-NPCs
153 	virtual int get_obj_hp() const; // hitpoints for non-NPCs
154 	virtual void set_obj_hp(int hp);
155 	int get_volume() const;     // Get space taken.
156 	// Add/remove to/from quantity.
157 	int modify_quantity(int delta, bool *del = nullptr);
158 	// Set shape coord. in chunk/gump.
set_shape_pos(unsigned int shapex,unsigned int shapey)159 	void set_shape_pos(unsigned int shapex, unsigned int shapey) {
160 		tx = shapex;
161 		ty = shapey;
162 	}
set_lift(int l)163 	void set_lift(int l) {
164 		lift = l;
165 	}
get_next()166 	Game_object *get_next() const {
167 		return next.get();
168 	}
get_prev()169 	Game_object *get_prev() const {
170 		return prev;
171 	}
172 	// Compare for render order.
173 	static int compare(Ordering_info &inf1, Game_object *obj2);
174 	int lt(Game_object &obj2);  // Is this less than another in pos.?
set_invalid()175 	void set_invalid() {    // Set to invalid position.
176 		chunk = nullptr;
177 	}
is_pos_invalid()178 	bool is_pos_invalid() const {
179 		return chunk == nullptr;
180 	}
181 	bool inside_locked() const;
set_chunk(Map_chunk * c)182 	void set_chunk(Map_chunk *c) {
183 		chunk = c;
184 	}
185 	// Get frame for desired direction.
get_dir_framenum(int dir,int frnum)186 	int get_dir_framenum(int dir, int frnum) const {
187 		return (frnum & 0xf) + rotate[dir];
188 	}
189 	// Get it using current dir.
get_dir_framenum(int frnum)190 	int get_dir_framenum(int frnum) const {
191 		return (frnum & 0xf) + (get_framenum() & (16 | 32));
192 	}
193 	// Get direction (NPC) is facing.
194 	int get_dir_facing() const;
195 	// Move to new abs. location.
196 	virtual void move(int newtx, int newty, int newlift, int newmap = -1);
197 	void move(Tile_coord const &t, int newmap = -1) {
198 		move(t.tx, t.ty, t.tz, newmap);
199 	}
200 	virtual void change_frame(int frnum);   // Change frame & set to repaint.
201 	// Swap positions.
202 	bool swap_positions(Game_object *obj2);
get_dependencies()203 	Game_object_set &get_dependencies() {
204 		return dependencies;
205 	}
206 	void clear_dependencies();  // Remove all dependencies.
207 
208 	class Egg_cast_functor {
209 	public:
operator()210 		Egg_object *operator()(Game_object *obj) const {
211 			return obj->as_egg();
212 		}
213 	};
214 
215 	class Actor_cast_functor {
216 	public:
operator()217 		Actor *operator()(Game_object *obj) const {
218 			return obj->as_actor();
219 		}
220 	};
221 
222 	class Game_object_cast_functor {
223 	public:
operator()224 		Game_object *operator()(Game_object *obj) const {
225 			return obj;
226 		}
227 	};
228 
229 	template <typename VecType, typename Cast>
230 	static int find_nearby(VecType &vec, Tile_coord const &pos,
231 	                       int shapenum, int delta, int mask, int qual,
232 	                       int framenum, Cast const &obj_cast, bool exclude_okay_to_take = false);
233 
234 	static int find_nearby_actors(Actor_vector &vec, Tile_coord const &pos,
235 	                              int shapenum, int delta, int mask = 8);
236 	static int find_nearby_eggs(Egg_vector &vec, Tile_coord const &pos,
237 	                            int shapenum, int delta, int qual = c_any_qual,
238 	                            int frnum = c_any_framenum);
239 	static int find_nearby(Game_object_vector &vec, Tile_coord const &pos,
240 	                       int shapenum, int delta, int mask, int qual = c_any_qual,
241 	                       int frnum = c_any_framenum,
242 						   bool exclude_okay_to_take = false);
243     static void obj_vec_to_weak(std::vector<Game_object_weak> &dest,
244 													Game_object_vector &src);
245 	int find_nearby_actors(Actor_vector &vec, int shapenum, int delta,
246 	                       int mask = 8) const;
247 	int find_nearby_eggs(Egg_vector &vec, int shapenum, int delta,
248 	                     int qual = c_any_qual, int frnum = c_any_framenum) const;
249 	int find_nearby(Game_object_vector &vec, int shapenum, int delta,
250 	                int mask, int qual = c_any_qual, int framenum = c_any_framenum) const;
251 	Game_object *find_closest(Game_object_vector &vec,
252 	                          int *shapenums, int num_shapes, int dist = 24);
253 	static Game_object *find_closest(Tile_coord const &pos,
254 	                                 int *shapenums, int num_shapes, int dist = 24);
255 	Game_object *find_closest(int *shapenums, int num_shapes,
256 	                          int dist = 24) {
257 		return find_closest(get_tile(), shapenums,
258 		                    num_shapes, dist);
259 	}
260 	Game_object *find_closest(int shapenum, int dist = 24) {
261 		return find_closest(&shapenum, 1, dist);
262 	}
263 	static Game_object *find_closest(Tile_coord const &pos, int shapenum,
264 	                                 int dist = 24) {
265 		return find_closest(pos, &shapenum, 1, dist);
266 	}
267 	TileRect get_footprint();  // Get tile footprint.
268 	Block get_block() const;
269 	bool blocks(Tile_coord const &tile) const;    // Do we block a given tile?
270 	// Find object blocking given tile.
271 	static Game_object *find_blocking(Tile_coord tile);
272 	static Game_object *find_door(Tile_coord tile);
273 	bool is_closed_door() const; // Checking for a closed door.
274 	Game_object *get_outermost();   // Get top 'owner' of this object.
275 	void say(const char *text);     // Put text up by item.
276 	void say(int msgnum);       // Show given text msg.
277 	void say(int from, int to); // Show random msg. from 'text.flx'.
278 	// Render.
279 	virtual void paint();
280 	void paint_outline(Pixel_colors pix);
281 	// Make this class abstract.
282 	virtual void paint_terrain() = 0;
283 	// Can this be clicked on?
is_findable()284 	virtual bool is_findable() {
285 		return true;
286 	}
287 	// Run usecode function.
288 	virtual void activate(int event = 1);
289 	virtual bool edit();        // Edit in ExultStudio.
290 	// Saved from ExultStudio.
291 	static void update_from_studio(unsigned char *data, int datalen);
292 	virtual std::string get_name() const;
293 	// Remove/delete this object.
294 	virtual void remove_this(Game_object_shared *keep = nullptr);
get_owner()295 	virtual Container_game_object *get_owner() const {
296 		return nullptr;
297 	}
set_owner(Container_game_object * o)298 	virtual void set_owner(Container_game_object *o) {
299 		ignore_unused_variable_warning(o);
300 	}
301 	static int get_weight(int shnum, int quant = 1);
302 	virtual int get_weight();
303 	virtual int get_max_weight() const;   // Get max. weight allowed.
304 	virtual bool is_dragable() const;// Can this be dragged?
305 	// Drop another onto this.
306 	virtual bool drop(Game_object *obj);
307 	// Set/clear/get actor flag.
set_flag(int flag)308 	virtual void set_flag(int flag) {
309 		ignore_unused_variable_warning(flag);
310 	}
clear_flag(int flag)311 	virtual void clear_flag(int flag) {
312 		ignore_unused_variable_warning(flag);
313 	}
get_flag(int flag)314 	virtual bool get_flag(int flag) const  {
315 		ignore_unused_variable_warning(flag);
316 		return false;
317 	}
set_flag_recursively(int flag)318 	virtual void set_flag_recursively(int flag) {
319 		ignore_unused_variable_warning(flag);
320 	}
get_type_flag(int flag)321 	virtual bool get_type_flag(int flag) const {
322 		ignore_unused_variable_warning(flag);
323 		return false;
324 	}
325 
as_actor()326 	virtual Actor *as_actor() {
327 		return nullptr;
328 	}
as_npc()329 	virtual Npc_actor *as_npc() {
330 		return nullptr;
331 	}
as_barge()332 	virtual Barge_object *as_barge() {
333 		return nullptr;
334 	}
as_terrain()335 	virtual Terrain_game_object *as_terrain() {
336 		return nullptr;
337 	}
as_container()338 	virtual Container_game_object *as_container() {
339 		return nullptr;
340 	}
as_egg()341 	virtual Egg_object *as_egg() {
342 		return nullptr;
343 	}
as_spellbook()344 	virtual Spellbook_object *as_spellbook() {
345 		return nullptr;
346 	}
as_virtstone()347 	virtual Virtue_stone_object *as_virtstone() {
348 		return nullptr;
349 	}
as_body()350 	virtual Dead_body *as_body() {
351 		return nullptr;
352 	}
is_egg()353 	virtual int is_egg() const { // An egg?
354 		return 0;
355 	}
read_attributes(const unsigned char * buf,int len)356 	virtual void read_attributes(const unsigned char *buf, int len) {
357 		ignore_unused_variable_warning(buf, len);
358 	}
359 	// Count contained objs.
360 	virtual int count_objects(int shapenum, int qual = c_any_qual,
361 	                          int framenum = c_any_framenum) {
362 		ignore_unused_variable_warning(shapenum, qual, framenum);
363 		return 0;
364 	}
365 	// Get contained objs.
get_objects(Game_object_vector & vec,int shapenum,int qual,int framenum)366 	virtual int get_objects(Game_object_vector &vec, int shapenum, int qual,
367 	                        int framenum) {
368 		ignore_unused_variable_warning(vec, shapenum, qual, framenum);
369 		return 0;
370 	}
371 	// Add an object.
372 	virtual bool add(Game_object *obj, bool dont_check = false,
373 	                 bool combine = false, bool noset = false);
374 	// Add to NPC 'ready' spot.
375 	virtual bool add_readied(Game_object *obj, int index,
376 	                        bool dont_check = false, bool force_pos = false, bool noset = false) {
377 		ignore_unused_variable_warning(index, force_pos);
378 		return add(obj, dont_check, false, noset);
379 	}
380 	virtual int add_quantity(int delta, int shapenum, int qual = c_any_qual,
381 	                         int framenum = c_any_framenum, bool dontcreate = false, bool temporary = false) {
382 		ignore_unused_variable_warning(shapenum, qual, framenum, dontcreate, temporary);
383 		return delta;
384 	}
385 	virtual int create_quantity(int delta, int shapenum, int qual,
386 	                            int framenum, bool temporary = false) {
387 		ignore_unused_variable_warning(shapenum, qual, framenum, temporary);
388 		return delta;
389 	}
remove_quantity(int delta,int shapenum,int qual,int framenum)390 	virtual int remove_quantity(int delta, int shapenum, int qual,
391 	                            int framenum) {
392 		ignore_unused_variable_warning(shapenum, qual, framenum);
393 		return delta;
394 	}
find_item(int shapenum,int qual,int framenum)395 	virtual Game_object *find_item(int shapenum, int qual, int framenum) {
396 		ignore_unused_variable_warning(shapenum, qual, framenum);
397 		return nullptr;
398 	}
399 	// Get coord. where this was placed.
get_original_tile_coord()400 	virtual Tile_coord get_original_tile_coord() const {
401 		return get_tile();
402 	}
403 	// Move out of the way.
move_aside(Actor * for_actor,int dir)404 	virtual bool move_aside(Actor *for_actor, int dir) {
405 		ignore_unused_variable_warning(for_actor, dir);
406 		return false;    // For now.
407 	}
408 	// Get frame if rotated clockwise.
409 	virtual int get_rotated_frame(int quads) const;
410 	// Step onto an (adjacent) tile.
411 	virtual bool step(Tile_coord t, int frame, bool force = false) {
412 		ignore_unused_variable_warning(t, frame, force);
413 		return false;
414 	}
is_monster()415 	virtual bool is_monster() const {
416 		return false;
417 	}
418 	virtual Game_object *find_weapon_ammo(int weapon, int needed = 1,
419 	                                      bool recursive = false) {
420 		ignore_unused_variable_warning(weapon, needed, recursive);
421 		return nullptr;
422 	}
423 	virtual int get_effective_range(const Weapon_info *winf = nullptr, int reach = -1) const;
424 	int get_weapon_ammo(int weapon, int family, int proj, bool ranged,
425 	                    Game_object **ammo = nullptr, bool recursive = false);
426 	void play_hit_sfx(int weapon, bool ranged);
try_to_hit(Game_object * attacker,int attval)427 	virtual bool try_to_hit(Game_object *attacker, int attval) {
428 		ignore_unused_variable_warning(attacker, attval);
429 		return true;
430 	}
431 	// Under attack.
432 	virtual Game_object *attacked(Game_object *attacker, int weapon_shape = -1,
433 	                              int ammo_shape = -1, bool explosion = false);
434 	// Hit-point algorithm:
435 	virtual int figure_hit_points(Game_object *attacker, int weapon_shape = -1,
436 	                              int ammo_shape = -1, bool explosion = false);
437 	virtual int apply_damage(Game_object *attacker, int str,
438 	                         int wpoints, int type, int bias = 0, int *exp = nullptr);
439 	virtual int reduce_health(int delta, int damage_type, Game_object *attacker = nullptr,
440 	                          int *exp = nullptr);
441 	// Write out to IREG file.
write_ireg(ODataSource * out)442 	virtual void write_ireg(ODataSource *out) {
443 		ignore_unused_variable_warning(out);
444 	}
445 	// Get size of IREG. Returns -1 if can't write to buffer
get_ireg_size()446 	virtual int get_ireg_size() {
447 		return 0;
448 	}
449 	// Write out IFIX, CHUNKS.
write_ifix(ODataSource * ifix,bool v2)450 	virtual void write_ifix(ODataSource *ifix, bool v2) {
451 		ignore_unused_variable_warning(ifix, v2);
452 	}
elements_read()453 	virtual void elements_read()    // Called when all member items read.
454 	{  }
get_live_npc_num()455 	virtual int get_live_npc_num() const {
456 		return -1;
457 	}
458 
delete_contents()459 	virtual void delete_contents() { }
460 
461 	// Return's the object's usecode for the shape number
462 	virtual int get_usecode() const;
463 	// Default:  Can't set it.
464 	virtual bool set_usecode(int ui, const char *nm = nullptr);
465 	bool usecode_exists() const;
466 };
467 
weak_from_obj(Game_object * obj)468 inline Game_object_weak weak_from_obj(Game_object *obj) {
469     return obj ? obj->weak_from_this() : Game_object_weak();
470 }
shared_from_obj(Game_object * obj)471 inline Game_object_shared shared_from_obj(Game_object *obj) {
472     return obj ? obj->shared_from_this() : Game_object_shared();
473 }
474 
475 /*
476  *  Object from U7chunks.
477  */
478 class Terrain_game_object : public Game_object {
479 	ShapeID prev_flat;
480 public:
481 	Terrain_game_object(int shapenum, int framenum, unsigned int tilex,
482 	                    unsigned int tiley, unsigned int lft = 0)
Game_object(shapenum,framenum,tilex,tiley,lft)483 		: Game_object(shapenum, framenum, tilex, tiley, lft),
484 		  prev_flat(ShapeID(12, 0))
485 	{  }
486 	~Terrain_game_object() override = default;
as_terrain()487 	Terrain_game_object *as_terrain() override {
488 		return this;
489 	}
490 	// Move to new abs. location.
491 	void move(int newtx, int newty, int newlift, int newmap = -1) override;
492 	// Remove/delete this object.
493 	void remove_this(Game_object_shared *keep = nullptr) override;
494 	void paint_terrain() override;
495 };
496 
497 /*
498  *  Object from an IFIXxx file.
499  */
500 class Ifix_game_object : public Game_object {
501 public:
502 	Ifix_game_object(int shapenum, int framenum, unsigned int tilex,
503 	                 unsigned int tiley, unsigned int lft = 0)
Game_object(shapenum,framenum,tilex,tiley,lft)504 		: Game_object(shapenum, framenum, tilex, tiley, lft)
505 	{  }
506 	~Ifix_game_object() override = default;
507 	// Move to new abs. location.
508 	void move(int newtx, int newty, int newlift, int newmap = -1) override;
509 	// Remove/delete this object.
510 	void remove_this(Game_object_shared *keep = nullptr) override;
paint_terrain()511 	void paint_terrain() override {  }
512 	void write_ifix(ODataSource *ifix, bool v2) override;
513 };
514 
515 #endif
516