/*
@Copyright Looking Glass Studios, Inc.
1996,1997,1998,1999,2000 Unpublished Work.
*/

// alarm icon
#include <2d.h>
#include <math.h>

#include <mprintf.h>
#include <resapi.h>
#include <playrobj.h>
#include <rooms.h>
#include <roomsys.h>
#include <filevar.h>
#include <scrnmode.h>
#include <questapi.h>
#include <dbfile.h>
#include <simtime.h>
#include <traitman.h>

#include <kbcook.h>
#include <keydefs.h>

#include <objpos.h>
#include <iobjsys.h>
#include <propbase.h>

#include <drkpanl.h>
#include <prcniter.h>

#include <dpcmap.h>
#include <dpcovrly.h>
#include <dpcutils.h>
#include <dpcovcst.h>
#include <dpcmfddm.h>
#include <dpcplayr.h>
#include <dpcplprp.h>
#include <dpcmulti.h>
#include <dpcgame.h>
#include <dpctrcst.h>
#include <dpcprop.h>
#include <dpcparam.h>

#include <netman.h>

// ui library not C++ ized properly yet 
extern "C" {
#include <event.h>
#include <gadbox.h>
#include <gadblist.h>
#include <gadbutt.h>
}

#include <dbmem.h>

// spans the whole width of the screen
static Rect full_rect = {{LMFD_X, LMFD_Y}, {RMFD_X + RMFD_W, RMFD_Y + RMFD_H}}; 
//static Rect close_rect = {{163,8},{163 + 20, 8 + 21}};
static Rect close_rect = {{606,6},{606 + 20, 6 + 21}};

static Rect mini_rect = {{482,268},{482+ 142, 268 + 22}};

static LGadButton close_button;
static DrawElement close_elem;
static IRes *close_handles[2];
static grs_bitmap *close_bitmaps[4];

static LGadButton mini_button;
static DrawElement mini_elem;
static IRes *mini_handles[2];
static grs_bitmap *mini_bitmaps[4];

static IRes *gMapHnd         = NULL;
static IRes *gMiniMapHnd     = NULL;
static IRes *gAutoMapHnd     = NULL;
static IRes *gMiniAutoMapHnd = NULL;
static IRes *gMapNone        = NULL;
static IRes *gMapBack        = NULL;
static IRes *gOnHnd          = NULL;
static IRes *gOffHnd         = NULL;
static IRes *gBrackets       = NULL;

static ObjID gSelectedObj = OBJ_NULL;
static ObjID gMouseOverObj = OBJ_NULL;

static int map_obj_pos(ObjID o);
static int map_cursor_pos(Point mpt);

bool DPCHasMap();

#define MAX_ROOMS 64

// Here's the type of my global 
struct sExplored
{
    char explored[MAX_ROOMS];
};

// Here's my descriptor, which identifies my stuff to the tag file & editor
sFileVarDesc gExploredDesc = 
{
    kMissionVar,              // Where do I get saved?
    "EXPLORED",               // Tag file tag
    "Rooms Explored",         // friendly name
    FILEVAR_TYPE(sExplored),  // Type (for editing)
    { 1, 0},                  // version
    { 1, 0},                  // last valid version 
    "deepc",                  // optional: what game am I in NULL means all 
}; 

// The actual global variable
cFileVar<sExplored,&gExploredDesc> gExplored; 

grs_canvas gMapCanvas;
grs_bitmap *gMapBitmap;

//--------------------------------------------------------------------------------------
void DPCMapInit(int which)
{
    int i;
    gMapNone= LoadPCX("nomap");
    gMapBack = LoadPCX("mapback");
    gOnHnd = LoadPCX("minion");
    gOffHnd = LoadPCX("minioff");
    gBrackets = LoadPCX("bracket");
    //gPlayerHnd = LoadPCX("plrpip");

    close_handles[0] = LoadPCX("CloseOff"); 
    close_handles[1] = LoadPCX("CloseOn"); 
    close_bitmaps[0] = (grs_bitmap *) close_handles[0]->Lock();
    close_bitmaps[1] = (grs_bitmap *) close_handles[1]->Lock();
    for (i = 2; i < 4; i++)
    {
        close_bitmaps[i] = close_bitmaps[0];
    }

    mini_handles[0] = LoadPCX("minimap0"); 
    mini_handles[1] = LoadPCX("minimap1"); 
    mini_bitmaps[0] = (grs_bitmap *) mini_handles[0]->Lock();
    mini_bitmaps[1] = (grs_bitmap *) mini_handles[1]->Lock();
    for (i = 2; i < 4; i++)
    {
        mini_bitmaps[i] = mini_bitmaps[0];
    }

    short w,h;
    Rect use_rect;
    sScrnMode smode;
    ScrnModeGet(&smode);
    w = RectWidth(&full_rect);
    h = RectHeight(&full_rect);
    use_rect.ul.x = (smode.w - w) / 2;
    use_rect.ul.y = full_rect.ul.y;
    use_rect.lr.x = use_rect.ul.x + w;
    use_rect.lr.y = use_rect.ul.y + h;
    DPCOverlaySetRect(which,use_rect);

    gMapBitmap = gr_alloc_bitmap(BMT_FLAT16, 0, w, h); // BMF_TRANS
    gr_make_canvas(gMapBitmap, &gMapCanvas);
}

//--------------------------------------------------------------------------------------
void DPCMapTerm(void)
{
    SafeFreeHnd(&gMapBack);
    SafeFreeHnd(&gMapNone);
    SafeFreeHnd(&gOnHnd);
    SafeFreeHnd(&gOffHnd);
    SafeFreeHnd(&gBrackets);

    close_handles[0]->Unlock();
    close_handles[1]->Unlock();
    SafeFreeHnd(&close_handles[0]);
    SafeFreeHnd(&close_handles[1]);

    mini_handles[0]->Unlock();
    mini_handles[1]->Unlock();
    SafeFreeHnd(&mini_handles[0]);
    SafeFreeHnd(&mini_handles[1]);

    gr_free(gMapBitmap);
}

//--------------------------------------------------------------------------------------
static HRESULT FindReferenceMarker(int maploc, ObjID *pObj, Point *pLoc)
{
    sPropertyObjIter iter;
    ObjID obj;
    sMapRef *pMap;
    int count = 0;
    int use_frame;
    BOOL found = FALSE;

    use_frame = maploc;
    while (!found)
    {
        gPropMapRef->IterStart(&iter);
        while (gPropMapRef->IterNext(&iter,&obj))
        {
            // for now, assume our first one is our match
            gPropMapRef->Get(obj, &pMap);
            if (pMap->m_frame == use_frame)
            {
                *pObj = obj;
                pLoc->x = pMap->m_x;
                pLoc->y = pMap->m_y;
                found = TRUE;
                break;
            }
        }
        gPropMapRef->IterStop(&iter);
        if (use_frame == -1)
        {
            if (!found)
                return(E_FAIL);
        }
        else
            use_frame = -1; // try the generic scale markers on our next pass
    }

    return(S_OK);
}
//--------------------------------------------------------------------------------------
static HRESULT FindScaleMarkers(ObjID *pObj1, Point *pLoc1, ObjID *pObj2, Point *pLoc2)
{
    sPropertyObjIter iter;
    ObjID obj;
    sMapRef *pMap;
    int count = 0;
    BOOL found = FALSE;

    gPropMapRef->IterStart(&iter);
    while (gPropMapRef->IterNext(&iter,&obj))
    {
        // for now, assume our first one is our match
        gPropMapRef->Get(obj, &pMap);

        // -1 is special scale marker
        if (pMap->m_frame == -1)
        {
            if (count == 0)
            {
                *pObj1 = obj;
                pLoc1->x = pMap->m_x;
                pLoc1->y = pMap->m_y;
            }
            else
            {
                *pObj2 = obj;
                pLoc2->x = pMap->m_x;
                pLoc2->y = pMap->m_y;
            }
            count++;
            if (count == 2)
            {
                //mprintf("found markers with frame %d\n",use_frame);
                found = TRUE;
                break;
            }
        }
    }
    gPropMapRef->IterStop(&iter);

    if (count < 2)
    {
        Warning(("FindScaleMarkers: only found %d markers!\n",count));
        return(S_FALSE);
    }

    return(S_OK);
}
//--------------------------------------------------------------------------------------
static float gScaleX = 0;
static float gScaleY = 0;
static HRESULT GetMapScale(float *pScaleX, float *pScaleY)
{
    ObjPos *p1, *p2;
    ObjID mark1, mark2;
    mxs_vector v1, v2;
    mxs_vector delta;
    Point loc1, loc2;

    if (gScaleX == 0)
    {
        if (FindScaleMarkers(&mark1, &loc1, &mark2, &loc2) != S_OK)
            return(E_FAIL);

        p1 = ObjPosGet(mark1);
        p2 = ObjPosGet(mark2);
        mx_copy_vec(&v1, &p1->loc.vec);
        mx_copy_vec(&v2, &p2->loc.vec);

        // scale is ratio of map units to world units
        mx_sub_vec(&delta, &v2, &v1); // v2 - v1

        sMapParams *params = GetMapParams();
        if (params->m_rotatehack)
        {
            gScaleX = fabs(float(loc2.x) - float(loc1.x)) / fabs(delta.x);
            gScaleY = fabs(float(loc2.y) - float(loc1.y)) / fabs(delta.y);
        }
        else
        {
            gScaleX = fabs(float(loc2.x) - float(loc1.x)) / fabs(delta.y);
            gScaleY = fabs(float(loc2.y) - float(loc1.y)) / fabs(delta.x);
        }
    }

    *pScaleX = gScaleX;
    *pScaleY = gScaleY;
    return(S_OK);
}


//--------------------------------------------------------------------------------------
static HRESULT FindObjectInMapCoords(ObjID o, Point *pt, int *pMaploc)
{
    ObjPos *pos, *markerpos;
    ObjID mark;
    mxs_vector d;
    float scale_x, scale_y;
    Point loc;
    Point map;
    HRESULT retval;
    sMapParams *params = GetMapParams();

    int maploc = map_obj_pos(o); 
    if (pMaploc != NULL)
        *pMaploc = maploc;

    // find our reference markers and establish translation factor
    retval = GetMapScale(&scale_x,&scale_y);
    if (retval != S_OK)
        return(retval);

    retval = FindReferenceMarker(maploc, &mark, &loc);
    if (retval != S_OK)
        return(retval);

    // convert object position into map coords using reference markers
    pos = ObjPosGet(o);
    markerpos = ObjPosGet(mark);

    mx_sub_vec(&d, &pos->loc.vec, &markerpos->loc.vec);

    // perform dimensional conversion
    if (params->m_rotatehack)
    {
        // we are on a mutant level that is rotated 90 degrees
        // which, ironically, is more like the world coords
        map.x = loc.x + (d.x * scale_y * -1);
        map.y = loc.y + (d.y * scale_x);
    }
    else
    {
        // normal case
        map.x = loc.x + (d.y * scale_x);
        map.y = loc.y + (d.x * scale_y);
    }

    pt->x = map.x;
    pt->y = map.y;

    return(retval);
}
//--------------------------------------------------------------------------------------
#define SELECT_SIZE 8
static void DrawObjectInMapCoords(Point dp, ObjID o, IRes *hnd, BOOL rotate, BOOL automap)
{
    Point mapcoord;
    Point drawpt;
    ObjPos *pos;
    sMapParams *params = GetMapParams();
    int maploc;

    pos = ObjPosGet(o);
    if (FindObjectInMapCoords(o, &mapcoord, &maploc) != S_OK)
        return;

    // if we aren't automapping and we haven't been to the relevant room, then bail.
    //  unless we are in a network game, and it is another player, cause that is just better
    AutoAppIPtr(NetManager);
    if (!(pNetManager->Networking() && IsAPlayer(o)))
        if (!automap && !gExplored.explored[maploc])
            return;

        // finally, draw the handle
    drawpt.x = dp.x + mapcoord.x;
    drawpt.y = dp.y + mapcoord.y;

    if (rotate)
    {
        fixang theta = 0x8000 - pos->fac.tz;
        if (params->m_rotatehack)
            theta = theta + 0x4000;
        DrawByHandleCenterRotate(hnd, drawpt, theta);
    }
    else
        DrawByHandleCenter(hnd, drawpt);

    // bracket on selected obj
    // note we only do this in fullscreen mode
    if (DPCOverlayCheck(kOverlayMap))
    {
        if (gSelectedObj == o)
            DrawByHandleCenter(gBrackets,drawpt);

        // blinking bracket on potential selection
        Point mpos;
        int dx,dy;
        Rect r = DPCOverlayGetRect(kOverlayMap);
        mouse_get_xy(&mpos.x,&mpos.y);
        dx = abs(mpos.x - r.ul.x - drawpt.x);
        dy = abs(mpos.y - r.ul.y - drawpt.y);
        if ((dx <= SELECT_SIZE) && (dy <= SELECT_SIZE))
        {
            if (o != PlayerObject())
            {
                gMouseOverObj = o;
                if (GetSimTime() & (1 << 9))
                    DrawByHandleCenter(gBrackets,drawpt);
            }
        }
    }

    // draw in associated label
    //mprintf("minimap check is %d\n",DPCOverlayCheck(kOverlayMiniMap));
    if (gPropMapText->IsRelevant(o) && DPCOverlayCheck(kOverlayMap))
    {
        const char *pStr;
        char temp[255];
        int w,h;
        gPropMapText->Get(o,&pStr);
        strcpy(temp,pStr); // this is stupid, but gr_font_foo doesn't take constr strings

        w = gr_font_string_width(gDPCFont,temp);
        h = gr_font_string_height(gDPCFont,temp);
        gr_font_string(gDPCFont,temp,drawpt.x - (w / 2), drawpt.y + 10);

        // hey, we are theoretically editing text
        // so draw a blinking cursor
        if ((o == gSelectedObj) && (GetSimTime() & (1 << 9)))
        {
            gr_set_fcolor(gDPCTextColor);
            gr_vline(drawpt.x + (w / 2) + 5, drawpt.y + 10 , drawpt.y + 10 + h);
        }
    }
}
//--------------------------------------------------------------------------------------
#define MAP_X 10
#define MAP_Y 8


// we would really get a big speedup by drawing this to a temp offscreen
// buffer -- X
void DPCMapDrawContents(Point dp, IRes *back, BOOL automap)
{
    int maps = 0;
    char buf[64]; 
    char temp[64];
    Rect dr;
    Point drawpt;

    // clear our scale factor cache
    gScaleX = 0;
    gScaleY = 0;

    if (!DPCHasMap())
        DrawByHandle(gMapNone,dp);
    else
    {
        DrawByHandle(back,dp);

        int maploc = map_obj_pos(PlayerObject()); 

        // draw in the "we've been here" decals
        char lvl[255];
        DPCGetLevelName(lvl,sizeof(lvl));
        sprintf(buf,"%s/p001xa",lvl); 
        cRectArray tmpRects; 
        FetchUIRects(buf, tmpRects);

        int i;
        for (i=0; i < tmpRects.Size(); i++)
        {
            if (gExplored.explored[i])
            {
                dr = tmpRects[i]; 

                sprintf(buf,"p001x%03d",i); 
                sprintf(temp,"intrface\\%s",lvl);

                IRes *decal = LoadPCX(buf,temp);
                drawpt.x = dr.ul.x + dp.x;
                drawpt.y = dr.ul.y + dp.y;
                DrawByHandle(decal, drawpt);
                SafeFreeHnd(&decal);
            }
        }

        // draw the current location decal
        sprintf(buf,"%s/p001ra",lvl); 
        FetchUIRects(buf, tmpRects);

        if (maploc >= 0 && maploc < tmpRects.Size())
        {
            dr = tmpRects[maploc]; 

            // Get the image
            sprintf(buf,"p001r%03d",maploc); 
            sprintf(temp,"intrface\\%s",lvl);

            IRes *decal = LoadPCX(buf,temp);
            drawpt.x = dr.ul.x + dp.x;
            drawpt.y = dr.ul.y + dp.y;
            DrawByHandle(decal, drawpt);
            SafeFreeHnd(&decal);

            if (!gExplored.explored[maploc])
                DPCMapSetExplored(maploc, 1);
        }

        gMouseOverObj = OBJ_NULL;

        // iterate over all map-relevant objs and draw them 
        cConcreteIter iter(gPropMapObjIcon);
        ObjID obj;
        IRes *icon;
        Label *name;
        BOOL rotate = FALSE;

        iter.Start();   
        while (iter.Next(&obj))
        {
            // how brutal is it to load these each frame?
            gPropMapObjIcon->Get(obj,&name);
            gPropMapObjRotate->Get(obj,&rotate);
            icon = LoadPCX(name->text);
            DrawObjectInMapCoords(dp, obj, icon, rotate, automap);
            SafeFreeHnd(&icon);
        }
        iter.Stop();
    }
}

//--------------------------------------------------------------------------------------
#define ONOFF_X 487
#define ONOFF_Y 268
#define MAPTEXT_X    166
#define MAPTEXT_Y    268
#define MAPTEXT_W    280

void DPCMapDrawCore(void)
{
    Rect r = DPCOverlayGetRect(kOverlayMap);
    Point drawpt;
    BOOL automap;

    drawpt.x = 0;
    drawpt.y = 0;
    DrawByHandle(gMapBack,drawpt);

    drawpt.x = MAP_X;
    drawpt.y = MAP_Y;
    AutoAppIPtr(DPCPlayer);
    automap = pDPCPlayer->HasTrait(PlayerObject(),kTraitAutomap);
    if (automap)
        DPCMapDrawContents(drawpt, gAutoMapHnd, automap);
    else
        DPCMapDrawContents(drawpt, gMapHnd, automap);

    // draw mouseover text
    Point mpt;
    mouse_get_xy(&mpt.x,&mpt.y);
    // put it in the decal coord frame
    mpt.x = mpt.x - drawpt.x - r.ul.x;
    mpt.y = mpt.y - drawpt.y - r.ul.y;

    int maploc = map_cursor_pos(mpt); 
    //mprintf("maploc is %d\n",maploc);
    if (gExplored.explored[maploc] || automap)
    {
        char tagname[255];
        char text[255];
        char lvl[255];
        DPCGetLevelName(lvl,sizeof(lvl));
        sprintf(tagname,"MapText_%s_",lvl);
        DPCStringFetch(text,sizeof(text),tagname,"maptext",maploc);
        if (strlen(text) > 0)
        {
            short w;
            w = gr_font_string_height(gDPCFont,text);
            gr_font_string(gDPCFont,text,MAPTEXT_X + ((MAPTEXT_W - w) / 2), MAPTEXT_Y);
        }
    }
}

//--------------------------------------------------------------------------------------

void DPCMapDraw(unsigned long inDeltaTicks)
{
    Rect r = DPCOverlayGetRect(kOverlayMap);
    gr_push_canvas(&gMapCanvas);
    DPCMapDrawCore();
    gr_pop_canvas();

    gr_bitmap(gMapBitmap, r.ul.x, r.ul.y);

    LGadDrawBox(VB(&close_button),NULL);
    LGadDrawBox(VB(&mini_button),NULL);

    Point drawpt;
    drawpt.x = ONOFF_X + r.ul.x;
    drawpt.y = ONOFF_Y + r.ul.y;
    if (DPCOverlayCheck(kOverlayMiniMap))
        DrawByHandle(gOnHnd, drawpt);
    else
        DrawByHandle(gOffHnd, drawpt);
}

//--------------------------------------------------------------------------------------
static bool rawkey_handler_func(uiEvent* ev, Region* r, void* data)
{
    ushort keycode;
    bool result;

    if (gSelectedObj == OBJ_NULL)
        return(FALSE);

    kbs_event kbe;
    kbe.code = ((uiRawKeyEvent*)ev)->scancode;
    kbe.state = ((uiRawKeyEvent*)ev)->action;

    kb_cook(kbe,&keycode,&result);

    int kc;
    if (keycode&KB_FLAG_DOWN)
    {
        kc=keycode&~KB_FLAG_DOWN;
        {
            char text[255];
            const char *oldtext;
            AutoAppIPtr(ObjectSystem);

            if (gPropMapText->Get(gSelectedObj, &oldtext))
                strcpy(text,oldtext);
            else
                strcpy(text,"");
            int l = strlen(text);
            switch (kc)
            {
                case KEY_BS:
                    if (l >= 1)
                    {
                        text[l-1] = '\0';
                        gPropMapText->Set(gSelectedObj, text);
                    }
                    break;
                case KEY_DEL:
                case KEY_PAD_DEL:
                    {
                        AutoAppIPtr(TraitManager);
                        ObjID markerarch = pObjectSystem->GetObjectNamed("Nav Marker");
                        if (pTraitManager->ObjHasDonor(gSelectedObj,markerarch))
                        {
                            pObjectSystem->Destroy(gSelectedObj);
                            gSelectedObj = OBJ_NULL;
                        }
                    }
                    break;
                case KEY_ENTER:
                    gSelectedObj = OBJ_NULL;
                    break;
                default:
                    if (isprint(kc))
                    {
                        if (l < 254)
                        {
                            text[l] = kc;
                            text[l+1] = '\0';
                        }
                    }
                    gPropMapText->Set(gSelectedObj, text);
                    break;
            }
            return(TRUE);
        }
    }
    return(FALSE);
}
//--------------------------------------------------------------------------------------
bool DPCMapHandleMouse(Point pos) 
{
    if (gMouseOverObj != PlayerObject())
        gSelectedObj = gMouseOverObj;
    return(TRUE);
}
//--------------------------------------------------------------------------------------
static bool mini_cb(short action, void* data, LGadBox* vb)
{
    if (action != BUTTONGADG_LCLICK)
        return(FALSE);
    uiDefer(DeferOverlayToggle,(void *)kOverlayMiniMap);
    return(TRUE);
}
//--------------------------------------------------------------------------------------
static bool close_cb(short action, void* data, LGadBox* vb)
{
    if (action == BUTTONGADG_LCLICK)
    {
        uiDefer(DeferOverlayClose,(void *)kOverlayMap);
    }
    return(TRUE);
}
//--------------------------------------------------------------------------------------
static int key_handler_id;
static void BuildInterfaceButtons(void)
{
    Rect r = DPCOverlayGetRect(kOverlayMap);

    // set up the continue button
    close_elem.draw_type = DRAWTYPE_BITMAPOFFSET;
    close_elem.draw_data = close_bitmaps;
    close_elem.draw_data2 = (void *)4; // should be 2 but hackery required

    LGadCreateButtonArgs(&close_button, LGadCurrentRoot(), close_rect.ul.x + r.ul.x, close_rect.ul.y + r.ul.y,
                         RectWidth(&close_rect), RectHeight(&close_rect), &close_elem, close_cb, 0);

    // set up the minimap button
    mini_elem.draw_type = DRAWTYPE_BITMAPOFFSET;
    mini_elem.draw_data = mini_bitmaps;
    mini_elem.draw_data2 = (void *)4; // should be 2 but hackery required

    LGadCreateButtonArgs(&mini_button, LGadCurrentRoot(), mini_rect.ul.x + r.ul.x, mini_rect.ul.y + r.ul.y,
                         RectWidth(&mini_rect), RectHeight(&mini_rect), &mini_elem, mini_cb, 0);

    // grab keyboard focus
    uiInstallRegionHandler(LGadBoxRegion(VB(&close_button)),UI_EVENT_KBD_RAW,rawkey_handler_func,NULL,&key_handler_id);
    uiGrabFocus(LGadBoxRegion(VB(&close_button)), UI_EVENT_KBD_RAW);
}

//--------------------------------------------------------------------------------------
static void DestroyInterfaceButtons(void)
{
    uiReleaseFocus(LGadBoxRegion(VB(&close_button)), UI_EVENT_KBD_RAW);
    uiRemoveRegionHandler(LGadBoxRegion(VB(&close_button)),key_handler_id);

    LGadDestroyBox(VB(&close_button),FALSE);
    LGadDestroyBox(VB(&mini_button),FALSE);
}
//--------------------------------------------------------------------------------------
void DPCMapStateChange(int which)
{
    gSelectedObj = OBJ_NULL;
    if (DPCOverlayCheck(which))
    {
        char buf[255];
        // just got put up
        BuildInterfaceButtons();

        char lvl[255];
        DPCGetLevelName(lvl,sizeof(lvl));
        sprintf(buf,"intrface\\%s",lvl);
        gMapHnd = LoadPCX("page001",buf);
        gAutoMapHnd = LoadPCX("page001a",buf);
    }
    else
    {
        // just got taken down
        DestroyInterfaceButtons();
        SafeFreeHnd(&gMapHnd);
        SafeFreeHnd(&gAutoMapHnd);
    }
}
//--------------------------------------------------------------------------------------
static int map_obj_pos(ObjID o)
{
    cRoom* objroom = g_pRooms->GetObjRoom(o); 
    if (objroom)
    {
        ObjID room = objroom->GetObjID(); 

        int loc;
        if (room != OBJ_NULL && g_MapLocProperty->Get(room,&loc))
        {
            return(loc);
        }
    }

    return -1;
}
//--------------------------------------------------------------------------------------
// mpt is in decal coordinate frame, not screen coords
static int map_cursor_pos(Point mpt)
{
    // look through all the decals
    char lvl[255];
    char buf[255];
    DPCGetLevelName(lvl,sizeof(lvl));
    sprintf(buf,"%s/p001xa",lvl); 
    cRectArray tmpRects; 
    FetchUIRects(buf, tmpRects);

    int i;
    for (i=0; i < tmpRects.Size(); i++)
    {
        //dr = tmpRects[i]; 
        if (RectTestPt(&tmpRects[i],mpt))
        {
            return(i);
        }
    }
    return -1;
}
//--------------------------------------------------------------------------------------
void DPCMapSetExplored(int loc, char val)
{
    gExplored.explored[loc] = val;
}
//--------------------------------------------------------------------------------------
#define MM_X   (639 - 128)
#define MM_Y   0

#define INNERMAP_W 614
#define INNERMAP_H 260

// this is all kind of overkill at 1:1
#define MINIBIG_W 128
#define MINIBIG_H 128

#define MINI_W 128
#define MINI_H 128
static Rect minimap_rect = {{MM_X,MM_Y}, {MM_X + MINI_W, MM_Y + MINI_H}};

static IRes *gMinimapHnd;

void DPCMiniMapInit(int which)
{
    gMinimapHnd = LoadPCX("minimap");

    sScrnMode smode;
    Rect use_rect;
    ScrnModeGet(&smode);
    use_rect.ul.x = smode.w - (640 - minimap_rect.ul.x);
    use_rect.ul.y = minimap_rect.ul.y;
    use_rect.lr.x = use_rect.ul.x + RectWidth(&minimap_rect);
    use_rect.lr.y = use_rect.ul.y + RectHeight(&minimap_rect);

    DPCOverlaySetRect(which, use_rect);
    DPCOverlaySetFlags(which, kOverlayFlagBufferTranslucent);
}
//--------------------------------------------------------------------------------------
void DPCMiniMapTerm(void)
{
    SafeFreeHnd(&gMinimapHnd);
}
//--------------------------------------------------------------------------------------
static int gMapLoc = -1;
void DPCMiniMapDraw(unsigned long inDeltaTicks)
{
    Rect r = {{0,0},{MINI_W,MINI_H}}; // our actual final drawing rect size
    Rect r2 = {{0,0},{MINIBIG_W, MINIBIG_H}}; // our pre-scaled rect
    Point drawpt;
    int mx, my;
    int offset_x, offset_y, bw, bh;
    char buf[64];
    cRectArray tmpRects; 
    int maploc;
    char lvl[255];
    DPCGetLevelName(lvl,sizeof(lvl));

    AutoAppIPtr(DPCPlayer);

    // don't do anything except in freelook mode
    if (DPC_mouse)
        return;

    if (!DPCHasMap())
        return;

    maploc = map_obj_pos(PlayerObject()); 
    gMapLoc = maploc;
    sprintf(buf,"%s/p001ra",lvl); 
    FetchUIRects(buf, tmpRects);

    if (maploc >= 0 && maploc < tmpRects.Size())
    {
        /*
        mx = tmpRects[maploc].ul.x;
        my = tmpRects[maploc].ul.y;
        */
        Point mappt;
        FindObjectInMapCoords(PlayerObject(), &mappt, NULL);
        mx = mappt.x;
        my = mappt.y;

        // so we want to pretend to have a bigger cliprect
        // then gr_scale_bitmap ourselves down to draw our actual self

        grs_bitmap *bmp, *newbitmap;
        grs_canvas newcanv;

        bmp = (grs_bitmap *) gMinimapHnd->Lock();
        newbitmap = gr_alloc_bitmap(bmp->type,bmp->flags, MINIBIG_W, MINIBIG_H);
        newbitmap->align = bmp->align;
        gr_make_canvas(newbitmap, &newcanv);
        gr_push_canvas(&newcanv);

        grs_clip saveClip = grd_gc.clip;                 // Clip it good!

        gr_safe_set_cliprect(r2.ul.x, r2.ul.y, r2.lr.x, r2.lr.y) ;
        /*
        offset_x = ((RectWidth(&r2) - RectWidth(&tmpRects[maploc])) / 2);
        offset_y = ((RectHeight(&r2) - RectHeight(&tmpRects[maploc])) / 2);
        */
        offset_x = RectWidth(&r2) / 2;
        offset_y = RectHeight(&r2) / 2;

        drawpt.x = r2.ul.x - mx + offset_x; 
        drawpt.y = r2.ul.y - my + offset_y; 
        bw = INNERMAP_W;
        bh = INNERMAP_H; 
        // make sure we always draw a full portion
        if (drawpt.x > r2.ul.x)
            drawpt.x = r2.ul.x;
        if (drawpt.y > r2.ul.y)
            drawpt.y = r2.ul.y;
        if (drawpt.x < r2.lr.x - bw)
            drawpt.x = r2.lr.x - bw;
        if (drawpt.y < r2.lr.y - bh)
            drawpt.y = r2.lr.y - bh;
        if (pDPCPlayer->HasTrait(PlayerObject(),kTraitAutomap))
            DPCMapDrawContents(drawpt, gMiniAutoMapHnd, TRUE);
        else
            DPCMapDrawContents(drawpt, gMiniMapHnd, FALSE);

        // restore the old cliprect
        grd_gc.clip = saveClip;
        gr_pop_canvas();

        // now draw out our scaled bitmap
        gr_scale_bitmap(newbitmap, r.ul.x, r.ul.y, RectWidth(&r), RectHeight(&r));

        gr_free(newbitmap);
        gMinimapHnd->Unlock();
    }
}
//--------------------------------------------------------------------------------------
void DPCMiniMapStateChange(int which)
{
    gMapLoc = -1;
    if (DPCOverlayCheck(which))
    {
        char buf[256];

        // just got put up
        char lvl[255];
        DPCGetLevelName(lvl,sizeof(lvl));
        sprintf(buf,"intrface\\%s",lvl);
        gMiniMapHnd = LoadPCX("page001",buf);
        gMiniAutoMapHnd = LoadPCX("page001a",buf);
    }
    else
    {
        // just got taken down
        SafeFreeHnd(&gMiniMapHnd);
        SafeFreeHnd(&gMiniAutoMapHnd);
    }
}
//--------------------------------------------------------------------------------------
bool DPCMiniMapCheckTransp(Point pt)
{
    // always return true since it is effectively transparent
    return(TRUE);
}
//--------------------------------------------------------------------------------------
bool DPCHasMap()
{
    /*
    AutoAppIPtr(QuestData);
    char qbname[255];
    char lvl[255];
    DPCGetLevelName(lvl,sizeof(lvl));
 
    sprintf(qbname,"Map%s",lvl);
    if (pQuestData->Get(qbname))
       return(TRUE);
    else
       return(FALSE);
    */
    return(TRUE);
}
//--------------------------------------------------------------------------------------
IRes *DPCMiniMapBitmap(void)
{
    return(gMinimapHnd);
}
//--------------------------------------------------------------------------------------
bool DPCMiniMapUpdate(void)
{
    // do we need to be refreshed?
    /*
    int newmap = map_player_pos();
    if (newmap != gMapLoc)
       return(TRUE);
    return(FALSE);
    */
    return(TRUE);
}
//--------------------------------------------------------------------------------------
sOverlayFunc OverlayMap = 
{ 
    DPCMapDraw,               // draw
    DPCMapInit,               // init
    DPCMapTerm,               // term
    DPCMapHandleMouse,        // mouse
    NULL,                     // dclick (really use)
    NULL,                     // dragdrop
    NULL,                     // key
    NULL,                     // bitmap
    "subpanel_op",            // upschema
    "subpanel_cl",            // downschema
    DPCMapStateChange,        // state
    NULL,                     // transparency
    0,                        // distance
    TRUE,                     // needmouse
    0,                        // alpha
};

sOverlayFunc OverlayMiniMap = 
{ 
    DPCMiniMapDraw,           // draw
    DPCMiniMapInit,           // init
    DPCMiniMapTerm,           // term
    NULL,                     // mouse
    NULL,                     // dclick (really use)
    NULL,                     // dragdrop
    NULL,                     // key
    DPCMiniMapBitmap,         // bitMiniMap
    "",                       // upschema
    "",                       // downschema
    DPCMiniMapStateChange,    // state
    NULL,                     // transparency
    0,                        // distance
    FALSE,                    // needmouse
    200,                      // alpha
    DPCMiniMapUpdate,         // update
};
