/**
 ** Barge.h - Ships, carts, flying-carpets.
 **
 ** Written: 7/13/2000 - JSF
 **/

/*
Copyright (C) 2000  Jeffrey S. Freedman
Copyright (C) 2001-2022  The Exult Team

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#ifndef INCL_BARGE
#define INCL_BARGE  1

#include "contain.h"

/*
 *  A 'barge', such as a ship or horse-and-cart.  The elements of a barge
 *  are stored in the outside world, so rendering and obstacle detection
 *  don't have to be reimplemented.
 */
class Barge_object : public Container_game_object, public Time_sensitive {
	static Game_object_shared editing;   // Egg being edited by ExultStudio.
    std::vector<Game_object_shared> objects; // All objects in/on barge.
	int perm_count;         // Counts permanent parts of barge,
	//   which proceed those placed on it.
	unsigned char xtiles, ytiles;   // Tiles covered (when vertical).
	unsigned char dir;      // Direction: 0=N, 1=E, 2=S, 3=W.
	bool complete;          // Flag:  all members have been read.
	bool gathered;          // Items on barge have been gathered.
	bool ice_raft;          // For Serpent Isle.
	bool first_step;        // So first motion can just be 1 tile.
	bool taking_2nd_step;       // Skip animation on 2nd step.
	signed char boat;       // 1 if a boat, 0 if not; -1=untested.
	int frame_time;         // Time between frames in msecs.  0 if
	//   not moving.
	PathFinder *path;       // For traveling.
	Tile_coord center;      // Center of barge.
	Game_object *get_object(int i) const {
		return objects[i].get();
	}
	void swap_dims();
	void set_center();
	int okay_to_rotate(Tile_coord const &pos);
	void add_dirty();
	// Finish up move/rotate operation.
	void finish_move(Tile_coord *positions, int newmap = -1);
public:
	Barge_object(int shapenum, int framenum,
	             unsigned int shapex, unsigned int shapey, unsigned int lft,
	             int xt, int yt, int d)
		: Container_game_object(shapenum, framenum,
		                        shapex, shapey, lft),
		perm_count(0),
		xtiles(xt), ytiles(yt), dir(d),
		complete(false), gathered(false), ice_raft(false),
		first_step(true), taking_2nd_step(false),
		boat(-1), frame_time(0), path(nullptr)
	{  }
	TileRect get_tile_footprint();
	bool is_moving() const {
		return frame_time > 0;
	}
	int get_xtiles() const {      // Dims. in tiles.
		return xtiles;
	}
	int get_ytiles() const {
		return ytiles;
	}
	Tile_coord get_center() const {
		return center;
	}
	~Barge_object() override;
	void set_to_gather() {      // Require 'gather' on next move.
		gathered = false;
	}
	void gather();          // Gather up objects on barge.
	void face_direction(int ndir);  // Face dir. (0-7).
	// Start rolling/sailing.
	void travel_to_tile(Tile_coord const &dest, int speed);
	void turn_right();      // Turn 90 degrees right.
	void turn_left();
	void turn_around();
	void stop() {       // Stop moving.
		frame_time = 0;
		first_step = true;
	}
	void done();            // No longer being operated.
	int okay_to_land();     // See if clear to land.
	Barge_object *as_barge() override {
		return this;
	}
	// For Time_sensitive:
	void handle_event(unsigned long curtime, uintptr udata) override;
	// Move to new abs. location.
	void move(int newtx, int newty, int newlift, int newmap = -1) override;
	// Remove an object.
	void remove(Game_object *obj) override;
	// Add an object.
	bool add(Game_object *obj, bool dont_check = false,
	         bool combine = false, bool noset = false) override;
	bool contains(Game_object *obj);
	// Drop another onto this.
	bool drop(Game_object *obj) override;
	// Render.
	void paint() override;
	void activate(int event = 1) override;
	bool edit() override;        // Edit in ExultStudio.
	// Saved from ExultStudio.
	static void update_from_studio(unsigned char *data, int datalen);
	// Step onto an (adjacent) tile.
	bool step(Tile_coord t, int frame = -1, bool force = false) override;
	// Write out to IREG file.
	void write_ireg(ODataSource *out) override;
	// Get size of IREG. Returns -1 if can't write to buffer
	int get_ireg_size() override;
	void elements_read() override;   // Called when all member items read.
};

#endif
