#include <exec/types.h>
#include <exec/alerts.h>
#include <intuition/intuition.h>
#include <graphics/gfx.h>
#include <graphics/displayinfo.h>
#include <graphics/gels.h>
#include <graphics/view.h>

#include <stdlib.h>

#include "animtools.h"
#include "saga.h"
#include "counters.h"

IMPORT struct GfxBase*       GfxBase;
IMPORT struct Window        *MainWindowPtr,
                            *InfoWindowPtr;
IMPORT struct WorldStruct    world[36 + 30];
IMPORT struct HeroStruct     hero[HEROES + 1];
IMPORT struct JarlStruct     jarl[JARLS + 1];
IMPORT struct MonsterStruct  monster[MONSTERS + 1];
IMPORT struct TreasureStruct treasure[TREASURES + 1];
IMPORT struct SordStruct     sord[SORDS + 1];
IMPORT UWORD                 DisplayDepth;

MODULE struct GelsInfo      *GInfoPtr     = NULL,
                            *InfoGInfoPtr = NULL;
MODULE struct Bob           *InfoBobPtr[TREASURES + 1 + 1],
                            *HeroBobPtr[HEROES + 1],
                            *JarlBobPtr[JARLS + 1],
                            *MonsterBobPtr[MONSTERS + 1],
                            *TreasureBobPtr[TREASURES + 1],
                            *SordBobPtr[SORDS + 1];

/* The word `Sword' is deliberately mispelled (within the source code) as
   Sord. This avoids collisions with the SWORD (signed word) typedef. */

NEWBOB NewBob =
{   NULL,               // initial image
    COUNTERWIDTH,       // width in words
    COUNTERHEIGHT,      // line height
    DEPTH,              // image depth
    0x7F,               // PlanePick
    0,                  // PlaneOnOff
    SAVEBACK | OVERLAY, // VSprite flags
    FALSE,              // double buffer?
    0,                  // raster depth
    HIDDEN_X, HIDDEN_Y, // x, y position (filled later)
    0,                  // hit mask
    0                   // me mask
};

AGLOBAL void createcounters(void)
{   SLONG whichhero, whichjarl, whichmonster, whichtreasure, whichsord;

    if (!(GInfoPtr = setupGelSys(MainWindowPtr->RPort, 0x03)))
    {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't set up GELs!\0", 24);
        cleanexit(EXIT_FAILURE);
    }
    NewBob.nb_RasDepth = DisplayDepth;

    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   NewBob.nb_Image = HeroData[whichhero];
        if (!(HeroBobPtr[whichhero] = makeBob(&NewBob)))
        {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't make hero bob(s)!\0", 24);
            cleanexit(EXIT_FAILURE);
        }
        AddBob(HeroBobPtr[whichhero], MainWindowPtr->RPort);
    }
    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
    {   NewBob.nb_Image = UnknownJarlData;
        if (!(JarlBobPtr[whichjarl] = makeBob(&NewBob)))
        {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't make jarl bob(s)!\0", 24);
            cleanexit(EXIT_FAILURE);
        }
        AddBob(JarlBobPtr[whichjarl], MainWindowPtr->RPort);
    }
    for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
    {   NewBob.nb_Image = MonsterData[whichmonster];
        if (!(MonsterBobPtr[whichmonster] = makeBob(&NewBob)))
        {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't make monster bob(s)!\0", 24);
            cleanexit(EXIT_FAILURE);
        }
        AddBob(MonsterBobPtr[whichmonster], MainWindowPtr->RPort);
    }
    for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
    {   NewBob.nb_Image = TreasureData[whichtreasure];
        if (!(TreasureBobPtr[whichtreasure] = makeBob(&NewBob)))
        {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't make treasure bob(s)!\0", 24);
            cleanexit(EXIT_FAILURE);
        }
        AddBob(TreasureBobPtr[whichtreasure], MainWindowPtr->RPort);
    }
    for (whichsord = 0; whichsord <= SORDS; whichsord++)
    {   NewBob.nb_Image = SordData[whichsord];
        if (!(SordBobPtr[whichsord] = makeBob(&NewBob)))
        {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't make sord bob(s)!\0", 24);
            cleanexit(EXIT_FAILURE);
        }
        AddBob(SordBobPtr[whichsord], MainWindowPtr->RPort);
}   }

AGLOBAL void destroycounters(void)
{   SLONG whichhero, whichjarl, whichmonster, whichtreasure, whichsord;

    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   if (HeroBobPtr[whichhero])
        {   remove_hero(whichhero, FALSE);
            RemBob(HeroBobPtr[whichhero]);
    }   }
    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
    {   if (JarlBobPtr[whichjarl])
        {   remove_jarl(whichjarl, FALSE);
            RemBob(JarlBobPtr[whichjarl]);
    }   }
    for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
    {   if (MonsterBobPtr[whichmonster])
        {   remove_monster(whichmonster, FALSE);
            RemBob(MonsterBobPtr[whichmonster]);
    }   }
    for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
    {   if (TreasureBobPtr[whichtreasure])
        {   remove_treasure(whichtreasure, FALSE);
            RemBob(TreasureBobPtr[whichtreasure]);
    }   }
    for (whichsord = 0; whichsord <= SORDS; whichsord++)
    {   if (SordBobPtr[whichsord])
        {   remove_sord(whichsord, FALSE);
            RemBob(SordBobPtr[whichsord]);
    }   }

    if (GInfoPtr)
    {   refreshcounters();
    }
    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   if (HeroBobPtr[whichhero])
        {   freeBob(HeroBobPtr[whichhero], NewBob.nb_RasDepth);
            HeroBobPtr[whichhero] = NULL;
    }   }
    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
    {   if (JarlBobPtr[whichjarl])
        {   freeBob(JarlBobPtr[whichjarl], NewBob.nb_RasDepth);
            JarlBobPtr[whichjarl] = NULL;
    }   }
    for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
    {   if (MonsterBobPtr[whichmonster])
        {   freeBob(MonsterBobPtr[whichmonster], NewBob.nb_RasDepth);
            MonsterBobPtr[whichmonster] = NULL;
    }   }
    for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
    {   if (TreasureBobPtr[whichtreasure])
        {   freeBob(TreasureBobPtr[whichtreasure], NewBob.nb_RasDepth);
            TreasureBobPtr[whichtreasure] = NULL;
    }   }
    for (whichsord = 0; whichsord <= SORDS; whichsord++)
    {   if (SordBobPtr[whichsord])
        {   freeBob(SordBobPtr[whichsord], NewBob.nb_RasDepth);
            SordBobPtr[whichsord] = NULL;
    }   }

    if (GInfoPtr)
    {   cleanupGelSys(GInfoPtr, MainWindowPtr->RPort);
}   }

AGLOBAL void unslot_hero(SLONG whichhero)
{   if (hero[whichhero].slot != -1)
    {   world[hero[whichhero].where].slot[hero[whichhero].slot] = FALSE;
        hero[whichhero].slot = -1;
}   }
AGLOBAL void unslot_jarl(SLONG whichjarl)
{   if (jarl[whichjarl].slot != -1)
    {   world[jarl[whichjarl].where].slot[jarl[whichjarl].slot] = FALSE;
        jarl[whichjarl].slot = -1;
}   }
AGLOBAL void unslot_monster(SLONG whichmonster)
{   if (monster[whichmonster].slot != -1)
    {   world[monster[whichmonster].where].slot[monster[whichmonster].slot] = FALSE;
        monster[whichmonster].slot = -1;
}   }
AGLOBAL void unslot_treasure(SLONG whichtreasure)
{   if (treasure[whichtreasure].slot != -1)
    {   world[treasure[whichtreasure].where].slot[treasure[whichtreasure].slot] = FALSE;
        treasure[whichtreasure].slot = -1;
}   }
AGLOBAL void unslot_sord(SLONG whichsord)
{   if (sord[whichsord].slot != -1)
    {   world[sord[whichsord].where].slot[sord[whichsord].slot] = FALSE;
        sord[whichsord].slot = -1;
}   }

AGLOBAL void move_hero(SLONG whichhero, FLAG display)
{   SLONG whichslot;

    // This assumes the counter has already been unslotted from its old
    // location.
    for (whichslot = 0; whichslot <= SLOTS; whichslot++)
    {   if (!(world[hero[whichhero].where].slot[whichslot]))
        {   hero[whichhero].slot = whichslot;
            break;
    }   }
    world[hero[whichhero].where].slot[whichslot] = TRUE;

    HeroBobPtr[whichhero]->BobVSprite->X = world[hero[whichhero].where].centrex - 12;
    HeroBobPtr[whichhero]->BobVSprite->Y = world[hero[whichhero].where].centrey - 12 - (whichslot * 7);
    if (display)
    {   refreshcounters();
}   }
AGLOBAL void move_monster(SLONG whichmonster, FLAG display)
{   SLONG whichslot;

    // This assumes the counter has already been unslotted from its old
    // location.
    for (whichslot = 0; whichslot <= SLOTS; whichslot++)
    {   if (!(world[monster[whichmonster].where].slot[whichslot]))
        {   monster[whichmonster].slot = whichslot;
            break;
    }   }
    world[monster[whichmonster].where].slot[whichslot] = TRUE;

    MonsterBobPtr[whichmonster]->BobVSprite->X = world[monster[whichmonster].where].centrex - 12;
    MonsterBobPtr[whichmonster]->BobVSprite->Y = world[monster[whichmonster].where].centrey - 12 - (whichslot * 7);
    if (display)
    {   refreshcounters();
}   }
AGLOBAL void move_jarl(SLONG whichjarl, FLAG display)
{   SLONG whichslot;

    // This assumes the counter has already been unslotted from its old
    // location.
    for (whichslot = 0; whichslot <= SLOTS; whichslot++)
    {   if (!(world[jarl[whichjarl].where].slot[whichslot]))
        {   jarl[whichjarl].slot = whichslot;
            break;
    }   }
    world[jarl[whichjarl].where].slot[whichslot] = TRUE;

    JarlBobPtr[whichjarl]->BobVSprite->X = world[jarl[whichjarl].where].centrex - 12;
    JarlBobPtr[whichjarl]->BobVSprite->Y = world[jarl[whichjarl].where].centrey - 12 - (whichslot * 7);
    if (display)
    {   refreshcounters();
}   }
AGLOBAL void move_treasure(SLONG whichtreasure, FLAG display)
{   SLONG whichslot;

    // This assumes the counter has already been unslotted from its old
    // location.
    for (whichslot = 0; whichslot <= SLOTS; whichslot++)
    {   if (!(world[treasure[whichtreasure].where].slot[whichslot]))
        {   treasure[whichtreasure].slot = whichslot;
            break;
    }   }
    world[treasure[whichtreasure].where].slot[whichslot] = TRUE;

    TreasureBobPtr[whichtreasure]->BobVSprite->X = world[treasure[whichtreasure].where].centrex - 12;
    TreasureBobPtr[whichtreasure]->BobVSprite->Y = world[treasure[whichtreasure].where].centrey - 12 - (whichslot * 7);
    if (display)
    {   refreshcounters();
}   }
AGLOBAL void move_sord(SLONG whichsord, FLAG display)
{   SLONG whichslot;

    // This assumes the counter has already been unslotted from its old
    // location.
    for (whichslot = 0; whichslot <= SLOTS; whichslot++)
    {   if (!(world[sord[whichsord].where].slot[whichslot]))
        {   sord[whichsord].slot = whichslot;
            break;
    }   }
    world[sord[whichsord].where].slot[whichslot] = TRUE;

    SordBobPtr[whichsord]->BobVSprite->X = world[sord[whichsord].where].centrex - 12;
    SordBobPtr[whichsord]->BobVSprite->Y = world[sord[whichsord].where].centrey - 12 - (whichslot * 7);
    if (display)
    {   refreshcounters();
}   }

AGLOBAL void init_counters(void)
{   SLONG whichhero, whichinfobob, whichjarl, whichmonster, whichtreasure,
          whichsord;

    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   hero[whichhero].slot = -1;
        HeroBobPtr[whichhero] = NULL;
    }
    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
    {   jarl[whichjarl].slot = -1;
        JarlBobPtr[whichjarl] = NULL;
    }
    for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
    {   monster[whichmonster].slot = -1;
        MonsterBobPtr[whichmonster] = NULL;
    }
    for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
    {   treasure[whichtreasure].slot = -1;
        TreasureBobPtr[whichtreasure] = NULL;
    }
    for (whichsord = 0; whichsord <= SORDS; whichsord++)
    {   sord[whichsord].slot = -1;
        SordBobPtr[whichsord] = NULL;
    }
    for (whichinfobob = 0; whichinfobob <= TREASURES + 1; whichinfobob++)
    {   InfoBobPtr[whichinfobob] = NULL;
}   }

AGLOBAL void revealjarl(SLONG whichjarl, FLAG display)
{   jarl[whichjarl].face        = FACEUP;
    jarl[whichjarl].recruitable = TRUE;
    JarlBobPtr[whichjarl]->BobVSprite->ImageData = JarlData[whichjarl];
    // InitMasks(JarlBobPtr[whichjarl]->BobVSprite);
    if (display)
    {   refreshcounters();
}   }

AGLOBAL void hidejarl(SLONG whichjarl, FLAG display)
{   jarl[whichjarl].face        = FACEDOWN;
    jarl[whichjarl].recruitable = FALSE;
    JarlBobPtr[whichjarl]->BobVSprite->ImageData = UnknownJarlData;
    // InitMasks(JarlBobPtr[whichjarl]->BobVSprite);
    if (display)
    {   refreshcounters();
}   }

AGLOBAL SLONG checkcounters(SWORD mousex, SWORD mousey, SLONG* countertype)
{   SLONG foundy,
          whichhero,
          whichcounter = -1,
          whichjarl,
          whichmonster,
          whichtreasure, whichsord;
    FLAG  found = FALSE;

    *(countertype) = -1;

    /* This assumes that counters with higher y-values (ie. lower on the
    screen) have higher priority than those with lower y-values. */

    // find all counters lying under the pointer
    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   if
        (   mousex >= HeroBobPtr[whichhero]->BobVSprite->X
         && mousex <= HeroBobPtr[whichhero]->BobVSprite->X + 24 - 1
         && mousey >= HeroBobPtr[whichhero]->BobVSprite->Y
         && mousey <= HeroBobPtr[whichhero]->BobVSprite->Y + 24 - 1
        )
        {   hero[whichhero].foundbob = TRUE;
            found = TRUE;
    }   }
    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
    {   if
        (   mousex >= JarlBobPtr[whichjarl]->BobVSprite->X
         && mousex <= JarlBobPtr[whichjarl]->BobVSprite->X + 24 - 1
         && mousey >= JarlBobPtr[whichjarl]->BobVSprite->Y
         && mousey <= JarlBobPtr[whichjarl]->BobVSprite->Y + 24 - 1
        )
        {   jarl[whichjarl].foundbob = TRUE;
            found = TRUE;
    }   }
    for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
    {   if
        (   mousex >= MonsterBobPtr[whichmonster]->BobVSprite->X
         && mousex <= MonsterBobPtr[whichmonster]->BobVSprite->X + 24 - 1
         && mousey >= MonsterBobPtr[whichmonster]->BobVSprite->Y
         && mousey <= MonsterBobPtr[whichmonster]->BobVSprite->Y + 24 - 1
        )
        {   monster[whichmonster].foundbob = TRUE;
            found = TRUE;
    }   }
    for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
    {   if
        (   mousex >= TreasureBobPtr[whichtreasure]->BobVSprite->X
         && mousex <= TreasureBobPtr[whichtreasure]->BobVSprite->X + 24 - 1
         && mousey >= TreasureBobPtr[whichtreasure]->BobVSprite->Y
         && mousey <= TreasureBobPtr[whichtreasure]->BobVSprite->Y + 24 - 1
        )
        {   treasure[whichtreasure].foundbob = TRUE;
            found = TRUE;
    }   }
    for (whichsord = 0; whichsord <= SORDS; whichsord++)
    {   if
        (   mousex >= SordBobPtr[whichsord]->BobVSprite->X
         && mousex <= SordBobPtr[whichsord]->BobVSprite->X + 24 - 1
         && mousey >= SordBobPtr[whichsord]->BobVSprite->Y
         && mousey <= SordBobPtr[whichsord]->BobVSprite->Y + 24 - 1
        )
        {   sord[whichsord].foundbob = TRUE;
            found = TRUE;
    }   }

    if (!found)
    {   return(-1);
    }

    // determine which counter is topmost (ie. which is lower on the screen)
    foundy = -1;
    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   if
        (   hero[whichhero].foundbob
         && HeroBobPtr[whichhero]->BobVSprite->Y > foundy
        )
        {   whichcounter = whichhero;
            *(countertype) = HERO;
            foundy = HeroBobPtr[whichhero]->BobVSprite->Y;
        }
        hero[whichhero].foundbob = FALSE;
    }
    for (whichjarl = 0; whichjarl <= JARLS; whichjarl++)
    {   if
        (   jarl[whichjarl].foundbob
         && JarlBobPtr[whichjarl]->BobVSprite->Y > foundy
        )
        {   whichcounter = whichjarl;
            *(countertype) = JARL;
            foundy = JarlBobPtr[whichjarl]->BobVSprite->Y;
        }
        jarl[whichjarl].foundbob = FALSE;
    }
    for (whichmonster = 0; whichmonster <= MONSTERS; whichmonster++)
    {   if
        (   monster[whichmonster].foundbob
         && MonsterBobPtr[whichmonster]->BobVSprite->Y > foundy
        )
        {   whichcounter = whichmonster;
            *(countertype) = MONSTER;
            foundy = MonsterBobPtr[whichmonster]->BobVSprite->Y;
        }
        monster[whichmonster].foundbob = FALSE;
    }
    for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
    {   if
        (   treasure[whichtreasure].foundbob
         && TreasureBobPtr[whichtreasure]->BobVSprite->Y > foundy
        )
        {   whichcounter = whichtreasure;
            *(countertype) = TREASURE;
            foundy = TreasureBobPtr[whichtreasure]->BobVSprite->Y;
        }
        treasure[whichtreasure].foundbob = FALSE;
    }
    for (whichsord = 0; whichsord <= SORDS; whichsord++)
    {   if
        (   sord[whichsord].foundbob
         && SordBobPtr[whichsord]->BobVSprite->Y > foundy
        )
        {   whichcounter = whichsord;
            *(countertype) = SORD;
            foundy = SordBobPtr[whichsord]->BobVSprite->Y;
        }
        sord[whichsord].foundbob = FALSE;
    }

    return(whichcounter);
}

AGLOBAL void select_hero(SLONG whichhero, FLAG display)
{   if (hero[whichhero].promoted != -1)
    {   HeroBobPtr[whichhero]->BobVSprite->ImageData = SelectedJarlData[hero[whichhero].promoted];
    } else
    {   HeroBobPtr[whichhero]->BobVSprite->ImageData = SelectedHeroData[whichhero];
    }
    // InitMasks(HeroBobPtr[whichhero]->BobVSprite);
    if (display)
    {   refreshcounters();
}   }
AGLOBAL void deselect_hero(SLONG whichhero, FLAG display)
{   if (hero[whichhero].promoted != -1)
    {   HeroBobPtr[whichhero]->BobVSprite->ImageData = JarlData[hero[whichhero].promoted];
    } else
    {   HeroBobPtr[whichhero]->BobVSprite->ImageData = HeroData[whichhero];
    }
    // InitMasks(HeroBobPtr[whichhero]->BobVSprite);
    if (display)
    {   refreshcounters();
}   }
AGLOBAL void select_jarl(SLONG whichjarl, FLAG display)
{   JarlBobPtr[whichjarl]->BobVSprite->ImageData = SelectedJarlData[whichjarl];
    // InitMasks(JarlBobPtr[whichjarl]->BobVSprite);
    if (display)
    {   refreshcounters();
}   }
AGLOBAL void deselect_jarl(SLONG whichjarl, FLAG display)
{   JarlBobPtr[whichjarl]->BobVSprite->ImageData = JarlData[whichjarl];
    // InitMasks(JarlBobPtr[whichjarl]->BobVSprite);
    if (display)
    {   refreshcounters();
}   }

AGLOBAL void remove_hero(SLONG whichhero, FLAG display)
{   unslot_hero(whichhero);
    HeroBobPtr[whichhero]->BobVSprite->X = HIDDEN_X;
    HeroBobPtr[whichhero]->BobVSprite->Y = HIDDEN_Y;
    if (display)
    {   refreshcounters();
}   }
AGLOBAL void remove_jarl(SLONG whichjarl, FLAG display)
{   unslot_jarl(whichjarl);
    JarlBobPtr[whichjarl]->BobVSprite->X = HIDDEN_X;
    JarlBobPtr[whichjarl]->BobVSprite->Y = HIDDEN_Y;
    if (display)
    {   refreshcounters();
}   }
AGLOBAL void remove_monster(SLONG whichmonster, FLAG display)
{   unslot_monster(whichmonster);
    MonsterBobPtr[whichmonster]->BobVSprite->X = HIDDEN_X;
    MonsterBobPtr[whichmonster]->BobVSprite->Y = HIDDEN_Y;
    if (display)
    {   refreshcounters();
}   }
AGLOBAL void remove_treasure(SLONG whichtreasure, FLAG display)
{   unslot_treasure(whichtreasure);
    TreasureBobPtr[whichtreasure]->BobVSprite->X = HIDDEN_X;
    TreasureBobPtr[whichtreasure]->BobVSprite->Y = HIDDEN_Y;
    if (display)
    {   refreshcounters();
}   }
AGLOBAL void remove_sord(SLONG whichsord, FLAG display)
{   unslot_sord(whichsord);
    SordBobPtr[whichsord]->BobVSprite->X = HIDDEN_X;
    SordBobPtr[whichsord]->BobVSprite->Y = HIDDEN_Y;
    if (display)
    {   refreshcounters();
}   }

AGLOBAL void refreshcounters(void)
{   WaitTOF();
    SortGList(MainWindowPtr->RPort);
    DrawGList(MainWindowPtr->RPort, ViewPortAddress(MainWindowPtr));
    WaitTOF();
}

AGLOBAL void reset_images(void)
{   SLONG whichhero;

    for (whichhero = 0; whichhero <= HEROES; whichhero++)
    {   HeroBobPtr[whichhero]->BobVSprite->ImageData = HeroData[whichhero];
        // InitMasks(HeroBobPtr[whichhero]->BobVSprite);
}   }

AGLOBAL void hero_info(SLONG whichhero)
{   SLONG infobobs = 0, whichsord, whichtreasure;

    if (!(InfoGInfoPtr = setupGelSys(InfoWindowPtr->RPort, 0x03)))
    {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't set up GELs!\0", 24);
        cleanexit(EXIT_FAILURE);
    }

    for (whichsord = 0; whichsord <= SORDS; whichsord++)
    {   if (sord[whichsord].possessortype == HERO
         && sord[whichsord].possessor     == whichhero)
        {   NewBob.nb_Image = SordData[whichsord];
            if (!(InfoBobPtr[0] = makeBob(&NewBob)))
            {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't make hero sword bob!\0", 24);
                cleanexit(EXIT_FAILURE);
            }
            AddBob(InfoBobPtr[0], InfoWindowPtr->RPort);
            InfoBobPtr[0]->BobVSprite->X = 600;
            InfoBobPtr[0]->BobVSprite->Y = 16;
            infobobs = 1;
            break;
    }   }

    for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
    {   if (treasure[whichtreasure].possessortype == HERO
         && treasure[whichtreasure].possessor     == whichhero)
        {   NewBob.nb_Image = TreasureData[whichtreasure];
            if (!(InfoBobPtr[infobobs] = makeBob(&NewBob)))
            {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't make hero treasure bob(s)!\0", 24);
                cleanexit(EXIT_FAILURE);
            }
            AddBob(InfoBobPtr[infobobs], InfoWindowPtr->RPort);
            InfoBobPtr[infobobs]->BobVSprite->X = 600;
            InfoBobPtr[infobobs]->BobVSprite->Y = 16 + (infobobs * (24 + 4));
            infobobs++;
    }   }

    SortGList(InfoWindowPtr->RPort);
    DrawGList(InfoWindowPtr->RPort, ViewPortAddress(InfoWindowPtr));
    WaitTOF();
}

AGLOBAL void jarl_info(SLONG whichjarl)
{   SLONG infobobs = 0, whichsord, whichtreasure;

    if (!(InfoGInfoPtr = setupGelSys(InfoWindowPtr->RPort, 0x03)))
    {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't set up GELs!\0", 24);
        cleanexit(EXIT_FAILURE);
    }

    for (whichsord = 0; whichsord <= SORDS; whichsord++)
    {   if (sord[whichsord].possessortype == JARL
         && sord[whichsord].possessor     == whichjarl)
        {   NewBob.nb_Image = SordData[whichsord];
            if (!(InfoBobPtr[0] = makeBob(&NewBob)))
            {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't make jarl sword bob!\0", 24);
                cleanexit(EXIT_FAILURE);
            }
            AddBob(InfoBobPtr[0], InfoWindowPtr->RPort);
            InfoBobPtr[0]->BobVSprite->X = 600;
            InfoBobPtr[0]->BobVSprite->Y = 16;
            infobobs = 1;
            break;
    }   }

    for (whichtreasure = 0; whichtreasure <= TREASURES; whichtreasure++)
    {   if (treasure[whichtreasure].possessortype == JARL
         && treasure[whichtreasure].possessor     == whichjarl)
        {   NewBob.nb_Image = TreasureData[whichtreasure];
            if (!(InfoBobPtr[infobobs] = makeBob(&NewBob)))
            {   DisplayAlert(AT_Recovery, "\0\20\20Saga: Can't make jarl treasure bob(s)!\0", 24);
                cleanexit(EXIT_FAILURE);
            }
            AddBob(InfoBobPtr[infobobs], InfoWindowPtr->RPort);
            InfoBobPtr[infobobs]->BobVSprite->X = 600;
            InfoBobPtr[infobobs]->BobVSprite->Y = 16 + (infobobs * (24 + 4));
            infobobs++;
    }   }

    SortGList(InfoWindowPtr->RPort);
    DrawGList(InfoWindowPtr->RPort, ViewPortAddress(InfoWindowPtr));
    WaitTOF();
}

AGLOBAL void uninfo(void)
{   SLONG whichinfobob;

    for (whichinfobob = 0; whichinfobob <= TREASURES + 1; whichinfobob++)
    {   if (InfoBobPtr[whichinfobob])
        {   RemBob(InfoBobPtr[whichinfobob]);
    }   }
    if (InfoGInfoPtr)
    {    SortGList(InfoWindowPtr->RPort);
         DrawGList(InfoWindowPtr->RPort, ViewPortAddress(InfoWindowPtr));
         WaitTOF();
    }
    for (whichinfobob = 0; whichinfobob <= TREASURES + 1; whichinfobob++)
    {   if (InfoBobPtr[whichinfobob])
        {   freeBob(InfoBobPtr[whichinfobob], NewBob.nb_RasDepth);
            InfoBobPtr[whichinfobob] = NULL;
    }   }
    if (InfoGInfoPtr)
    {   cleanupGelSys(InfoGInfoPtr, InfoWindowPtr->RPort);
}   }
