/*  equip.c: (c) 2002 sibn

    This file is part of GWiz.

    GWiz 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.

    GWiz 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 GWiz; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_ttf.h>
#include "gwiz.h"
#include "inspect.h"
#include "equip.h"
#include "items.h"
#include "joystick.h"
#include "uiloop.h"
#include "text.h"

#define EQUIPPED (USAGE_EQUIPPABLE|USAGE_EQUIPPED)

extern GwizApp gwiz;

/* Long, long name.  Global int made more sense to me here, so uh, heh. */
int equipmenucursorposition = -1;

void Equip (GwizInspector *gi, PlayerPawn *pawn)
{
    int i;

    for (i = 0; i < 8; i++) /* precursory check: items to equip? */
	if (pawn->item[i].usage & USAGE_EQUIPPABLE)
	    break;
	else 
	    if (i == 7) /* end of the list, nothing equippable yet */
		return;

    equipmenucursorposition = GetNextEquippableItem (pawn);
    if (equipmenucursorposition == -1)
	return; /* No equippable items on this pawn */
    EquipMenuLoop (gi, pawn);
}

/* Equip item if possible, unequip if already equipped (and not cursed) */
void FlipEquippedState (GwizInspector *gi, PlayerPawn *pawn)
{
    int position = equipmenucursorposition;
    int errcode = FALSE;

    if (pawn->item[position].usage & USAGE_EQUIPPED)
	{
	    if (pawn->item[position].special & CURSED)
		return; /* cannot remove cursed items */
	    pawn->item[position].usage = (pawn->item[position].usage ^
					  USAGE_EQUIPPED);
	    SetInspectorInventory (gi, pawn);
	} else {
	    if (PawnItemCompatible (pawn->class, 
				    pawn->item[position].usage) == FALSE)
		return; /* This pawn cannot use the item specified */
	    if (ItemIsWeapon (&pawn->item[position]))
		errcode = UnequipWeapon(pawn);
	    if (ItemIsArmor (&pawn->item[position]))
		errcode = UnequipArmor(pawn);
	    if (ItemIsShield (&pawn->item[position]))
		errcode = UnequipShield(pawn);
	    if (ItemIsHelmet (&pawn->item[position]))
		errcode = UnequipHelmet(pawn);
	    if (ItemIsGauntlet (&pawn->item[position]))
		errcode = UnequipGauntlet(pawn);
	    if (errcode)
		return; /* could not unequip previous item (curse, etc.) */
	    pawn->item[position].usage = (pawn->item[position].usage |
					  USAGE_EQUIPPED);
	    SetInspectorInventory (gi, pawn);
	}
}

int GetNextEquippableItem (PlayerPawn *pawn)
{
    int i;
    int offset = equipmenucursorposition + 1;

    if (offset == 0) /* If i<0, this is the first run, so return first match */
	for (i = 0; i < 8; i++)
	    {
		if (pawn->item[i].usage & USAGE_EQUIPPABLE)
		    return (i);
	    }

    for (i = offset; i < 8; i++) /* otherwise, go on to the next item */
	if (pawn->item[i].usage & USAGE_EQUIPPABLE)
	    return (i);

    /* if we make it this far, there were no equippable items after the last */
    for (i = 0; i < 8; i++)
	if (pawn->item[i].usage & USAGE_EQUIPPABLE)
	    return (i);
    return (-1);
}

int GetPrevEquippableItem (PlayerPawn *pawn)
{
    int i;
    int offset = equipmenucursorposition - 1;

    for (i = offset; i > -1; i--)
	if (pawn->item[i].usage & USAGE_EQUIPPABLE)
	    return (i);

    /* if we get this far, there are no equippable items before the current */
    for (i = 8; i > offset; i--)
	if (pawn->item[i].usage & USAGE_EQUIPPABLE)
	    return (i);
    return (-1);
}

void MoveEquipCursor (GwizInspector *gi, PlayerPawn *pawn, int goingup)
{
    if (goingup)
	{
	    equipmenucursorposition = GetPrevEquippableItem (pawn);
	} else {
	    equipmenucursorposition = GetNextEquippableItem (pawn);
	}
}

void EquipMenuLoop (GwizInspector *gi, PlayerPawn *pawn)
{
    SDL_Event event;
    SDL_Rect dest;
    SDL_Rect crect;
    int breakout = FALSE;
    int y = gi->area->h - gwiz.tbord[0]->h - gwiz.font.height*8;

    dest.x = gwiz.canvas->w/2 - gi->area->w/2;
    dest.y = gwiz.canvas->h/2 - gi->area->h/2;
    dest.h = gi->area->h;
    dest.w = gi->area->w;
    crect.x = gwiz.tbord[0]->w;
    crect.y = y + gwiz.font.height*equipmenucursorposition;
    crect.h = gwiz.cursor->h;
    crect.w = gwiz.cursor->w;

    SDL_BlitSurface (gwiz.cursor, NULL, gi->area, &crect);
    SDL_BlitSurface (gi->area, NULL, gwiz.canvas, &dest);
    SDL_Flip (gwiz.canvas);

    while (SDL_WaitEvent (&event) != 0)
	{
	    SDL_Event *e = &event;
	    if (EventIsUp(e))
		MoveEquipCursor (gi, pawn, TRUE);
	    if (EventIsDown(e))
		MoveEquipCursor (gi, pawn, FALSE);
	    if (EventIsOk(e))
		FlipEquippedState (gi, pawn);
	    if (EventIsCancel(e))
		breakout = TRUE;

	    SDL_FillRect (gi->area, &crect, 0);
	    if (breakout) /* do this after deleting the cursor's image */
		break;
	    crect.y = y + gwiz.font.height*equipmenucursorposition;
	    SDL_BlitSurface (gwiz.cursor, NULL, gi->area, &crect);
	    /* copy the new image over the old one */
	    SDL_BlitSurface (gi->area, NULL, gwiz.canvas, &dest);
	    SDL_Flip (gwiz.canvas);
	}
}


/* These functions specify equipment that you can only have one of; equipping
   a new one should unequip the old one. */
int UnequipWeapon (PlayerPawn *pawn)
{
    int i;

    for (i = 0; i < 8; i++)
	if (((pawn->item[i].usage & EQUIPPED) == EQUIPPED) &&
	    ItemIsWeapon (&pawn->item[i]))
	    {
		if (pawn->item[i].special & CURSED)
		    return (TRUE); /* equipped item is cursed, cannot remove */
		pawn->item[i].usage = (pawn->item[i].usage ^ USAGE_EQUIPPED);
	    }
    return (FALSE);
}

int UnequipArmor (PlayerPawn *pawn)
{
    int i;

    for (i = 0; i < 8; i++)
	if (((pawn->item[i].usage & EQUIPPED) == EQUIPPED) &&
	    ItemIsArmor (&pawn->item[i]))
	    {
		if (pawn->item[i].special & CURSED)
		    return (TRUE); /* equipped item is cursed, cannot remove */
		pawn->item[i].usage = (pawn->item[i].usage ^ USAGE_EQUIPPED);
	    }
    return (FALSE);
}

int UnequipShield (PlayerPawn *pawn)
{
    int i;

    for (i = 0; i < 8; i++)
	if (((pawn->item[i].usage & EQUIPPED) == EQUIPPED) &&
	    ItemIsShield (&pawn->item[i]))
	    {
		if (pawn->item[i].special & CURSED)
		    return (TRUE); /* equipped item is cursed, cannot remove */
		pawn->item[i].usage = (pawn->item[i].usage ^ USAGE_EQUIPPED);
	    }
    return (FALSE);
}

int UnequipHelmet (PlayerPawn *pawn)
{
    int i;

    for (i = 0; i < 8; i++)
	if (((pawn->item[i].usage & EQUIPPED) == EQUIPPED) &&
	    ItemIsHelmet (&pawn->item[i]))
	    {
		if (pawn->item[i].special & CURSED)
		    return (TRUE); /* equipped item is cursed, cannot remove */
		pawn->item[i].usage = (pawn->item[i].usage ^ USAGE_EQUIPPED);
	    }
    return (FALSE);
}

int UnequipGauntlet (PlayerPawn *pawn)
{
    int i;

    for (i = 0; i < 8; i++)
	if (((pawn->item[i].usage & EQUIPPED) == EQUIPPED) &&
	    ItemIsGauntlet (&pawn->item[i]))
	    {
		if (pawn->item[i].special & CURSED)
		    {
			MsgBox ("Cannot unequip cursed items");
			return (TRUE); /* item is cursed, can't remove */
		    }
		pawn->item[i].usage = (pawn->item[i].usage ^ USAGE_EQUIPPED);
	    }
    return (FALSE);
}

int PawnItemCompatible (int class, int usage)
{
    int compat;
    switch (class)
	{
	case FIGHTER: /* shared compatibility between these three.  :) */
	case SAMURAI:
	case LORD:
	    compat = USAGE_SWORD |
		USAGE_ARMOR |
		USAGE_HELMET |
		USAGE_GAUNTLET |
		USAGE_BOOT |
		USAGE_RING |
		USAGE_MACE |
		USAGE_DAGGER |
		USAGE_BOW |
		USAGE_STAFF |
		USAGE_2X_SWORD |
		USAGE_ROBES |
		USAGE_SHIELD |
		USAGE_LEATHER |
		USAGE_AMULET;
	    if (usage & compat)
		return (TRUE);
	    break;
	case MAGE:
	    compat = USAGE_BOOT |
		USAGE_RING |
		USAGE_STAFF |
		USAGE_ROBES |
		USAGE_AMULET;
	    if (usage & compat)
		return (TRUE);
	    break;
	case CLERIC:
	    compat = USAGE_BOOT |
		USAGE_RING |
		USAGE_MACE |
		USAGE_DAGGER |
		USAGE_STAFF |
		USAGE_ROBES |
		USAGE_AMULET;
	    if (usage & compat)
		return (TRUE);
	    break;
	case WIZARD:
	    compat = USAGE_BOOT | /* no mace or dagger; mages use staves */
		USAGE_RING |
		USAGE_STAFF |
		USAGE_ROBES |
		USAGE_AMULET;
	    if (usage & compat)
		return (TRUE);
	    break;
	case THIEF:
	case NINJA:
	    compat = USAGE_HELMET |
		USAGE_GAUNTLET |
		USAGE_BOOT |
		USAGE_RING |
		USAGE_DAGGER |
		USAGE_BOW |
		USAGE_LEATHER;
	    if (usage & compat)
		return (TRUE);
	    break;
	}
    return (FALSE);
}
