/*
* - Movement Path menu tab
*/
#error "This file is not used at present, but might be in future"
#include <stdio.h>
#include "igui.hpp"
#include "../memory.hpp"
#include "../console.hpp"
#include "../core.hpp"
#include "../script.hpp"
#include "../init.hpp"
#include "../linklist.hpp"
#include "menusys.h"
// DEFINES
// VARIABLES
static int sel_xoff=0; // Offset from where we started the drag
static int sel_yoff=0; // so that the dragging is centered on that spot
// i.e. we drag it by the point we first clicked on
extern int lx_proj;
extern int focus,PA_Id; // GUI variables
static int CurPath=0;
extern int MapXpos_Id,MapYpos_Id; // Map X,Y coordinate boxes
extern char mapxstr[],mapystr[];
extern int mapx,mapy; // Current map position
extern SPRITE transfer; // 256x256 Transfer buffer for screen clipping
PATH_NODE *pathsel; // Path under scrutiny
static char ll_pos_str[]=" ";
static int listpos_Id;
static char mpt_str[]=" ";
static int mpt_Id;
static char beh_str[]=" ";
static int beh_Id;
// FUNCTIONS
extern void pause();
extern void Toolbar();
extern void DrawMap(int x,int y,char s_proj,char l_proj,char f_proj);
static void Nothing();
static void clipmap(); // Make sure coordinates are within bounds
void PA_up(); // Panning functions
void PA_down();
void PA_left();
void PA_right();
void PA_Create();
void PA_Edit();
void PA_Delete();
void PA_AddNode();
void PA_MoveNode();
void PA_DelNode();
void PA_Title();
void PA_Behave();
/*
void PA_1stNode();
void PA_NextNode();
void PA_PrevNode();
*/
static void SelectObj(int cx,int cy); // Do the actual picking up
static void PA_Update();
static void GetMapX(); // Get map position
static void GetMapY();
// Parts of the TL_Edit browser
void GetPAFromList( int x0, int y0, char *prompt, int listsize, char **list, char *name);
// CODE
/*
* GoFocal - The menu tab function. This is called from the toolbar
*/
void PA_GoFocal()
{
int temp; // Used to get button handles
if(focus==6) // Make sure we don't redraw if the user clicks again
return;
focus=6; // This is now the focus
Toolbar(); // Build up the menu system again from scratch
IG_SetFocus(PA_Id); // And make the button stick inwards
// Set up Map window
IG_BlackPanel(VIEWX-1,VIEWY-1,258,258);
IG_Region(VIEWX,VIEWY,256,256,PA_AddNode,NULL,PA_MoveNode);
// Write sprite drawing status
temp = IG_ToggleButton(486,72,"Rooftops OFF",Nothing,NULL,NULL,&lx_proj);
IG_SetInText(temp,"Rooftops ON ");
// Set up the X and Y map position counter at the top
MapXpos_Id = IG_InputButton(24,40,mapxstr,GetMapX,NULL,NULL);
MapYpos_Id = IG_InputButton(112,40,mapystr,GetMapY,NULL,NULL);
PA_Update();
IG_TextButton(416,104,__up,PA_up,NULL,NULL); // Pan up button
IG_TextButton(400,128,__left,PA_left,NULL,NULL); // Pan left button
IG_TextButton(432,128,__right,PA_right,NULL,NULL); // Pan right button
IG_TextButton(416,150,__down,PA_down,NULL,NULL); // Pan down button
IG_AddKey(UP_KEY,PA_up); // Pan up key binding
IG_AddKey(DN_KEY,PA_down); // Pan down key binding
IG_AddKey(LF_KEY,PA_left); // Pan left key binding
IG_AddKey(RT_KEY,PA_right); // Pan right key binding
// Create objects
IG_TextButton(300,256,"Create Movement Path",PA_Create,NULL,NULL);
// Modify objects
IG_TextButton(300,288,"Choose Movement Path",PA_Edit,NULL,NULL);
// Delete objects
IG_TextButton(300,320,"Delete Movement Path",PA_Delete,NULL,NULL);
DrawScreenText(64,348,"Movement path title:");
mpt_Id = IG_InputButton(64,364,mpt_str,PA_Title,NULL,NULL);
DrawScreenText(64,396,"Behaviour afterwards:");
beh_Id = IG_InputButton(64,412,beh_str,PA_Behave,NULL,NULL);
// Delete last point
IG_TextButton(300,370,"Remove last Point",PA_DelNode,NULL,NULL);
IG_AddKey(DEL,PA_DelNode);
}
/*
* Nothing - Just draw the map. Used by toggle-buttons
*/
void Nothing()
{
PA_Update();
return;
}
/*
* TL_up - Scroll upwards
*/
void PA_up()
{
mapy--;
clipmap();
PA_Update();
}
/*
* TL_down - Scroll downwards
*/
void PA_down()
{
mapy++;
clipmap();
PA_Update();
}
/*
* TL_left - Scroll to the left
*/
void PA_left()
{
mapx--;
clipmap();
PA_Update();
}
/*
* TL_right - Scroll to the right
*/
void PA_right()
{
mapx++;
clipmap();
PA_Update();
}
/*
* PA_AddNode - Add a single node to the current path
*/
void PA_AddNode()
{
int click_x,click_y;
if(!PAlist[CurPath])
return;
// First do a quick bounds check, to prevent the creation of sprites
// where the user can't actually see.
click_x = ((x-VIEWX)>>5); // Work out the position of the mouse
click_y = ((y-VIEWY)>>5); // in tiles
if(click_x<0 || click_y<0) // out the top/left of the screen?
return; // Yes, abort
if(click_x>VSW-1 || click_y>VSH-1) // Out the bottom/right of the screen?
return; // Yes, abort
// Now do the full calculation.
click_x = ((x-VIEWX)>>5)+(mapx); // click_x = (mouse_x_pos/32) + map_x_pos
click_y = ((y-VIEWY)>>5)+(mapy); // click_y = (mouse_y_pos/32) + map_y_pos
for(PATH_NODE *t=PAlist[CurPath]->path;t;t=t->next)
if(click_x == t->x)
if(click_y == t->y)
return;
pathsel = PL_Add(&PAlist[CurPath]->path);
if(!pathsel)
{
Notify(-1,-1,"Bugger",NULL);
return;
}
pathsel->x=click_x;
pathsel->y=click_y;
PA_Update();
}
/*
* PA_MoveNode - Move a single node around
*/
void PA_MoveNode()
{
int click_x,click_y;
if(!PAlist[CurPath])
return;
if(!pathsel)
return;
// First do a quick bounds check, to prevent the creation of sprites
// where the user can't actually see.
click_x = ((x-VIEWX)>>5); // Work out the position of the mouse
click_y = ((y-VIEWY)>>5); // in tiles
if(click_x<0 || click_y<0) // out the top/left of the screen?
return; // Yes, abort
if(click_x>VSW-1 || click_y>VSH-1) // Out the bottom/right of the screen?
return; // Yes, abort
// Now do the full calculation.
click_x = ((x-VIEWX)>>5)+(mapx); // click_x = (mouse_x_pos/32) + map_x_pos
click_y = ((y-VIEWY)>>5)+(mapy); // click_y = (mouse_y_pos/32) + map_y_pos
for(PATH_NODE *t=PAlist[CurPath]->path;t;t=t->next)
if(click_x == t->x)
if(click_y == t->y)
return;
pathsel->x=click_x;
pathsel->y=click_y;
PA_Update();
}
/*
* PA_DelNode - Delete last node
*/
void PA_DelNode()
{
PATH_NODE *tt;
pathsel = NULL;
if(!PAlist[CurPath])
return;
PL_Del(&PAlist[CurPath]->path);
for(tt=PAlist[CurPath]->path;tt;tt=tt->next) pathsel=tt;
PA_Update();
}
/*
* TL_Edit - Ask the user what an existing object should be like
* TL_SlowInsert calls this as well as the GUI.
* TL_Edit calls down to GetTLFromList to display the browser
*-/
void TL_Edit()
{
char **list;
char Name[32];
// Make sure we have an object
if(!laysel)
{
Notify(-1,-1,"No sprite has been selected.","You must pick a sprite before you can modify it.");
return;
}
// Make sure it's not a silly object
if(laysel==curmap.roof)
{
Notify(-1,-1,"Not permitted.",NULL);
return;
}
// Allocate a list of possible characters
list=(char **)M_get(SQtot+1,sizeof(char *));
// Set it up, convert to uppercase for Wyber's ordered selection routine
for(int ctr=0;ctr<SQtot;ctr++)
{
list[ctr]=SQlist[ctr].name;
strupr(list[ctr]); // Affects the original too
}
strcpy(Name,laysel->name); // Set up the default string
qsort(list,SQtot,sizeof(char*),CMP); // Sort them for the dialog box
// This is the graphical dialog box, taken from DEU.
GetTLFromList( -1,-1, "Choose a character:", SQtot-1, list, Name);
// If the user didn't press ESC instead of choosing, modify the character
if(Name[0]) // It's ok, do it
{
L_Init(laysel,Name); // Re-evaluate the character
strcpy(last_sprite,Name); // Keep this name for reference
}
free(list); // Dispose of the list
PA_Update();
}
/*
* TL_Delete - Remove an object
*-/
void TL_Delete()
{
if(!laysel)
{
Notify(-1,-1,"No sprite has been selected.","You must pick a sprite before you can delete it.");
return;
}
if(laysel==curmap.roof) // This can't happen
{
Notify(-1,-1,"Not Permitted",NULL); // Get shirty
return;
}
L_Free(laysel); // Destroy the object
laysel=NULL; // Nothing currently selected
PA_Update();
sel_xoff = 0; // If we drag and drop, no grab offset
sel_yoff = 0;
}
/*
* TL_Pick - Drag and drop an object. This calls down to SelectObj();
*-/
void TL_Pick()
{
int click_x,click_y;
click_x = ((x-VIEWX)>>5)+(mapx); // click_x = (mouse_x_pos/32) + map_x_pos
click_y = ((y-VIEWY)>>5)+(mapy); // click_y = (mouse_y_pos/32) + map_y_pos
if(dragflag) // If we're dragging an object
{
if(!laysel)
{
Notify(-1,-1,"Internal error in drag'n'drop code",NULL);
return;
}
laysel->x=click_x + sel_xoff; // Get clicked position
laysel->y=click_y + sel_yoff; // And move object to that place.
if(laysel->x<0) laysel->x=0; // Sanity checks.
if(laysel->y<0) laysel->y=0;
dragflag=2; // Reset drag timer
}
else // If we're not dragging, or time out
{
SelectObj(click_x,click_y); // Go fish
if(laysel) // If an object was selected
{
dragflag=2; // We go into drag mode
strcpy(last_sprite,laysel->name); // We'll make more of these
}
}
PA_Update();
}
/*
* TL_MoveThere - Move an object to the current square without dragging it
*-/
void TL_MoveThere()
{
int click_x,click_y;
click_x = ((x-VIEWX)>>5)+(mapx); // click_x = (mouse_x_pos/32) + map_x_pos
click_y = ((y-VIEWY)>>5)+(mapy); // click_y = (mouse_y_pos/32) + map_y_pos
if(laysel)
{
laysel->x=click_x + sel_xoff; // Get clicked position
laysel->y=click_y + sel_yoff; // And move object to that place.
if(laysel->x<0) laysel->x=0; // Sanity checks.
if(laysel->y<0) laysel->y=0;
PA_Update();
}
}
/*
* TL_GotoFirst - Move to the first object in the list
*-/
void TL_GotoFirst()
{
if(!curmap.roof->next) // No objects? Can't do it
return;
laysel=curmap.roof->next; // Select the first one.
mapx=laysel->x-(VSW/2); // center the object in the view
mapy=laysel->y-(VSH/2);
clipmap(); // Clip the view to sensible bounds
PA_Update();
}
/*
* TL_GotoNext - Move to the next object in the list
*-/
void TL_GotoNext()
{
if(!laysel) // Abort if no object selected
return;
if(!laysel->next) // Abort if no object follows
return;
laysel=laysel->next; // Go to the next one
mapx=laysel->x-(VSW/2); // center the object in the view
mapy=laysel->y-(VSH/2);
clipmap(); // Clip the view to sensible bounds
PA_Update();
pause();
}
/* =========================== Auxiliary functions ======================== */
/*
* SelectObj - fish for an object on the map where the user has clicked
*-/
void SelectObj(int cx,int cy)
{
laysel = NULL; // Assume nothing was there
sel_xoff = 0; // No select offset
sel_yoff = 0;
for(LAYER *ttemp=curmap.roof;ttemp;ttemp=ttemp->next)
if(cx>=ttemp->x && cx<ttemp->x+ttemp->mw)
if(cy>=ttemp->y && cy<ttemp->y+ttemp->mh)
{
laysel=ttemp;
sel_xoff = (ttemp->x - cx); // If we grab it by
sel_yoff = (ttemp->y - cy); // the ear, record
} // where the ear was
// If laysel == NULL then we caught a fish
// Time to go
return;
}
/*
* PA_Update - Draw map and display nodes
*/
void PA_Update()
{
char temp[13];
int tot=1,pos;
int a,b,oa,ob;
PATH_NODE *tt;
DrawMap(mapx,mapy,1,lx_proj,0);
strcpy(mpt_str,"- ");
strcpy(beh_str,"- ");
if(!PAlist[CurPath])
return;
strcpy(mpt_str,PAlist[CurPath]->name);
strcpy(beh_str,PAlist[CurPath]->func);
IG_UpdateText(mpt_Id,mpt_str);
IG_UpdateText(beh_Id,beh_str);
if(!PAlist[CurPath]->path) // Abort, because no node was chosen
return;
tot = 0;
// Plot the control points onscreen
for(tt=PAlist[CurPath]->path;tt;tt=tt->next,tot++)
if(tt->x >= mapx && tt->x < (mapx+(VSW)))
if(tt->y >= mapy && tt->y < (mapy+(VSH)))
{
a = ((tt->x-mapx)<<5)+VIEWX;
b = ((tt->y-mapy)<<5)+VIEWY;
box(a,b,a+31,b+31,RED,swapscreen);
itoa(tot,temp,10);
C_printxy(a,b,temp);
if(pathsel == tt)
box(a,b,a+31,b+31,WHITE,swapscreen);
}
// Join the points
for(tt=PAlist[CurPath]->path;tt->next;tt=tt->next)
{
a = tt->x-mapx;
b = tt->y-mapy;
oa = tt->next->x-mapx;
ob = tt->next->y-mapy;
a=(a<<5)+16+VIEWX;
b=(b<<5)+16+VIEWY;
oa=(oa<<5)+16+VIEWX;
ob=(ob<<5)+16+VIEWY;
if(a<VIEWX)
a=VIEWX;
if(a>(VIEWX+256))
a=VIEWX+256;
if(oa<VIEWX)
oa=VIEWX;
if(oa>(VIEWX+256))
oa=VIEWX+256;
if(b<VIEWY)
b=VIEWY;
if(b>(VIEWY+256))
b=VIEWY+256;
if(ob<VIEWY)
ob=VIEWY;
if(ob>(VIEWY+256))
ob=VIEWY+256;
ITGline(a,b,oa,ob,WHITE,swapscreen);
}
}
/*
* clipmap - clip the map's coordinates to sensible values
*/
void clipmap()
{
if(mapx<0) mapx=0;
if(mapx>curmap.w-VSW) mapx=curmap.w-VSW;
if(mapy>curmap.h-VSH) mapy=curmap.h-VSH;
if(mapy<0) mapy=0;
}
void PA_Create()
{
for(int ctr=0;ctr<MAX_PATHS;ctr++)
if(!PAlist[ctr])
{
CurPath=ctr;
PAlist[ctr] = M_get(1,sizeof(PATHLIST));
PAlist[ctr]->path=NULL;
sprintf(PAlist[ctr]->name,"PATH_%d",ctr);
InputString(-1,-1,"Enter a description of the path:",16,PAlist[ctr]->name);
PA_Update();
return;
}
}
void PA_Edit()
{
char **list;
char Name[32];
int tot,cur,ctr;
tot=0;
for(ctr=0;ctr<MAX_PATHS;ctr++)
if(PAlist[ctr])
tot++;
if(!tot)
{
Notify(-1,-1,"No Movement Paths have been created yet.",NULL);
return;
}
list=(char **)M_get(tot,sizeof(char *));
// Set it up, convert to uppercase for Wyber's ordered selection routine
cur=0;
for(ctr=0;ctr<MAX_PATHS;ctr++)
if(PAlist[ctr])
{
list[cur]=PAlist[ctr]->name;
strupr(list[cur++]); // Affects the original too
}
if(PAlist[CurPath])
strcpy(Name,PAlist[CurPath]->name); // Set up the default string
else
strcpy(Name,list[0]);
qsort(list,tot,sizeof(char*),CMP); // Sort them for the dialog box
// This is the graphical dialog box, taken from DEU.
InputNameFromList( -1,-1, "Choose a Movement Path:", tot-1, list, Name);
// If the user didn't press ESC instead of choosing, modify the character
if(Name[0]) // It's ok, do it
for(ctr=0;ctr<MAX_PATHS;ctr++)
if(PAlist[ctr])
if(!stricmp(PAlist[ctr]->name,Name))
CurPath=ctr;
free(list); // Dispose of the list
PA_Update();
}
void PA_Delete()
{
if(!PAlist[CurPath])
return;
if(!Notify(-1,-1,"Really delete this movement path?",NULL))
return;
// Delete until deleted
for(;PL_Del(&PAlist[CurPath]->path););
M_free(PAlist[CurPath]);
PAlist[CurPath]=NULL;
}
void PA_Title()
{
if(!PAlist[CurPath])
return;
InputString(-1,-1,"Enter a description of the path:",16,PAlist[CurPath]->name);
PA_Update();
}
void PA_Behave()
{
char **list;
char Name[32];
if(!PAlist[CurPath])
return;
list=(char **)M_get(COtot+1,sizeof(char *));
// Set it up, convert to uppercase for Wyber's ordered selection routine
list[0]="-";
for(int ctr=0;ctr<COtot;ctr++)
{
list[ctr+1]=COlist[ctr].name;
strupr(list[ctr]); // Affects the original too
}
strcpy(Name,PAlist[CurPath]->func); // Set up the default string
qsort(list,COtot,sizeof(char*),CMP); // Sort them for the dialog box
// This is the graphical dialog box, taken from DEU.
InputNameFromList( -1,-1, "Choose a function to call when finished:", COtot, list, Name);
// If the user didn't press ESC instead of choosing, modify the character
if(Name[0]) // It's ok, do it
strcpy(PAlist[CurPath]->func,Name);
free(list); // Dispose of the list
PA_Update();
}
/*
* GetPAFromList - Show the list of paths
*/
void GetPAFromList( int x0, int y0, char *prompt, int listsize, char **list, char *name)
{
//InputNameFromListWithFunc( x0, y0, prompt, listsize, list, 5, name, 257, 257, TL_Thumb);
}
/*
* GetMapX - Ask the user where on the map they want to be
*/
void GetMapX()
{
mapx=InputIntegerValue(-1,-1,0,curmap.w-VSW,mapx);
DrawMap(mapx,mapy,1,lx_proj,0);
}
/*
* GetMapY - Ask the user where on the map they want to be
*/
void GetMapY()
{
mapy=InputIntegerValue(-1,-1,0,curmap.h-VSH,mapy);
DrawMap(mapx,mapy,1,lx_proj,0);
}