/*
 *  Copyright (C) 2000-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 CHEAT_H
#define CHEAT_H

#include <memory>
#include <vector>
#include "singles.h"

class Game_window;
class ShapeBrowser;
class SoundTester;
class CheatScreen;
class Actor;
class Game_object;
class Tile_coord;
class Effects_manager;
class Map_chunk;

using Game_object_shared = std::shared_ptr<Game_object>;

class Cheat : public Game_singletons {
public:
	Cheat();
	~Cheat();

	void init();
	void finish_init();
	enum Map_editor_mode {
	    move = 0,           // Normal dragging.
	    paint = 1,          // Left-mouse dragging paints shapes.
	    paint_chunks = 2,       // Left-dragging paints whole chunks.
	    combo_pick = 3,         // Left-click adds item to combo.
	    select_chunks = 4       // Select whole chunks.
	};
private:
	ShapeBrowser *browser;
	SoundTester *tester;
	CheatScreen *cscreen;

	bool god_mode;
	bool wizard_mode;
	bool map_editor;
	bool tile_grid;
	Map_editor_mode edit_mode;
	int  edit_lift;
	int  edit_shape, edit_frame;      // What to 'paint' with.
	int  edit_chunknum;           // For painting with chunks.
	std::vector<Game_object_shared> selected;   // Selected objects (map-editing).
	std::vector<Game_object_shared> clipboard;  // Cut/copy/paste objects.
	bool infravision;
	bool pickpocket;
	bool grab_actor;
	bool npc_numbers;
	bool hack_mover;

	bool enabled;
	// Rectangle containing selected chunks:
	int chunksel_left, chunksel_right, chunksel_top, chunksel_bottom;

	void send_select_status();
public:
	bool operator()() const {
		return enabled;
	}
	void set_enabled(bool en);

	bool in_god_mode() const {
		return god_mode;
	}
	bool in_wizard_mode() const {
		return wizard_mode;
	}
	bool in_map_editor() const {
		return map_editor;
	}
	bool show_tile_grid() const {
		return map_editor && tile_grid;
	}
	Map_editor_mode get_edit_mode() const {
		return edit_mode;
	}
	int  get_edit_lift() const {
		return edit_lift;
	}
	int  get_edit_shape() const {
		return edit_shape;
	}
	int  get_edit_frame() const {
		return edit_frame;
	}
	int  get_edit_chunknum() const {
		return edit_chunknum;
	}
	bool in_infravision() const {
		return infravision;
	}
	bool in_pickpocket() const {
		return pickpocket;
	}
	bool in_hack_mover() const {
		return hack_mover || map_editor;
	}

	void toggle_god();
	void set_god(bool god) {
		god_mode = god;
	}
	void toggle_wizard();
	void set_wizard(bool wizard) {
		wizard_mode = wizard;
	}
	void toggle_map_editor();
	void toggle_tile_grid();
	void set_edit_mode(Map_editor_mode md);
	void clear_chunksel();
	void add_chunksel(Map_chunk *chunk, bool extend = false);
	void move_chunk(Map_chunk *chunk, int dx, int dy);
	void move_selected_chunks(int dx, int dy);
	void set_edit_lift(int lift);
	void set_edit_shape(int sh, int fr);
	void set_edit_chunknum(int chnum) {
		edit_chunknum = chnum;
	}
	void set_map_editor(bool map) {
		if (map_editor != map)
			toggle_map_editor();
	}
	void toggle_infravision();
	void set_infravision(bool infra) {
		infravision = infra;
	}
	void toggle_pickpocket();
	void set_pickpocket(bool pick) {
		pickpocket = pick;
	}
	void toggle_hack_mover();
	void set_hack_mover(bool hm) {
		hack_mover = hm;
	}

	void toggle_eggs() const;
	void change_gender() const;

	void toggle_Petra() const;
	void toggle_naked() const;
	void change_skin() const;

	void levelup_party() const;
	void heal_party() const;

	void fake_time_period() const;
	void dec_skip_lift() const;
	void set_skip_lift(int skip) const;

	void append_selected(Game_object *obj);
	void toggle_selected(Game_object *obj);
	void clear_selected();
	void delete_selected();
	void move_selected_objs(int dx, int dy, int dz);
	void move_selected(int dx, int dy, int dz);
	const std::vector<Game_object_shared> &get_selected() const {
		return selected;
	}
	bool is_selected(Game_object *o);

	void cut(bool copy = false);
	void paste(int mx, int my);
	void paste();
	const std::vector<Game_object_shared> &get_clipboard() const {
		return clipboard;
	}

	void map_teleport() const;
	void cursor_teleport() const;
	void next_map_teleport() const;

	void create_coins() const;
	void create_last_shape() const;
	void delete_object();
	void shape_browser() const;
	bool get_browser_shape(int &shape, int &frame) const;
	void sound_tester() const;

	void cheat_screen() const;

	bool grabbing_actor() const {
		return grab_actor;
	}
	void toggle_grab_actor();
	void set_grab_actor(bool grab) {
		grab_actor = grab;
	}
	void set_grabbed_actor(Actor *actor) const;
	void clear_this_grabbed_actor(Actor *actor) const;

	bool number_npcs() const {
		return npc_numbers;
	}
	void toggle_number_npcs();
	void set_number_npcs(bool num) {
		npc_numbers = num;
	}
};

extern Cheat cheat;

#endif
