/*  playerpawn.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 <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include "gwiz.h"
#include "playerpawn.h"
#include "uiloop.h"
#include "prefsdat.h"
#include "text.h"
#include "maploader.h"
#include "menus.h"
#include "party.h"
#include "joystick.h"
#include "classchange.h"

extern GwizApp gwiz;
extern const SDL_Color fg, bg;

void InitStatusPix(void)
{
    gwiz.status.ok = GwizRenderText("Ok");
    gwiz.status.poison = GwizRenderText("Poisoned");
    gwiz.status.petrif = GwizRenderText("Petrified");
    gwiz.status.dead = GwizRenderText ("Dead");
    gwiz.status.ash = GwizRenderText ("Ash");
    gwiz.status.afraid = GwizRenderText ("Afraid");
    gwiz.status.lost = GwizRenderText ("Lost");
}

void InitNewPlayer (PlayerPawn *pawn)
{
    int i;
    
    for (i = 0; i < 8; i++)
	{
	    strncpy (pawn->item[i].name, "               ", 16);
	    pawn->item[i].version = ITEM_VERSION - 1; /* empty items invalid */
	    /* Don't set visual, because this is all going away shortly */
	    pawn->item[i].acmod = 0;
	    pawn->item[i].swimmod = 0;
	    pawn->item[i].luckmod = 0;
	    pawn->item[i].agimod = 0;
	    pawn->item[i].vitmod = 0;
	    pawn->item[i].devmod = 0;
	    pawn->item[i].iqmod = 0;
	    pawn->item[i].strmod = 0;
	    pawn->item[i].special = 0;
	    pawn->item[i].buyfor = 0;
	    pawn->item[i].sellfor = 0;
	    pawn->item[i].usage = USAGE_NONE;
	    pawn->item[i].magice = 0;
	    pawn->item[i].clerice = 0;
	}
    for (i = 0; i < 7; i++)
	{
	    strncpy (pawn->mm.ptlist, "0 /0 /0 /0 /0 /0 /0", 20);
	    pawn->mm.spellpoints[i] = 0;
	    pawn->mm.maxpoints[i] = 0;
	    strncpy (pawn->cm.ptlist, "0 /0 /0 /0 /0 /0 /0", 20);
	    pawn->cm.spellpoints[i] = 0;
	    pawn->cm.maxpoints[i] = 0;
	}
    for (i = 0; i < NUM_SPELLS; i++)
	{
	    pawn->spellsknown[i] = FALSE;
	}

    /* Don't set sep, sgp, smarks, sage, or srip here, either. */
    pawn->counter.ep = 0;
    pawn->counter.gp = 0;
    pawn->counter.marks = 0;
    pawn->counter.age = 0;
    pawn->counter.rip = 0;
    pawn->counter.hp = 10;
    pawn->counter.hp_max = 10;
    
    pawn->attr.ac = 10;
    pawn->attr.str = 0;
    pawn->attr.iq = 0;
    pawn->attr.dev = 0;
    pawn->attr.vit = 0;
    pawn->attr.agi = 0;
    pawn->attr.luck = 0;
    pawn->attr.swim = 0;
    
    strncpy (pawn->name, "               ", 16);
    /* Don't set visual, because it's going to be replaced in a minute */
    pawn->level = 1;
    pawn->sex = MALE;
    pawn->ali = GOOD;
    pawn->class = FIGHTER;
    pawn->race = HUMAN;
    pawn->status = STATUS_OK;
    pawn->saved_x = 128;
    pawn->saved_y = 128;
    pawn->saved_z = 0;
    /* NULL will keep pawn of the roster, as well as point to the first
       opening IN that roster.  :) */
    pawn->version = -1;
}

void ValidatePartyFile (void)
{
    int tmp;
    FILE *party;
    
    if ((party = fopen (gwiz.udata.party, "rb")) != NULL)
	{
	    return;
	} else {
	    CreatePartyFile();
	    if ((party = fopen (gwiz.udata.party, "rb")) == NULL)
		BailCall ("playerpawn.c: unable to create party: ",
			  gwiz.udata.party);
	}
    
    /* ok, party file exists, and is correct version.  check the it */
    for (tmp = 0; tmp < 20; tmp++)
	{
	    if (fseek(party, sizeof(PlayerPawn), SEEK_CUR) != 0)
		BailCall ("playerpawn.c: invalid party file: ",
			  gwiz.udata.party);
	    /* TODO: Should ask if you want to replace it */
	}
    /* one last check to see if the party file is too big: */
    if (fseek (party, sizeof(int), SEEK_CUR) == -1)
	BailCall ("playerpawn.c: invalid party file: ",
		  gwiz.udata.party);
    
    fclose (party);
}

void CreatePartyFile (void)
{
    /* "bug_free_function(tm)" */
    PlayerPawn pawn;
    int tmp;
    
    FILE *party;
    
    InitNewPlayer (&pawn);
    
    if ((party = fopen (gwiz.udata.party, "wb")) == NULL)
	BailCall ("playerpawn.c: Unable to create party file: ",
		  gwiz.udata.party);
    
    FlipPawnToSaveFormat(&pawn);
    for (tmp = 0; tmp < 20; tmp++)
	{
	    fwrite (&pawn, sizeof(PlayerPawn), 1, party);
	}
    /* don't flip the pawn's format back, because it is simply discarded */
    
    fclose (party);
}

void SavePawn (PlayerPawn pawn, int whichpawn)
{
    int tmp;
    
    FILE *party;
    party = fopen(gwiz.udata.party, "r+b");
    if (party == NULL)
	BailCall ("playerpawn.c: Unable to save pawn to file ",
		  gwiz.udata.party);
    
    if ((tmp = fseek(party, sizeof(PlayerPawn)*whichpawn, SEEK_CUR)) != 0)
	BailCall ("playerpawn.c: unable to locate position! ",
		  gwiz.udata.party);

    pawn.saved_x = gwiz.x;
    pawn.saved_y = gwiz.y;
    pawn.saved_z = gwiz.z;
    
    FlipPawnToSaveFormat (&pawn);
    fwrite (&pawn, sizeof(PlayerPawn), 1, party);
    FlipPawnToPlayFormat (&pawn);
    
    fclose (party);
}

void LoadPawn (int whichpawn, PlayerPawn *pawn)
{
    int tmp;
    FILE *party;
    
    party = fopen (gwiz.udata.party, "rb");
    if (party == NULL) /* make sure it's actually there */
	{
	    CreatePartyFile();
	    
	    party = fopen (gwiz.udata.party, "rb");
	    if (party == NULL) /* make sure it's actually there */
		BailCall ("playerpawn.c: unable to open party file: ",
			  gwiz.udata.party);
	}
    
    if ((tmp = fseek(party, sizeof(PlayerPawn)*whichpawn, SEEK_CUR)) != 0)
	BailCall ("playerpawn.c: unable to locate pawn position! ",
		  gwiz.udata.party);
    
    fread (pawn, sizeof(PlayerPawn), 1, party);
    FlipPawnToPlayFormat (pawn);
    
    fclose (party);
}

void DeletePawn (void)
{
    PlayerPawn pawn;
    SDL_Surface *screen;
    int pawnno;
    
    if (CountValidPawns() < 0)
	return;

    EmptyParty (); /* necessary to prevent corruption and "out-of-sync" errs */
    
    screen = SDL_DisplayFormat (gwiz.canvas);
    
    if ((pawnno = NewPawnList()) < 0)
	{
	    SDL_BlitSurface (screen, NULL, gwiz.canvas, NULL);
	    SDL_FreeSurface (screen);
	    return;
	}
    
    LoadPawn (pawnno, &pawn);
    InitNewPlayer (&pawn);
    SavePawn (pawn, pawnno);
    CompactPartyFile ();
    
    SDL_BlitSurface (screen, NULL, gwiz.canvas, NULL);
    SDL_Flip (gwiz.canvas);
}

/* This function is -extremely important- because it prevents massive pawn
   corruption and improperly synced data transfers between the party and the
   save file. */
void CompactPartyFile (void)
{
    PlayerPawn pawn;
    int i;
    int j;

    EmptyParty(); /* We must take care to not screw up the current listing */

    for (i = 0; i < 20; i++)
	{
	    LoadPawn (i, &pawn);
	    if (pawn.version < 0)
		{
		    for (j = i+1; j < 20; j++)
			{
			    LoadPawn (j, &pawn);
			    if (pawn.version != -1)
				{
				    SavePawn (pawn, i);
				    InitNewPlayer (&pawn);
				    SavePawn (pawn, j);
				    /* prevent multiple overwrites and loss */
				    break; 
				}
			}
		}
	}
}

void FlipPawnToSaveFormat (PlayerPawn *pawn)
{
    int i;
    
    /* some of these are #defined hex numbers, but I re-order EVERYTHING
       to enhance clarity, and reduce the number of "renegade variables"
       I have to track */
    for (i = 0; i < 8; i++)
	{
	    pawn->item[i].version = htonl (pawn->item[i].version);
	    pawn->item[i].acmod   = htonl (pawn->item[i].acmod);
	    pawn->item[i].swimmod = htonl (pawn->item[i].swimmod);
	    pawn->item[i].luckmod = htonl (pawn->item[i].luckmod);
	    pawn->item[i].agimod  = htonl (pawn->item[i].agimod);
	    pawn->item[i].vitmod  = htonl (pawn->item[i].vitmod);
	    pawn->item[i].devmod  = htonl (pawn->item[i].devmod);
	    pawn->item[i].iqmod   = htonl (pawn->item[i].iqmod);
	    pawn->item[i].strmod  = htonl (pawn->item[i].strmod);
	    pawn->item[i].special = htonl (pawn->item[i].special);
	    pawn->item[i].buyfor  = htonl (pawn->item[i].buyfor);
	    pawn->item[i].sellfor = htonl (pawn->item[i].sellfor);
	    pawn->item[i].usage   = htonl (pawn->item[i].usage);
	    pawn->item[i].magice  = htonl (pawn->item[i].magice);
	    pawn->item[i].clerice = htonl (pawn->item[i].clerice);
	}
    for (i = 0; i < 7; i++)
	{
	    pawn->mm.spellpoints[i] = htonl (pawn->mm.spellpoints[i]);
	    pawn->mm.maxpoints[i]   = htonl (pawn->mm.maxpoints[i]);
	    pawn->cm.spellpoints[i] = htonl (pawn->cm.spellpoints[i]);
	    pawn->cm.maxpoints[i]   = htonl (pawn->cm.spellpoints[i]);
	}
    for (i = 0; i < NUM_SPELLS; i++)
	{
	    pawn->spellsknown[i] = htonl (pawn->spellsknown[i]);
	}
    pawn->counter.ep     = htonl (pawn->counter.ep);
    pawn->counter.gp     = htonl (pawn->counter.gp);
    pawn->counter.marks  = htonl (pawn->counter.marks);
    pawn->counter.age    = htonl (pawn->counter.age);
    pawn->counter.rip    = htonl (pawn->counter.rip);
    pawn->counter.hp     = htonl (pawn->counter.hp);
    pawn->counter.hp_max = htonl (pawn->counter.hp_max);
    
    pawn->attr.ac   = htonl (pawn->attr.ac);
    pawn->attr.str  = htonl (pawn->attr.str);
    pawn->attr.iq   = htonl (pawn->attr.iq);
    pawn->attr.dev  = htonl (pawn->attr.dev);
    pawn->attr.vit  = htonl (pawn->attr.vit);
    pawn->attr.agi  = htonl (pawn->attr.agi);
    pawn->attr.luck = htonl (pawn->attr.luck);
    pawn->attr.swim = htonl (pawn->attr.swim);
    
    pawn->level   = htonl (pawn->level);
    pawn->sex     = htonl (pawn->sex);
    pawn->ali     = htonl (pawn->ali);
    pawn->class   = htonl (pawn->class);
    pawn->race    = htonl (pawn->race);
    pawn->status  = htonl (pawn->status);
    pawn->saved_x = htonl (pawn->saved_x);
    pawn->saved_y = htonl (pawn->saved_y);
    pawn->saved_z = htonl (pawn->saved_z);
    pawn->version = htonl (pawn->version);
}

void FlipPawnToPlayFormat (PlayerPawn *pawn)
{
    int i;
    
    /* some of these are #defined hex numbers, but I re-order EVERYTHING
       to enhance clarity, and reduce the number of "renegade variables"
       I have to track */
    for (i = 0; i < 8; i++)
	{
	    pawn->item[i].version = ntohl (pawn->item[i].version);
	    pawn->item[i].acmod   = ntohl (pawn->item[i].acmod);
	    pawn->item[i].swimmod = ntohl (pawn->item[i].swimmod);
	    pawn->item[i].luckmod = ntohl (pawn->item[i].luckmod);
	    pawn->item[i].agimod  = ntohl (pawn->item[i].agimod);
	    pawn->item[i].vitmod  = ntohl (pawn->item[i].vitmod);
	    pawn->item[i].devmod  = ntohl (pawn->item[i].devmod);
	    pawn->item[i].iqmod   = ntohl (pawn->item[i].iqmod);
	    pawn->item[i].strmod  = ntohl (pawn->item[i].strmod);
	    pawn->item[i].special = ntohl (pawn->item[i].special);
	    pawn->item[i].buyfor  = ntohl (pawn->item[i].buyfor);
	    pawn->item[i].sellfor = ntohl (pawn->item[i].sellfor);
	    pawn->item[i].usage   = ntohl (pawn->item[i].usage);
	    pawn->item[i].magice  = ntohl (pawn->item[i].magice);
	    pawn->item[i].clerice = ntohl (pawn->item[i].clerice);
	}
    for (i = 0; i < 7; i++)
	{
	    pawn->mm.spellpoints[i] = ntohl (pawn->mm.spellpoints[i]);
	    pawn->mm.maxpoints[i]   = ntohl (pawn->mm.maxpoints[i]);
	    pawn->cm.spellpoints[i] = ntohl (pawn->cm.spellpoints[i]);
	    pawn->cm.maxpoints[i]   = ntohl (pawn->cm.spellpoints[i]);
	}
    for (i = 0; i < NUM_SPELLS; i++)
	{
	    pawn->spellsknown[i] = ntohl (pawn->spellsknown[i]);
	}

    pawn->counter.ep     = ntohl (pawn->counter.ep);
    pawn->counter.gp     = ntohl (pawn->counter.gp);
    pawn->counter.marks  = ntohl (pawn->counter.marks);
    pawn->counter.age    = ntohl (pawn->counter.age);
    pawn->counter.rip    = ntohl (pawn->counter.rip);
    pawn->counter.hp     = ntohl (pawn->counter.hp);
    pawn->counter.hp_max = ntohl (pawn->counter.hp_max);
    
    pawn->attr.ac   = ntohl (pawn->attr.ac);
    pawn->attr.str  = ntohl (pawn->attr.str);
    pawn->attr.iq   = ntohl (pawn->attr.iq);
    pawn->attr.dev  = ntohl (pawn->attr.dev);
    pawn->attr.vit  = ntohl (pawn->attr.vit);
    pawn->attr.agi  = ntohl (pawn->attr.agi);
    pawn->attr.luck = ntohl (pawn->attr.luck);
    pawn->attr.swim = ntohl (pawn->attr.swim);
    
    pawn->level   = ntohl (pawn->level);
    pawn->sex     = ntohl (pawn->sex);
    pawn->ali     = ntohl (pawn->ali);
    pawn->class   = ntohl (pawn->class);
    pawn->race    = ntohl (pawn->race);
    pawn->status  = ntohl (pawn->status);
    pawn->saved_x = ntohl (pawn->saved_x);
    pawn->saved_y = ntohl (pawn->saved_y);
    pawn->saved_z = ntohl (pawn->saved_z);
    pawn->version = ntohl (pawn->version);
}

int FirstAvailablePawn (void)
{
    int pawnno = -1;
    int i = 0;
    FILE *party;
    PlayerPawn pawn;
    
    ValidatePartyFile(); /* check/create party file */
    party = fopen (gwiz.udata.party, "rb");
    if (party == NULL)
	BailCall ("playerpawn.c: unable to open party file: ",
		  gwiz.udata.party);
    
    for (i = 0; i < 20; i++)
	{
	    fread (&pawn, sizeof(PlayerPawn), 1, party);
	    if (pawn.version == -1)
		{
		    pawnno = i;
		    break;
		}
	}
    
    fclose (party);
    
    if (pawnno == -1) /* no vacancy */
	return (-1);

    return (pawnno);
}

void GetClassAbbr (int class, char *cname)
{
    switch (class)
	{
	case FIGHTER:
	    strncpy(cname, "Fig", 4);
	    break;
	case MAGE:
	    strncpy(cname, "Mag", 4);
	    break;
	case CLERIC:
	    strncpy(cname, "Cle", 4);
	    break;
	case THIEF:
	    strncpy(cname, "Thi", 4);
	    break;
	case WIZARD:
	    strncpy(cname, "Wiz", 4);
	    break;
	case SAMURAI:
	    strncpy(cname, "Sam", 4);
	    break;
	case LORD:
	    strncpy(cname, "Lor", 4);
	    break;
	case NINJA:
	    strncpy(cname, "Nin", 4);
	    break;
	}
}

int NewPawnList(void)
{
    SDL_Event event;
    SDL_Rect dest;
    GwizPawnList gpl;
    int done = 0;
    int i;
    
    ValidatePartyFile();
    
    gpl.maxposition = CountValidPawns();

    if (gpl.maxposition == -1) /* no pawns = no list. */
	return (-1);

    for (i = 0; i < 6; i++)
	    if (gwiz.pawnno[i] > -1)
		gpl.maxposition--;
    gpl.maxposition -= GetNumberOfIncompatiblePawns();

    if (gpl.maxposition < 0) /* reduce pawn count by number of pawns in use */
	return (-1);
    
    gpl.position = 0;
    
    LoadPawnListPix(&gpl);
    
    dest.x = gwiz.canvas->w/2 - gpl.area->w/2;
    dest.y = gwiz.canvas->h/2 - gpl.area->h/2;
    dest.h = gpl.area->h;
    dest.w = gpl.area->w;
    
    gpl.crect.x = 8;
    gpl.crect.y = 8 + gwiz.font.height/2 - gwiz.cursor->w/2;
    gpl.crect.h = gwiz.cursor->h;
    gpl.crect.w = gwiz.cursor->w;

    gpl.displace = NewGwizSurface (gpl.area->w, gpl.area->h);
    SDL_BlitSurface (gwiz.canvas, &dest, gpl.displace, NULL);
    
    SDL_BlitSurface (gwiz.cursor, NULL, gpl.area, &gpl.crect);
    SDL_BlitSurface (gpl.area, NULL, gwiz.canvas, &dest);
    SDL_Flip (gwiz.canvas);
    
    while ((SDL_WaitEvent(&event)) != 0)
	{
	    SDL_Event *e = &event;
	    if (EventIsUp (e))
		MovePawnListCursor (&gpl, 0);
	    if (EventIsDown (e))
		MovePawnListCursor (&gpl, 1);
	    if (EventIsCancel (e))
		done = 1;
	    if (EventIsOk (e))
		done = 2;

	    if (done)
		break;
	    SDL_BlitSurface (gwiz.cursor, NULL, gpl.area, &gpl.crect);
	    SDL_BlitSurface (gpl.area, NULL, gwiz.canvas, &dest);
	    SDL_Flip (gwiz.canvas);
	}
    
    SDL_FreeSurface (gpl.area);
    SDL_BlitSurface (gpl.displace, NULL, gwiz.canvas, &dest);
    SDL_FreeSurface (gpl.displace);
    SDL_Flip (gwiz.canvas);
    if (done == 2)
	return (GetLiteralPawnNo(gpl.position));
    else
	return -1;
}

void MovePawnListCursor (GwizPawnList *gpl, int direction)
{
    switch (direction)
	{
	case 0:
	    if (gpl->position == 0)
		break;
	    SDL_FillRect (gpl->area, &gpl->crect, 0);
	    gpl->crect.y -= gwiz.font.height;
	    gpl->position--;
	    break;
	case 1:
	    if (gpl->position == gpl->maxposition)
		break;
	    SDL_FillRect (gpl->area, &gpl->crect, 0);
	    gpl->crect.y += gwiz.font.height;
	    gpl->position++;
	    break;
	}
}

void LoadPawnListPix (GwizPawnList *gpl)
{
    PlayerPawn pawn;
    SDL_Rect dest;
    SDL_Surface *names   = NULL;
    SDL_Surface *sexes   = NULL;
    SDL_Surface *alis    = NULL;
    SDL_Surface *acs     = NULL;
    SDL_Surface *classes = NULL;
    SDL_Surface *hps     = NULL;
    SDL_Surface *hpmaxes = NULL;
    
    names = RenderPawnNames (&pawn);
    sexes = RenderPawnSexes (&pawn);
    alis = RenderPawnAlis (&pawn);
    acs = RenderPawnClasses (&pawn);
    classes = RenderPawnACs (&pawn);
    hps = RenderPawnHPs (&pawn);
    hpmaxes = RenderPawnHPMaxes (&pawn);
    
    gpl->area = NewTextBox (gwiz.cursor->w    + 
			    names->w          +
			    gwiz.font.width   +
			    sexes->w          +
			    gwiz.font.width   +
			    alis->w           +
			    gwiz.font.width   +
			    classes->w        +
			    gwiz.font.width   +
			    acs->w            +
			    gwiz.font.width   +
			    hps->w            +
			    hpmaxes->w        +
			    gwiz.font.width,
			    
			    names->h);
    
    dest.x = 18;
    dest.y = 8;
    dest.h = names->h;
    dest.w = names->w;
    
    SDL_BlitSurface (names, NULL, gpl->area, &dest);
    dest.x += names->w + gwiz.font.width;
    dest.w = sexes->w;
    SDL_FreeSurface (names);
    SDL_BlitSurface (sexes, NULL, gpl->area, &dest);
    dest.x += sexes->w + gwiz.font.width;
    dest.w = alis->w;
    SDL_FreeSurface (sexes);
    SDL_BlitSurface (alis, NULL, gpl->area, &dest);
    dest.x += alis->w + gwiz.font.width;
    dest.w = classes->w;
    SDL_FreeSurface (alis);
    SDL_BlitSurface (classes, NULL, gpl->area, &dest);
    dest.x += classes->w + gwiz.font.width;
    dest.w = acs->w;
    SDL_FreeSurface (classes);
    SDL_BlitSurface (acs, NULL, gpl->area, &dest);
    dest.x += acs->w + gwiz.font.width;
    dest.w = hps->w;
    SDL_FreeSurface (acs);
    SDL_BlitSurface (hps, NULL, gpl->area, &dest);
    dest.x += hps->w + gwiz.font.width;
    dest.w = hpmaxes->w;
    SDL_FreeSurface (hps);
    SDL_BlitSurface (hpmaxes, NULL, gpl->area, &dest);
    SDL_FreeSurface (hpmaxes);
}

int GetLiteralPawnNo (int which)
{
    PlayerPawn pawn;
    int pawnno = -1;
    int i = 0;

    for (i = 0; i < 20; i++)
        {
	    LoadPawn(i, &pawn);
	    if (pawn.version != -1)
		/* Pawn must be compatible with the party to be counted.  If it
		   isn't compatible, it will be skipped. */
		if ((CheckPawnUsage (i) != 1) && (PawnIsPartyCompatible(&pawn)))
		    pawnno++;
	    if (pawnno == which)
		break;
	}
    return (i);
}

int CountValidPawns(void)
{
    PlayerPawn pawn;
    int i = 0;
    int vp = -1;
    
    for (i = 0; i < 20; i++)
	{
	    LoadPawn(i, &pawn);
	    if (pawn.version > -1)
		vp++;
	}
    return (vp);
}

SDL_Surface *RenderPawnNames (PlayerPawn *pawn)
{
    SDL_Surface *area = NULL;
    SDL_Surface *name[20];
    SDL_Rect dest;
    int i;
    int j = 0;
    int widest = 0;
    char tmp[16];
    
    for (i = 0; i < 20; i++)
	{
	    LoadPawn (i, pawn);
	    if ((pawn->version > -1) &&
		((CheckPawnUsage(i) != 1)) &&
		(PawnIsPartyCompatible (pawn)))
		{
			snprintf(tmp, sizeof(char)*16, "%-16s", pawn->name);
			name[j] = GwizRenderText(tmp);
			if (name[j]->w > widest)
			    widest = name[j]->w;
			j++;
		}
	}
    
    area = NewGwizSurface (widest, gwiz.font.height*20);
    
    dest.x = 0;
    dest.y = 0;
    dest.h = gwiz.font.height;
    dest.w = widest;
    
    for (i = 0; i < j; i++)
	{
	    SDL_BlitSurface (name[i], NULL, area, &dest);
	    dest.y += gwiz.font.height;
	    SDL_FreeSurface (name[i]);
	}
    return (area);
}

SDL_Surface *RenderPawnSexes (PlayerPawn *pawn)
{
    SDL_Surface *area = NULL;
    SDL_Surface *sex[20];
    SDL_Rect dest;
    int i;
    int j = 0;
    int widest = 0;
    char tmp[2];
    
    for (i = 0; i < 20; i++)
	{
	    LoadPawn (i, pawn);
	    if ((pawn->version > -1) &&
		(CheckPawnUsage (i) != 1) &&
		(PawnIsPartyCompatible (pawn)))
		{
		    if (pawn->sex == FEMALE)
			snprintf(tmp, sizeof(char)*2, "%s", "F");
		    else
			snprintf(tmp, sizeof(char)*2, "%s", "M");
		    sex[j] = GwizRenderText(tmp);
		    if (sex[j]->w > widest)
			widest = sex[j]->w;
		    j++;
		}
	}
    
    area = NewGwizSurface (widest, gwiz.font.height*20);
    
    dest.x = 0;
    dest.y = 0;
    dest.h = gwiz.font.height;
    dest.w = widest;
    
    for (i = 0; i < j; i++)
	{
	    SDL_BlitSurface (sex[i], NULL, area, &dest);
	    dest.y += gwiz.font.height;
	    SDL_FreeSurface (sex[i]);
	}
    
    return (area);
}

SDL_Surface *RenderPawnAlis (PlayerPawn *pawn)
{
    SDL_Surface *area = NULL;
    SDL_Surface *ali[20];
    SDL_Rect dest;
    int i;
    int j = 0;
    int widest = 0;
    char tmp[2];
    
    for (i = 0; i < 20; i++)
	{
	    LoadPawn (i, pawn);
	    if ((pawn->version > -1) &&
		(CheckPawnUsage (i) != 1) &&
		(PawnIsPartyCompatible (pawn)))
		{
		    if (pawn->ali == GOOD)
			snprintf(tmp, sizeof(char)*2, "%s", "G");
		    else if (pawn->ali == NEUTRAL)
			snprintf(tmp, sizeof(char)*2, "%s", "N");
		    else
			snprintf (tmp, sizeof(char)*2, "%s", "E");
		    ali[j] = GwizRenderText(tmp);
		    if (ali[j]->w > widest)
			widest = ali[j]->w;
		    j++;
		}
	}
    
    area = NewGwizSurface (widest, gwiz.font.height*20);
    
    dest.x = 0;
    dest.y = 0;
    dest.h = gwiz.font.height;
    dest.w = widest;
    
    for (i = 0; i < j; i++)
	{
	    SDL_BlitSurface (ali[i], NULL, area, &dest);
	    dest.y += gwiz.font.height;
	    SDL_FreeSurface (ali[i]);
	}
    
    return (area);
}

SDL_Surface *RenderPawnClasses (PlayerPawn *pawn)
{
    SDL_Surface *area = NULL;
    SDL_Surface *class[20];
    SDL_Rect dest;
    int i;
    int j = 0;
    int widest = 0;
    char tmp[4];
    
    for (i = 0; i < 20; i++)
	{
	    LoadPawn (i, pawn);
	    if ((pawn->version > -1) &&
		(CheckPawnUsage (i) != 1) &&
		(PawnIsPartyCompatible (pawn)))
		{
		    GetClassAbbr(pawn->class, tmp);
		    class[j] = GwizRenderText(tmp);
		    if (class[j]->w > widest)
			widest = class[j]->w;
		    j++;
		}
	}
    
    area = NewGwizSurface (widest, gwiz.font.height*20);
    
    dest.x = 0;
    dest.y = 0;
    dest.h = gwiz.font.height;
    dest.w = widest;
    
    for (i = 0; i < j; i++)
	{
	    SDL_BlitSurface (class[i], NULL, area, &dest);
	    dest.y += gwiz.font.height;
	    SDL_FreeSurface (class[i]);
	}
    
    return (area);
}

SDL_Surface *RenderPawnACs (PlayerPawn *pawn)
{
    SDL_Surface *area = NULL;
    SDL_Surface *acs[20];
    SDL_Rect dest;
    int i;
    int j = 0;
    int widest = 0;
    char tmp[4];
    
    for (i = 0; i < 20; i++)
	{
	    LoadPawn (i, pawn);
	    if ((pawn->version > -1) &&
		(CheckPawnUsage (i) != 1) &&
		(PawnIsPartyCompatible (pawn)))
		{
		    snprintf(tmp, sizeof(char)*4, "%-3d", pawn->attr.ac);
		    acs[j] = GwizRenderText(tmp);
		    if (acs[j]->w > widest)
			widest = acs[j]->w;
		    j++;
		}
	}

    area = NewGwizSurface (widest, gwiz.font.height*20);
    
    dest.x = 0;
    dest.y = 0;
    dest.h = gwiz.font.height;
    dest.w = widest;
    
    for (i = 0; i < j; i++)
	{
	    SDL_BlitSurface (acs[i], NULL, area, &dest);
	    dest.y += gwiz.font.height;
	    SDL_FreeSurface (acs[i]);
	}
    
    return (area);
}

SDL_Surface *RenderPawnHPs (PlayerPawn *pawn)
{
    SDL_Surface *area = NULL;
    SDL_Surface *hps[20];
    SDL_Rect dest;
    int i;
    int j = 0;
    int widest = 0;
    char tmp[5];
    
    for (i = 0; i < 20; i++)
	{
	    LoadPawn (i, pawn);
	    if ((pawn->version > -1) &&
		(CheckPawnUsage (i) != 1) &&
		(PawnIsPartyCompatible (pawn)))
		{
		    snprintf(tmp, sizeof(char)*5, "%-4d",
			     pawn->counter.hp);
		    hps[j] = GwizRenderText(tmp);
		    if (hps[j]->w > widest)
			widest = hps[j]->w;
		    j++;
		}
	}
    
    area = NewGwizSurface (widest, gwiz.font.height*20);
    
    dest.x = 0;
    dest.y = 0;
    dest.h = gwiz.font.height;
    dest.w = widest;
    
    for (i = 0; i < j; i++)
	{
	    SDL_BlitSurface (hps[i], NULL, area, &dest);
	    dest.y += gwiz.font.height;
	    SDL_FreeSurface (hps[i]);
	}
    
    return (area);
}

SDL_Surface *RenderPawnHPMaxes (PlayerPawn *pawn)
{
    SDL_Surface *area = NULL;
    SDL_Surface *hpmax[20];
    SDL_Rect dest;
    int i;
    int j = 0;
    int widest = 0;
    char tmp[5];
    
    for (i = 0; i < 20; i++)
	{
	    LoadPawn (i, pawn);
	    if ((pawn->version > -1) &&
		(CheckPawnUsage(i) != 1) &&
		(PawnIsPartyCompatible (pawn)))
		{
		    snprintf(tmp, sizeof(char)*5, "%-4d",
			     pawn->counter.hp_max);
		    hpmax[j] = GwizRenderText(tmp);
		    if (hpmax[j]->w > widest)
			widest = hpmax[j]->w;
		    j++;
		}
	}
    
    area = NewGwizSurface (widest, gwiz.font.height*20);
    
    dest.x = 0;
    dest.y = 0;
    dest.h = gwiz.font.height;
    dest.w = widest;
    
    for (i = 0; i < j; i++)
	{
	    SDL_BlitSurface (hpmax[i], NULL, area, &dest);
	    dest.y += gwiz.font.height;
	    SDL_FreeSurface (hpmax[i]);
	}
    
    return (area);
}

int CheckPawnUsage (int which)
{
    int i;
    for (i = 0; i < 6; i++)
	if (gwiz.pawnno[i] == which)
	    return (1);
    
    return 0;
}

void PoolGold (int pawnno)
{
    int numpawns = 0;
    int totalgp = 0;
    int i;

    if (pawnno < 0)
	return;

    for (i = 0; i < 6; i++)
	if (gwiz.pawnno[i] > -1)
	    numpawns++;
    if (numpawns == 0)
	return;

    for (i = 0; i < numpawns; i++)
	{
	    totalgp += gwiz.pawn[i].counter.gp;
	    gwiz.pawn[i].counter.gp = 0;
	}
    gwiz.pawn[pawnno].counter.gp = totalgp;
}

void DivvyGold (void)
{
    int numpawns = 0;
    int totalgp = 0;
    int average;
    int modulo;
    int i;

    /* FIXME: Could be some confusion with compactpartypawns() */
    for (i = 0; i < 6; i++)
	if (gwiz.pawnno[i] > -1)
	    numpawns++;

    if (numpawns == 0)
	return;

    for (i = 0; i < numpawns; i++)
	{
	    totalgp += gwiz.pawn[i].counter.gp;
	    gwiz.pawn[i].counter.gp = 0;
	}

    modulo = totalgp % numpawns;
    average = totalgp / numpawns;

    for (i = 0; i < numpawns; i++)
	gwiz.pawn[i].counter.gp = average;
    i = 0;
    while (modulo > 0)
	{
	    if (i < numpawns)
		{
		    gwiz.pawn[i].counter.gp++;
		    modulo--;
		} else {
		    i = 0;
		    gwiz.pawn[i].counter.gp++;
		    modulo--;
		}
	    i++;
	}
}

SDL_Surface *RenderPawnInventory (PlayerPawn *pawn)
{
    SDL_Surface *srf = NewGwizSurface (gwiz.font.width*15, gwiz.font.height*8);
    SDL_Rect dest;
    int i;

    dest.x = 0;
    dest.y = 0;
    dest.h = gwiz.font.height;

    for (i = 0; i < 8; i++)
	if (pawn->item[i].usage != USAGE_NONE)
	    {
		SDL_Surface *name = GwizRenderText (pawn->item[i].name);
		dest.w = name->w;
		SDL_BlitSurface (name, NULL, srf, &dest);
		dest.y += gwiz.font.height;
		SDL_FreeSurface (name);
	    }
    return (srf);
}

void ChangeClass (void)
{
    PlayerPawn pawn;
    int whichpawn = NewPawnList();

    LoadPawn (whichpawn, &pawn);

    NewClassEligibilityList (&pawn);
    SavePawn (pawn, whichpawn);
}

void RenamePawn (void)
{
    PlayerPawn pawn;
    int whichpawn = NewPawnList();
    int i;

    LoadPawn (whichpawn, &pawn);

    for (i = 0; i < 16; i++)
	pawn.name[i] = '\0';
    NewTextEntry ("Enter new name:", pawn.name, 16);
    SavePawn (pawn, whichpawn);
}

void ReorderPartyFile (void)
{
    int validpawns = CountValidPawns()+1;
    PlayerPawn pawn[validpawns];
    int registeredpawns[validpawns];
    int pawnno;
    int i = 0;
    int j = 0;

    CompactPartyFile();
    for (i = 0; i < validpawns; i++)
	registeredpawns[i] = -1;
    for (i = 0; i < validpawns; i++)
	{
	    pawnno = NewPawnList();
	    if (pawnno < 0) /* cancelled reordering */
		return;
	    LoadPawn (pawnno, &pawn[i]);
	    for (j = 0; j < validpawns; j++)
		if (registeredpawns[j] == pawnno)
		    {
			i--; /* trying to list the same pawn twice.  Don't do */
			continue; /* it.  back up once, and start loop again */
		    }
	    registeredpawns[i] = pawnno;
	}
    for (i = 0; i < validpawns; i++)
	SavePawn (pawn[i], i);
}

inline short int PawnIsMage (PlayerPawn *pawn)
{
    if ((pawn->class == MAGE) || (pawn->class == SAMURAI)) return (TRUE);
    return (FALSE);
}

inline short int PawnIsCleric (PlayerPawn *pawn)
{
    if ((pawn->class == CLERIC) || (pawn->class == LORD)) return (TRUE);
    return (FALSE);
}

inline short int PawnIsWizard (PlayerPawn *pawn)
{
    if (pawn->class == WIZARD) return (TRUE);
    return (FALSE);
}

inline short int PawnIsNotMagical (PlayerPawn *pawn)
{
    if ((pawn->class == FIGHTER) || (pawn->class == THIEF) ||
	(pawn->class == NINJA)) return (TRUE);
    return (FALSE);
}

short int PartyIsGood (void)
{
    int i;
    for (i = 0; i < MAXPAWNS; i++)
	{
	    if (gwiz.pawnno[i] > -1)
		if (gwiz.pawn[i].ali == EVIL)
		    return (FALSE);
	}
    return (TRUE);
}

short int PartyIsNeutral (void)
{
    int i;
    for (i = 0; i < MAXPAWNS; i++)
	{
	    if (gwiz.pawnno[i] > -1)
		if ((gwiz.pawn[i].ali == EVIL) || (gwiz.pawn[i].ali == GOOD))
		    return (FALSE);
	}
    return (TRUE);
}

short int PartyIsEvil (void)
{
    int i;
    for (i = 0; i < MAXPAWNS; i++)
	{
	    if (gwiz.pawnno[i] > -1)
		if (gwiz.pawn[i].ali == GOOD)
		    return (FALSE);
	}
    return (TRUE);
}

short int PawnIsPartyCompatible (PlayerPawn *pawn)
{
    if (PartyIsGood() && (pawn->ali != EVIL))
	return (TRUE);
    if (PartyIsNeutral())
	return (TRUE);
    if (PartyIsEvil() && (pawn->ali != GOOD))
	return (TRUE);
    return (FALSE);
}

short int GetNumberOfIncompatiblePawns (void)
{
    PlayerPawn pawn;
    short int incompat = 0;
    int i;

    if (PartyIsNeutral())
	return (0);
    if (PartyIsGood ())
	{
	    for (i = 0; i < 20; i++)
		{
		    LoadPawn (i, &pawn);
		    if (pawn.ali == EVIL)
			incompat++;
		}
	} else if (PartyIsEvil()) {
	    for (i = 0; i < 20; i++)
		{
		    LoadPawn (i, &pawn);
		    if (pawn.ali == GOOD)
			incompat++;
		}
	}
    return (incompat);
}
