#ifndef ARCANE__UTIL_H
#define ARCANE__UTIL_H

/*
 * arcane - A rogue-like game engine
 * Copyright (C) 2005  Petr Baudis <pasky@ucw.cz>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * 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
 */

#include <sstream>
#include <string>

#include "prop.h"


enum Direction {
	DIR_N = 0,
	DIR_NE = 1,
	DIR_E = 2,
	DIR_SE = 3,
	DIR_S = 4,
	DIR_SW = 5,
	DIR_W = 6,
	DIR_NW = 7,

	DIRS = 8
};

inline enum Direction
revdir(enum Direction dir)
{
	return enum Direction((int(dir) + DIRS/2) % DIRS);
}

inline enum Direction
getdir(unsigned x1, unsigned y1, unsigned x2, unsigned y2, int &hint)
{
	enum Direction dir;
	enum { X, Y, Z } hint_s;

	// cotan(pi/3)*10 = 6, cotan(pi/6)*10 = 17
	if (y1 == y2 || abs(int(x1 - x2) * 10 / int(y1 - y2)) > 17) {
		dir = DIR_W;
		hint = (y1 > y2) ? 1 : -1;
		hint_s = Y;
	} else if (abs(int(x1 - x2) * 10 / int(y1 - y2)) > 6) {
		dir = DIR_NW;
		hint = 0;
		hint_s = Z;
	} else {
		dir = enum Direction(DIRS + DIR_N);
		hint = (x1 > x2) ? -1 : 1;
		hint_s = X;
	}

	if (y2 > y1) {
		dir = enum Direction(DIR_W - (int(dir) - DIR_W));
		if (hint_s == X) hint = -hint;
	}
	if (x2 > x1) {
		dir = enum Direction(DIRS - int(dir));
		if (hint_s == Y) hint = -hint;
	}

	if (dir < 0)
		dir = enum Direction(int(dir) + DIRS);
	return enum Direction(int(dir) % DIRS);
}


inline long min(long a, long b) { return a < b ? a : b; }
inline long max(long a, long b) { return a > b ? a : b; }

inline int sgn(long x) { return x > 0 ? 1 : x < 0 ? -1 : 0; }


// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html
inline std::string
tostr(long x, int width = 0)
{
	std::ostringstream o;
	if (width)
		o.width(width);
	o << x;
	return o.str();
}
inline std::string
tostr(unsigned long x, int width = 0)
{
	std::ostringstream o;
	if (width)
		o.width(width);
	o << x;
	return o.str();
}
inline std::string
tostr(int x, int width = 0)
{
	return tostr(long(x), width);
}

inline int
rand(int max)
{
	return max != 0 ? rand() % max : 0;
}

inline unsigned long
rand(unsigned long max)
{
	return max != 0 ? (unsigned long)(rand()) % max : 0;
}


struct Dice {
	int bonus, rolls, amount;
};

inline int
dice(Dice &dice)
{
	int r = dice.bonus;
	for (int i = 0; i < dice.rolls; i++)
		r += 1 + rand(dice.amount - 1);
	return r;
}

inline unsigned
prob_in_danger(int base_prob, int danger_obj, int danger_env)
{
	unsigned freq;
	
	if (danger_obj < danger_env) {
		freq = 100 / ((3 + danger_env - danger_obj) / 3);
	} else {
		// qhack, but reduced
		//unsigned probdan[14] = { 100, 90, 80, 72, 64, 56, 50, 42, 35, 28, 20, 12, 4, 1 };
		unsigned probdan[15] = { 100, 85, 70, 62, 54, 36, 30, 22, 18, 15, 10, 8, 4, 2, 1 };
		freq = probdan[min(danger_obj - danger_env, 14)];
	}

	return base_prob * max(1, freq) / 100;
}

#endif
