/*  classchange.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_ttf.h>
#include <stdlib.h>
#include "gwiz.h"
#include "text.h"
#include "playerpawn.h"
#include "classchange.h"
#include "uiloop.h"

extern GwizApp gwiz;
GwizClassChanger *gcc;

void NewClassEligibilityList (PlayerPawn *pawn)
{
    int whichclass;
    int classno = -1;
    int i;

    gcc = (GwizClassChanger *)Smalloc(sizeof(GwizClassChanger));

    gcc->pawn = pawn;
    InitClassChanger ();

    whichclass = ClassChangeLoop();

    SDL_BlitSurface (gcc->displace, NULL, gwiz.canvas, &gcc->drect);
    SDL_FreeSurface (gcc->displace);
    SDL_FreeSurface (gcc->area);
    Sfree (gcc);

    if (whichclass == -1)
	return;

    for (i = 0; i < (NINJA + 1); i++)
	{
	    if (CheckPawnEligibilityForClass (gcc->pawn, i))
		classno++;
	    if (classno == gcc->position)
		break;
	}
    SetPawnClass (gcc->pawn, classno);
}

void InitClassChanger (void)
{
    char *classes[] = {
	"Fighter",
	"Mage",
	"Cleric",
	"Thief",
	"Wizard",
	"Samurai",
	"Lord",
	"Ninja",
	NULL
    };
    SDL_Surface *list = NewVertTextMsg (classes, 0);
    SDL_Rect srect;
    SDL_Rect trect;
    int i;

    CountAvailableClassesToPawn();
    gcc->crect.x = BORDERWIDTH;
    gcc->crect.y = BORDERHEIGHT + (gwiz.font.height/2 - gwiz.cursor->h/2);
    gcc->crect.h = gwiz.cursor->h;
    gcc->crect.w = gwiz.cursor->w;
    gcc->yoffset = gcc->crect.y;

    gcc->area = NewTextBox (list->w + gwiz.cursor->w,
			    (gcc->maxposition + 1)*gwiz.font.height);

    gcc->drect.x = CenterHoriz (gwiz.canvas, gcc->area);
    gcc->drect.y = CenterVert (gwiz.canvas, gcc->area);
    gcc->drect.h = gcc->area->h;
    gcc->drect.w = gcc->area->w;

    gcc->displace = NewGwizSurface (gcc->area->w, gcc->area->h);
    SDL_BlitSurface (gwiz.canvas, &gcc->drect, gcc->displace, NULL);

    trect.x = BORDERWIDTH + gwiz.cursor->w;
    trect.y = BORDERHEIGHT;
    trect.h = gwiz.font.height;
    trect.w = list->w;
    srect.x = 0;
    srect.y = 0;
    srect.h = trect.h;
    srect.w = trect.w;

    for (i = 0; i < (NINJA + 1); i++)
	{
	    if (CheckPawnEligibilityForClass(gcc->pawn, i))
		{
		    SDL_BlitSurface (list, &srect, gcc->area, &trect);
		    trect.y += gwiz.font.height;
		}
	    srect.y += gwiz.font.height;
	}
    SDL_BlitSurface (gwiz.cursor, NULL, gcc->area, &gcc->crect);
    SDL_BlitSurface (gcc->area, NULL, gwiz.canvas, &gcc->drect);
    SDL_Flip (gwiz.canvas);
    SDL_FreeSurface (list);
}

void MoveClassChangeCursor (int goingup)
{
    SDL_FillRect (gcc->area, &gcc->crect, gwiz.bgc);
    if (goingup)
	{
	    gcc->position--;
	    if (gcc->position < 0)
		gcc->position = gcc->maxposition;
	} else {
	    gcc->position++;
	    if (gcc->position > gcc->maxposition)
		gcc->position = 0;
	}
    gcc->crect.y = gcc->yoffset + gcc->position*gwiz.font.height;
    SDL_BlitSurface (gwiz.cursor, NULL, gcc->area, &gcc->crect);
    SDL_BlitSurface (gcc->area, NULL, gwiz.canvas, &gcc->drect);
    SDL_Flip (gwiz.canvas);
}

int ClassChangeLoop (void)
{
    SDL_Event event;
    SDL_Event *e = &event;

    while (SDL_WaitEvent (e) != 0)
	{
	    if (EventIsUp (e))
		MoveClassChangeCursor (TRUE);
	    if (EventIsDown (e))
		MoveClassChangeCursor (FALSE);
	    if (EventIsCancel (e))
		return (-1);
	    if (EventIsOk (e))
		return (gcc->position);
	}
    return (-1);
}

void CountAvailableClassesToPawn (void)
{
    PlayerPawn *pawn = gcc->pawn;
    /* FIXME: What if stats were drained, and no classes are available? */
    int classes = -1;

    if (pawn->attr.str > 10)
	classes++;

    if (pawn->attr.iq > 10)
	classes++;

    if ((pawn->attr.dev > 10) && (pawn->ali != NEUTRAL))
	classes++;

    if ((pawn->attr.agi > 10) && (pawn->ali != GOOD))
	classes++;

    if ((pawn->attr.dev > 11) &&
	(pawn->attr.iq > 11) &&
	(pawn->ali != NEUTRAL))
	classes++;

    if ((pawn->attr.str > 14) &&
	(pawn->attr.iq > 10) &&
	(pawn->attr.dev > 9) &&
	(pawn->attr.vit > 13) &&
	(pawn->attr.agi > 9) &&
	(pawn->ali != EVIL))
	classes++;

    if ((pawn->attr.str > 14) &&
	(pawn->attr.iq > 11) &&
	(pawn->attr.dev > 11) &&
	(pawn->attr.vit > 15) &&
	(pawn->attr.agi > 13) &&
	(pawn->attr.luck > 14) &&
	(pawn->ali == GOOD))
	classes++;

    if ((pawn->attr.str > 14) &&
	(pawn->attr.iq > 16) &&
	(pawn->attr.dev > 14) &&
	(pawn->attr.vit > 15) &&
	(pawn->attr.agi > 14) &&
	(pawn->attr.luck > 15) &&
	(pawn->ali == EVIL))
	classes++;

    gcc->maxposition = classes;
}

int CheckPawnEligibilityForClass (PlayerPawn *pawn, int class)
{
    switch (class)
	{
	case FIGHTER:
	    if (pawn->attr.str > 10)
		return (TRUE);
	case MAGE:
	    if (pawn->attr.iq > 10)
		return (TRUE);
	case CLERIC:
	    if ((pawn->attr.dev > 10) && (pawn->ali != NEUTRAL))
		return (TRUE);
	case THIEF:
	    if ((pawn->attr.agi > 10) && (pawn->ali != GOOD))
		return (TRUE);
	case WIZARD:
	    if ((pawn->attr.dev > 11) &&
		(pawn->attr.iq > 11) &&
		(pawn->ali != NEUTRAL))
		return (TRUE);
	case SAMURAI:
	    if ((pawn->attr.str > 14) &&
		(pawn->attr.iq > 10) &&
		(pawn->attr.dev > 9) &&
		(pawn->attr.vit > 13) &&
		(pawn->attr.agi > 9) &&
		(pawn->ali != EVIL))
		return (TRUE);
	case LORD:
	    if ((pawn->attr.str > 14) &&
		(pawn->attr.iq > 11) &&
		(pawn->attr.dev > 11) &&
		(pawn->attr.vit > 15) &&
		(pawn->attr.agi > 13) &&
		(pawn->attr.luck > 14) &&
		(pawn->ali == GOOD))
		return (TRUE);
	case NINJA:
	    if ((pawn->attr.str > 14) &&
		(pawn->attr.iq > 16) &&
		(pawn->attr.dev > 14) &&
		(pawn->attr.vit > 15) &&
		(pawn->attr.agi > 14) &&
		(pawn->attr.luck > 15) &&
		(pawn->ali == EVIL))
		return (TRUE);
	}	    
    return (FALSE);
}

void SetPawnClass (PlayerPawn *pawn, int classno)
{
    char spellmodulo;
    int points;
    int i;
    switch (pawn->race)
	{
	case HUMAN:
	    pawn->attr.str = HUMAN_STR - 10;
	    pawn->attr.iq = HUMAN_IQ - 10;
	    pawn->attr.dev = HUMAN_DEV - 10;
	    pawn->attr.vit = HUMAN_VIT - 10;
	    pawn->attr.agi = HUMAN_AGI - 10;
	    pawn->attr.luck = HUMAN_LUCK - 10;
	    pawn->class = classno;
	    break;
	case ELF:
	    pawn->attr.str = ELF_STR - 10;
	    pawn->attr.iq = ELF_IQ - 10;
	    pawn->attr.dev = ELF_DEV - 10;
	    pawn->attr.vit = ELF_VIT - 10;
	    pawn->attr.agi = ELF_AGI - 10;
	    pawn->attr.luck = ELF_LUCK - 10;
	    pawn->class = classno;
	    break;
	case DWARF:
	    pawn->attr.str = DWARF_STR - 10;
	    pawn->attr.iq = DWARF_IQ - 10;
	    pawn->attr.dev = DWARF_DEV - 10;
	    pawn->attr.vit = DWARF_VIT - 10;
	    pawn->attr.agi = DWARF_AGI - 10;
	    pawn->attr.luck = DWARF_LUCK - 10;
	    pawn->class = classno;
	    break;
	case GNOME:
	    pawn->attr.str = DWARF_STR - 10;
	    pawn->attr.iq = DWARF_IQ - 10;
	    pawn->attr.dev = DWARF_DEV - 10;
	    pawn->attr.vit = DWARF_VIT - 10;
	    pawn->attr.agi = DWARF_AGI - 10;
	    pawn->attr.luck = DWARF_LUCK - 10;
	    pawn->class = classno;
	    break;
	case HOBBIT:
	    pawn->attr.str = HOBBIT_STR - 10;
	    pawn->attr.iq = HOBBIT_IQ - 10;
	    pawn->attr.dev = HOBBIT_DEV - 10;
	    pawn->attr.vit = HOBBIT_VIT - 10;
	    pawn->attr.agi = HOBBIT_AGI - 10;
	    pawn->attr.luck = HOBBIT_LUCK - 10;
	    pawn->class = classno;
	    break;
	}
    /* This cuts the pawn's maximum spell points by 50%.  Any potential
       remainders are decided by coin toss whether to be credited or not */
    for (i = 0; i < 7; i++)
	{
	    if (pawn->cm.maxpoints[i] > 0)
		{
		    points = pawn->cm.maxpoints[i];
		    spellmodulo = points % 2;
		    if (spellmodulo > 0)
			spellmodulo = (rand() < 0.5) ? 0 : 1;
		    pawn->cm.maxpoints[i] = points/2 + spellmodulo;
		    if (pawn->cm.spellpoints[i] > pawn->cm.maxpoints[i])
			pawn->cm.spellpoints[i] = pawn->cm.maxpoints[i];
		}
	    if (pawn->mm.maxpoints[i] > 0)
		{
		    points = pawn->mm.maxpoints[i];
		    spellmodulo = points % 2;
		    if (spellmodulo > 0)
			spellmodulo = (rand() < 0.5) ? 0 : 1;
		    pawn->mm.maxpoints[i] = points/2 + spellmodulo;
		    if (pawn->mm.spellpoints[i] > pawn->mm.maxpoints[i])
		    pawn->mm.spellpoints[i] = pawn->mm.maxpoints[i];
		}
	}
    for (i = 0; i < 8; i++)
	if ((pawn->item[i].usage & USAGE_EQUIPPED) == USAGE_EQUIPPED)
	    pawn->item[i].usage = (pawn->item[i].usage ^ USAGE_EQUIPPED);
}
