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