diff options
Diffstat (limited to 'editline.c')
-rw-r--r-- | editline.c | 3361 |
1 files changed, 3361 insertions, 0 deletions
diff --git a/editline.c b/editline.c new file mode 100644 index 0000000..6ec521e --- /dev/null +++ b/editline.c @@ -0,0 +1,3361 @@ +/* + + viDOOM - level editor for DOOM + + Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) + + This program 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. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Editor LINEDEF definitions + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "globals.h" + +#include <math.h> +#include <ctype.h> + +#include "editvar.h" +#include "sectors.h" +#include "texture.h" +#include "util.h" + + +/* ---------------------------------------- MACROS +*/ +#define LinesCrossV(v1,v2,v3,v4) \ + LinesCross ((v1)->v.x,(v1)->v.y,(v2)->v.x,(v2)->v.y, \ + (v3)->v.x,(v3)->v.y,(v4)->v.x,(v4)->v.y) + +#define SetPoint(pt,vt) do {(pt).x=(vt)->v.x;(pt).y=(vt)->v.y;} while(0) + +#define SPLINE_THRESH 1 + +/* This following define relies on the naming of parameters in DoCalcSpline() + and DoCalcLine() +*/ +#define CHECKSTEP(X,Y) do { \ + (*len)++; \ + \ + if (p) \ + if (((*len)%step)==0) \ + { \ + if ((*idx)<MAX_STEPS) \ + { \ + p[*idx].x=X; \ + p[*idx].y=Y; \ + (*idx)++; \ + } \ + } \ + } while(0) + +/* ---------------------------------------- STEP CREATION SHARED DATA +*/ +#define MIN_STEPS 1 +#define MAX_STEPS 128 + +struct { + int x; + int y; + + EditLine *from; + EditLine *to; + int from_c; + int to_c; + int from_f; + int to_f; + + int swap; + Point vf[2]; + Point vt[2]; + + int no; + double step_f; + double step_c; + int circular; + int side; + + Point p[2][MAX_STEPS+2]; + } step; + + +/* ---------------------------------------- PRIVATE UTILS +*/ +static void DrawLinedef(EditLine *l, int col) +{ + double dx,dy; + + TRACE; + + dx=((l->v[0]->v.x)-(l->v[1]->v.x))/2; + dy=((l->v[0]->v.y)-(l->v[1]->v.y))/2; + + MapLineD(l,col); + + MapLine((int)(l->v[0]->v.x-dx),(int)(l->v[0]->v.y-dy), + (int)(l->v[0]->v.x-dx-dy/6),(int)(l->v[0]->v.y-dy+dx/6),col); +} + + +static int SelColour(int selmode) +{ + switch(selmode) + { + case SELECT_OVER: + return(OVERCOL); + break; + case SELECT_SELECTED: + return(SELCOL); + break; + default: + if (edit_mode==SECTOR_MODE) + return(SECTCOL); + else + return(LINECOL); + break; + } +} + + +static void RemoveHighlights(List l) +{ + Iterator i; + Object *o; + int *n; + + i=ListIterator(l); + + while(i) + { + n=IteratorData(i); + + if ((o=MapElem(linedef,*n))) + DrawLinedef(o->data,SelColour(o->select)); + + i=IteratorNext(i); + } +} + + +static void LineSelectionCentre(int *x,int *y) +{ + int *f; + EditLine *l; + Iterator i; + int min_x,min_y,max_x,max_y; + + TRACE; + + i=ListIterator(selected); + + min_x=99999; + min_y=99999; + max_x=-99999; + max_y=-99999; + + while(i) + { + f=IteratorData(i); + l=GETLINE(*f); + + min_x=MIN(l->min_x,min_x); + min_y=MIN(l->min_y,min_y); + max_x=MAX(l->max_x,max_x); + max_y=MAX(l->max_y,max_y); + + i=IteratorNext(i); + } + + *x=min_x+(max_x-min_x)/2; + *y=min_y+(max_y-min_y)/2; +} + + +static void DeleteLeftSidedef(EditLine *l) +{ + Object *o; + int n; + int del; + int side; + EditLine *cl; + + TRACE; + + if (l->l.left==-1) + return; + + l->sl=NULL; + side=l->l.left; + l->l.left=-1; + + /* Free up the sidedef if there is no other linedef + bound to it + */ + del=TRUE; + + for(n=0;(n<MapSize(linedef))&&(del);n++) + { + cl=GETLINE(n); + + if ((cl)&&((cl->l.left==side)||(cl->l.right==side))) + del=FALSE; + } + + if (del) + { + o=MapElem(sidedef,side); + Release(o->data); + o->data=NULL; + } +} + + +static void DeleteRightSidedef(EditLine *l) +{ + Object *o; + int n; + int del; + int side; + EditLine *cl; + + TRACE; + + if (l->l.right==-1) + return; + + l->sr=NULL; + side=l->l.right; + l->l.right=-1; + + /* Free up the sidedef if there is no other linedef + bound to it + */ + del=TRUE; + + for(n=0;(n<MapSize(linedef))&&(del);n++) + { + cl=GETLINE(n); + + if ((cl)&&((cl->l.left==side)||(cl->l.right==side))) + del=FALSE; + } + + if (del) + { + o=MapElem(sidedef,side); + Release(o->data); + o->data=NULL; + } +} + + +static void DeleteLinedef(int f) +{ + Object *o; + EditLine *l; + + TRACE; + + o=MapElem(linedef,f); + l=o->data; + DeleteLeftSidedef(l); + DeleteRightSidedef(l); + + IntListRm(l->v[0]->l,f); + IntListRm(l->v[1]->l,f); + + Release(o->data); + o->data=NULL; + o->select=SELECT_NONE; +} + + +static int SplitLinedef(int f) +{ + Object o; + EditLine *l,*nl; + Sidedef *nsl,*nsr; + EditVert *nv; + int n_nl,dx,dy,tw; + + TRACE; + + l=GETLINE(f); + + o.select=SELECT_NONE; + + /* Create copies of the original linedefs and sidedefs + */ + nl=Grab(sizeof(EditLine)); + memcpy(nl,l,sizeof(EditLine)); + o.data=nl; + n_nl=MapSize(linedef); + nl->no=n_nl; + MapAdd(linedef,n_nl,&o); + + nsr=Grab(sizeof(Sidedef)); + memcpy(nsr,l->sr,sizeof(Sidedef)); + o.data=nsr; + nl->l.right=MapSize(sidedef); + MapAdd(sidedef,nl->l.right,&o); + nl->sr=GETSIDE(nl->l.right); + + if (l->l.left!=-1) + { + nsl=Grab(sizeof(Sidedef)); + memcpy(nsl,l->sl,sizeof(Sidedef)); + o.data=nsl; + nl->l.left=MapSize(sidedef); + MapAdd(sidedef,nl->l.left,&o); + nl->sl=GETSIDE(nl->l.left); + } + else + nsl=NULL; + + /* Work out the middle of the current line and create the vertex there + */ + nv=Grab(sizeof(EditVert)); + nv->l=ListNew(sizeof(int)); + + dx=((l->v[1]->v.x)-(l->v[0]->v.x))/2; + dy=((l->v[1]->v.y)-(l->v[0]->v.y))/2; + + nv->v.x=l->v[0]->v.x+dx; + nv->v.y=l->v[0]->v.y+dy; + o.data=nv; + + /* Update the vertex map, and the from/to in the old/new linedefs + */ + nl->l.from=MapSize(vertex); + MapAdd(vertex,nl->l.from,&o); + + l->l.to=nl->l.from; + + l->v[1]=GETVERT(l->l.to); + nl->v[0]=GETVERT(nl->l.from); + + /* Update the vertex lists + */ + IntListRm(nl->v[1]->l,f); + IntListUniqAdd(nl->v[0]->l,f); + IntListUniqAdd(nl->v[0]->l,n_nl); + + /* Align textures + */ + tw=CalcTextureWidth(nsr->upper,nsr->middle,nsr->lower); + + if (tw) + nsr->x=(l->sr->x+Len(l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y))%tw; + else + nsr->x=0; + + if (nsl) + { + tw=CalcTextureWidth(nsl->upper,nsl->middle,nsl->lower); + if (tw) + nsl->x=(l->sl->x+Len(l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y))%tw; + else + nsl->x=0; + } + + /* New linedef no + */ + return(n_nl); +} + + +/* ---------------------------------------- STEP CREATION CODE CALCULATIONS +*/ +static void DoCalcLine (int x0,int y0,int x1,int y1, + Point p[],int step,int *idx,int *len) +{ + int dx,dy,ix,iy,incre,incrne,d,x,y,ymode; + int p1x,p1y,p2x,p2y; + + TRACE; + + p1x=x0; + p1y=y0; + p2x=x1; + p2y=y1; + + dx=p2x-p1x; + dy=p2y-p1y; + + ix=SGN(dx); + iy=SGN(dy); + + dx=ABS(dx); + dy=ABS(dy); + + if (dy>dx) + { + ymode=TRUE; + d=dx*2-dy; + incre=dx*2; + incrne=(dx-dy)*2; + } + else + { + ymode=FALSE; + d=dy*2-dx; + incre=dy*2; + incrne=(dy-dx)*2; + } + + x=p1x; + y=p1y; + + CHECKSTEP(x,y); + + if (ymode) + while(y!=p2y) + { + if (d<=0) + { + d+=incre; + y+=iy; + } + else + { + d+=incrne; + y+=iy; + x+=ix; + } + + CHECKSTEP(x,y); + } + else + while(x!=p2x) + { + if (d<=0) + { + d+=incre; + x+=ix; + } + else + { + d+=incrne; + y+=iy; + x+=ix; + } + + CHECKSTEP(x,y); + } +} + + +static void DoCalcSpline (int x0,int y0,int x1,int y1,int x2,int y2, + Point p[],int step,int *idx,int *len) +{ + int xa, ya, xb, yb, xc, yc, xp, yp; + + TRACE; + + if ((x0==x1==x2)&&(y0==y1==y2)) + { + CHECKSTEP(x0,y0); + return; + } + + if ((x0==x1)&&(y0==y1)) + { + if (p) + DoCalcLine(x1,y1,x2,y2,p,step,idx,len); + else + *len+=Len(x1,y1,x2,y2); + return; + } + + if ((x0==x2)&&(y0==y2)) + { + if (p) + DoCalcLine(x0,y0,x1,y1,p,step,idx,len); + else + *len+=Len(x0,y0,x1,y1); + return; + } + + if ((x1==x2)&&(y1==y2)) + { + if (p) + DoCalcLine(x0,y0,x2,y2,p,step,idx,len); + else + *len+=Len(x0,y0,x2,y2); + return; + } + + xa = ( x0 + x1 ) / 2; + ya = ( y0 + y1 ) / 2; + xc = ( x1 + x2 ) / 2; + yc = ( y1 + y2 ) / 2; + xb = ( xa + xc ) / 2; + yb = ( ya + yc ) / 2; + + xp = ( x0 + xb ) / 2; + yp = ( y0 + yb ) / 2; + + if ( ABS( xa - xp ) + ABS( ya - yp ) > SPLINE_THRESH ) + DoCalcSpline(x0,y0,xa,ya,xb,yb,p,step,idx,len); + else + if (p) + DoCalcLine(x0,y0,xb,yb,p,step,idx,len); + else + *len+=Len(x0,y0,xb,yb); + + xp = ( x2 + xb ) / 2; + yp = ( y2 + yb ) / 2; + if ( ABS( xc - xp ) + ABS( yc - yp ) > SPLINE_THRESH ) + DoCalcSpline(xb,yb,xc,yc,x2,y2,p,step,idx,len); + else + if (p) + DoCalcLine(xb,yb,x2,y2,p,step,idx,len); + else + *len+=Len(xb,yb,x2,y2); +} + + +static void Spline(int x0,int y0, int x1, int y1, int x2, int y2, + Point p[],int step) +{ + int len; + int idx; + + TRACE; + + len=0; + idx=0; + DoCalcSpline(x0,y0,x1,y1,x2,y2,p,step,&idx,&len); +} + + +static int SplineLen(int x0,int y0, int x1, int y1, int x2, int y2) +{ + int len; + + TRACE; + + len=0; + DoCalcSpline(x0,y0,x1,y1,x2,y2,NULL,0,NULL,&len); + return (len); +} + + +static void CalcSteps(void) +{ + double dx,dy; + int f,r; + int len; + + TRACE; + + step.step_f=((double)step.to_f-step.from_f)/(step.no+2); + step.step_c=((double)step.to_c-step.from_c)/(step.no+2); + + if (step.circular) + { + f=step.side; + + len=SplineLen(step.vf[f].x,step.vf[f].y,step.x,step.y, + step.vt[f].x,step.vt[f].y); + + len=(int)((double)len/((double)step.no+1.0)+1.0); + + if (len<1) + len=1; + + Spline(step.vf[f].x,step.vf[f].y,step.x,step.y, + step.vt[f].x,step.vt[f].y,&step.p[f][1],len); + + step.p[f][0].x=step.vf[f].x; + step.p[f][0].y=step.vf[f].y; + + step.p[f][step.no+1].x=step.vt[f].x; + step.p[f][step.no+1].y=step.vt[f].y; + } + else + for(f=0;f<2;f++) + { + dx=(double)(step.vt[f].x-step.vf[f].x)/(step.no+1); + dy=(double)(step.vt[f].y-step.vf[f].y)/(step.no+1); + + for(r=1;r<=step.no;r++) + { + step.p[f][r].x=(int)(step.vf[f].x+(dx*r)); + step.p[f][r].y=(int)(step.vf[f].y+(dy*r)); + } + + step.p[f][0].x=step.vf[f].x; + step.p[f][0].y=step.vf[f].y; + + step.p[f][step.no+1].x=step.vt[f].x; + step.p[f][step.no+1].y=step.vt[f].y; + } +} + + +int SectorInBox(Point tl, Point br) +{ + int x,y; + + x=tl.x+(br.x-tl.x)/2; + y=tl.y+(br.y-tl.y)/2; + + return (SectorHoldingPoint(x,y)); +} + + +/* ---------------------------------------- STEP CREATION CALLBACKS +*/ +static void PickDraw(int *x, int *y) +{ + int f; + + TRACE; + + step.x=*x; + step.y=*y; + + if (step.circular) + CalcSteps(); + + for(f=0;f<2;f++) + MapLine(step.p[f][0].x,step.p[f][0].y, + step.p[f][1].x,step.p[f][1].y,LINECOL); + + for(f=1;f<=step.no;f++) + { + MapLine(step.p[0][f].x,step.p[0][f].y, + step.p[1][f].x,step.p[1][f].y,LINECOL); + + MapLine(step.p[0][f].x,step.p[0][f].y, + step.p[0][f+1].x,step.p[0][f+1].y,LINECOL); + + MapLine(step.p[1][f].x,step.p[1][f].y, + step.p[1][f+1].x,step.p[1][f+1].y,LINECOL); + } +} + + +static void PickKey(GFXKey k) +{ + TRACE; + + if (k.code==GFX_ASCII) + switch(toupper(k.ascii)) + { + case 'C': + step.circular=!step.circular; + CalcSteps(); + break; + + case 'S': + step.side^=1; + CalcSteps(); + break; + + case 'R': + step.swap=!step.swap; + + if (!step.swap) + { + SetPoint(step.vf[0],step.from->v[0]); + SetPoint(step.vf[1],step.from->v[1]); + SetPoint(step.vt[0],step.to->v[0]); + SetPoint(step.vt[1],step.to->v[1]); + } + else + { + SetPoint(step.vf[0],step.from->v[0]); + SetPoint(step.vf[1],step.from->v[1]); + SetPoint(step.vt[0],step.to->v[1]); + SetPoint(step.vt[1],step.to->v[0]); + } + + CalcSteps(); + + if (step.circular) + { + step.side^=1; + CalcSteps(); + step.side^=1; + } + + break; + + case '+': + if (step.no<MAX_STEPS) + { + step.no++; + CalcSteps(); + + if (step.circular) + { + step.side^=1; + CalcSteps(); + step.side^=1; + } + } + break; + + case '-': + if (step.no>MIN_STEPS) + { + step.no--; + CalcSteps(); + + if (step.circular) + { + step.side^=1; + CalcSteps(); + step.side^=1; + } + } + break; + } +} + + +static void PickInfo(char *p) +{ + TRACE; + + GuiDrawInfoBox(p,GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE, + "No : %d|" + "Step (F) : %d|" + "Step (C) : %d|" + "Mode : %-s|" + "Side : %d", + step.no,ABS((int)step.step_f),ABS((int)step.step_c), + step.circular ? "Curve " : "Straight", + step.side); + + GuiDrawInfoBox(p,GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "+ - increase number of steps|" + "- - decrease number of steps|" + "C - change between straight/curve|" + "S - change wall being moved in curve mode|" + "R - swap vertex matching|" + " |" + "Press left button to complete. ESC to cancel"); +} + + +/* ---------------------------------------- STEP CREATION CODE +*/ +typedef struct + { + int line; + int apply; + } TextureMatch; + +static void ApplyTextureOffset(List li,int tw,int right) +{ + int off; + Iterator i; + TextureMatch *tm; + EditLine *l; + Sidedef *s; + + TRACE; + + i=ListIterator(li); + off=0; + + while(i) + { + tm=IteratorData(i); + + l=GETLINE(tm->line); + + if (tm->apply) + { + if (right) + s=l->sr; + else + s=l->sl; + + s->x=off; + } + + off=(off+Len(l->v[0]->v.x,l->v[0]->v.y,l->v[1]->v.x,l->v[1]->v.y))%tw; + + i=IteratorNext(i); + } +} + + +static int CreateSteps(int i_from, int i_to) +{ + EditSect *s; + EditLine *from,*to; + DirName upper,lower,middle,floor,ceiling; + int s_flag; + int type; + + TRACE; + + from=GETLINE(i_from); + to=GETLINE(i_to); + + if ((Len(from->v[0]->v.x,from->v[0]->v.y, + from->v[1]->v.x,from->v[1]->v.y)==0)|| + (Len(to->v[0]->v.x,to->v[0]->v.y,to->v[1]->v.x,to->v[1]->v.y)==0)) + { + GuiInfoBox("ERROR","Lines must be non-zero length"); + return(FALSE); + } + + if (((from->l.from==to->l.from)&&(to->l.to==to->l.to))|| + ((from->l.from==to->l.to)&&(to->l.to==to->l.from))) + { + GuiInfoBox("ERROR","Lines cannot share a vertex"); + return(FALSE); + } + + if (!(LinesCrossV(from->v[0],to->v[0],from->v[1],to->v[1]))) + { + step.swap=FALSE; + SetPoint(step.vf[0],from->v[0]); + SetPoint(step.vf[1],from->v[1]); + SetPoint(step.vt[0],to->v[0]); + SetPoint(step.vt[1],to->v[1]); + } + else + { + step.swap=TRUE; + SetPoint(step.vf[0],from->v[0]); + SetPoint(step.vf[1],from->v[1]); + SetPoint(step.vt[0],to->v[1]); + SetPoint(step.vt[1],to->v[0]); + } + + step.x=ms.x; + step.y=ms.y; + step.from=from; + step.to=to; + step.no=1; + step.circular=FALSE; + step.side=0; + + s=GETSECT(from->sr->sector); + step.from_c=s->s.ceiling; + step.from_f=s->s.floor; + + s=GETSECT(to->sr->sector); + step.to_c=s->s.ceiling; + step.to_f=s->s.floor; + + CalcSteps(); + + if ((PickPoint("Create steps",&step.x,&step.y,PickDraw,PickKey,PickInfo))&& + (ChooseSectorStyle(&s_flag,upper,middle,lower,floor,ceiling))&& + ((type=SelectSector())!=SECTOR_NULLID)) + { + Object o; + EditLine *el; + EditVert *ev[2][MAX_STEPS+2]; + EditSect *s; + Sidedef *ns; + TextureMatch tm; + List side_sl[2],side_sr[2]; + int n; + int v[2][MAX_STEPS+2]; + int do_ceiling; + double fh,ch; + int prev_fh,prev_ch; + int in_sect[MAX_STEPS],sect,prev_sect; + int nl,flags; + int offy_c,offy_f,tw,th; + int f,r; + + /* Create lists for mainting lines for afterward texture alignment + */ + for(f=0;f<2;f++) + { + side_sl[f]=ListNew(sizeof(TextureMatch)); + side_sr[f]=ListNew(sizeof(TextureMatch)); + } + + if ((do_ceiling=GUI_yesno("Move ceiling with steps?"))) + ch=step.from_c+step.step_c; + else + ch=MAX(step.to_c,step.from_c); + + fh=step.from_f+step.step_f; + + tw=CalcTextureWidth(upper,middle,lower); + + TextureSize(middle,NULL,&th); + + /* Create/get all the vertexes needed + */ + for(f=0;f<=step.no+1;f++) + { + if (f==0) + { + v[0][f]=step.from->l.from; + v[1][f]=step.from->l.to; + ev[0][f]=step.from->v[0]; + ev[1][f]=step.from->v[1]; + } + else if (f==step.no+1) + { + if (step.swap) + { + v[1][f]=step.to->l.from; + v[0][f]=step.to->l.to; + ev[1][f]=step.to->v[0]; + ev[0][f]=step.to->v[1]; + } + else + { + v[0][f]=step.to->l.from; + v[1][f]=step.to->l.to; + ev[0][f]=step.to->v[0]; + ev[1][f]=step.to->v[1]; + } + } + else + for(r=0;r<2;r++) + { + ev[r][f]=Grab(sizeof(EditVert)); + ev[r][f]->v.x=step.p[r][f].x; + ev[r][f]->v.y=step.p[r][f].y; + ev[r][f]->l=ListNew(sizeof(int)); + + o.data=ev[r][f]; + o.select=SELECT_NONE; + v[r][f]=MapSize(vertex); + MapAdd(vertex,-1,&o); + } + + /* While we're here, get all the containing sectors too + */ + in_sect[f]=SectorInBox(step.p[0][f],step.p[1][f+1]); + } + + /* Delete current left sidedefs on the anchor lines + */ + if (step.from->l.left!=-1) + DeleteLeftSidedef(step.from); + + if (step.to->l.left!=-1) + DeleteLeftSidedef(step.to); + + /* Set up the flags for the 1st line and all the previous sector and + height vars + */ + prev_fh=step.from_f; + prev_ch=step.from_c; + prev_sect=step.from->sr->sector; + offy_c=0; + offy_f=0; + + /* Create the steps up to the last one + */ + for(f=0;f<=step.no;f++) + { + if (in_sect[f]!=-1) + s=GETSECT(in_sect[f]); + else + s=NULL; + + sect=CreateUnboundSector + (type,(int)fh,(int)ch,default_light_level,0,floor,ceiling); + + /* Create the linedef at the start of the step. For the 1st step + we adjust the original linedef. Otherwise create a new one + */ + if (!f) + { + el=step.from; + el->l.flags|=side2_mask; + el->l.flags&=~block_mask; + + ns=Grab(sizeof(Sidedef)); + ns->x=0; + ns->y=0; + + el->l.flags|=upper_peg_mask; + el->l.flags&=~lower_peg_mask; + + if (prev_ch>(int)ch) + { + strcpy(el->sr->upper,upper); + strcpy(ns->upper,empty_texture); + } + else if (prev_ch<(int)ch) + { + strcpy(el->sr->upper,empty_texture); + strcpy(ns->upper,upper); + } + else + { + strcpy(el->sr->upper,empty_texture); + strcpy(ns->upper,empty_texture); + } + + if (prev_fh<(int)fh) + { + strcpy(el->sr->lower,lower); + strcpy(ns->lower,empty_texture); + } + else if (prev_fh>(int)fh) + { + strcpy(el->sr->lower,empty_texture); + strcpy(ns->lower,lower); + } + else + { + strcpy(el->sr->lower,empty_texture); + strcpy(ns->lower,empty_texture); + } + + strcpy(el->sr->middle,empty_texture); + strcpy(ns->middle,empty_texture); + + ns->sector=sect; + + o.data=ns; + o.select=SELECT_NONE; + + n=MapSize(sidedef); + MapAdd(sidedef,n,&o); + el->sl=ns; + el->l.left=n; + } + else + { + flags=side2_mask|upper_peg_mask; + + nl=CreateNewLinedef + (v[0][f],v[1][f],flags,normal_linedef,0,TRUE, + 0,0,prev_sect, + (prev_ch > (int)ch) ? upper : empty_texture, + empty_texture, + (prev_fh < (int)fh) ? lower : empty_texture, + 0,0,sect, + (prev_ch < (int)ch) ? upper : empty_texture, + empty_texture, + (prev_fh > (int)fh) ? lower : empty_texture); + + /* Add the new linedef to the vertex lists + */ + IntListUniqAdd(ev[0][f]->l,nl); + IntListUniqAdd(ev[1][f]->l,nl); + } + + /* Create the linedefs for the walls + */ + if (th) + { + offy_f-=(int)fh-prev_fh; + + while (offy_f<0) + offy_f+=th; + + offy_f%=th; + } + + if (do_ceiling) + if (th) + { + offy_c-=(int)ch-prev_ch; + + while (offy_c<0) + offy_c+=th; + + offy_c%=th; + } + + for(r=0;r<2;r++) + { + if (in_sect[f]==-1) + { + int offy; + + flags=block_mask; + + if (!do_ceiling) + { + flags|=upper_peg_mask; + offy=0; + } + else + offy=offy_c; + + nl=CreateNewLinedef(v[r][f+r],v[r][f+(r^1)], + flags,normal_linedef,0,FALSE, + 0,offy,sect, + empty_texture, + middle, + empty_texture, + 0,0,-1, + empty_texture, + empty_texture, + empty_texture); + + tm.line=nl; + + if (r==0) + { + tm.apply=TRUE; + ListAppend(side_sr[r],&tm); + tm.apply=FALSE; + ListInsert(side_sl[r],&tm); + } + else + { + tm.apply=TRUE; + ListInsert(side_sr[r],&tm); + tm.apply=FALSE; + ListAppend(side_sl[r],&tm); + } + } + else + { + int offy_l,offy_r; + + flags=side2_mask; + flags=side2_mask|lower_peg_mask|upper_peg_mask; + + if ((int)ch>s->s.ceiling) + offy_r=offy_c; + else if ((int)fh<s->s.floor) + offy_r=offy_c; + else + offy_r=0; + + offy_l=0; + + nl=CreateNewLinedef(v[r][f+r],v[r][f+(r^1)], + flags,normal_linedef,0,TRUE, + 0,offy_r,sect, + ((int)ch > s->s.ceiling) ? + upper : empty_texture, + empty_texture, + ((int)fh < s->s.floor) ? + lower : empty_texture, + 0,offy_l,in_sect[f], + ((int)ch < s->s.ceiling) ? + upper : empty_texture, + empty_texture, + ((int)fh > s->s.floor) ? + lower : empty_texture); + + tm.line=nl; + + if (r==0) + { + tm.apply=TRUE; + ListAppend(side_sr[r],&tm); + tm.apply=TRUE; + ListInsert(side_sl[r],&tm); + } + else + { + tm.apply=TRUE; + ListInsert(side_sr[r],&tm); + tm.apply=TRUE; + ListAppend(side_sl[r],&tm); + } + } + + /* Add the new linedef to the vertex lists + */ + IntListUniqAdd(ev[r][f]->l,nl); + IntListUniqAdd(ev[r][f+1]->l,nl); + } + + prev_fh=(int)fh; + prev_ch=(int)ch; + + fh+=step.step_f; + + if (do_ceiling) + ch+=step.step_c; + + prev_sect=sect; + } + + /* Adjust the end linedef anchor + */ + el=step.to; + el->l.flags|=side2_mask; + el->l.flags&=~block_mask; + + ns=Grab(sizeof(Sidedef)); + ns->x=0; + ns->y=0; + + if ((prev_ch!=step.to_c)&&(s_flag&SSTYLE_UPPER_PEG)) + el->l.flags|=upper_peg_mask; + else if (!(s_flag&SSTYLE_LEAVE_PEG)) + el->l.flags&=~upper_peg_mask; + + if ((prev_fh!=step.to_f)&&(s_flag&SSTYLE_LOWER_PEG)) + el->l.flags|=lower_peg_mask; + else if (!(s_flag&SSTYLE_LEAVE_PEG)) + el->l.flags&=~lower_peg_mask; + + if (prev_ch<step.to_c) + { + strcpy(el->sr->upper,upper); + strcpy(ns->upper,empty_texture); + } + else if (prev_ch>step.to_c) + { + strcpy(el->sr->upper,empty_texture); + strcpy(ns->upper,upper); + } + else + { + strcpy(el->sr->upper,empty_texture); + strcpy(ns->upper,empty_texture); + } + + if (prev_fh>step.to_f) + { + strcpy(el->sr->lower,lower); + strcpy(ns->lower,empty_texture); + } + else if (prev_fh<step.to_f) + { + strcpy(el->sr->lower,empty_texture); + strcpy(ns->lower,lower); + } + else + { + strcpy(el->sr->lower,empty_texture); + strcpy(ns->lower,empty_texture); + } + + strcpy(el->sr->middle,empty_texture); + strcpy(ns->middle,empty_texture); + + ns->sector=prev_sect; + + o.data=ns; + o.select=SELECT_NONE; + + n=MapSize(sidedef); + MapAdd(sidedef,n,&o); + el->sl=ns; + el->l.left=n; + + /* Calculate the texture offsets for the walls + */ + for(f=0;f<2;f++) + { + ApplyTextureOffset(side_sl[f],tw,FALSE); + ApplyTextureOffset(side_sr[f],tw,TRUE); + + ListClear(side_sl[f]); + ListClear(side_sr[f]); + } + + SectorCalcContainingAll(); + + return(TRUE); + } + else + return(FALSE); +} + + +/* ---------------------------------------- LINEDEF VECTOR MAP UTILS +*/ + +/* Note this is repeated, rather than shared with the sector vector map to save + any unexpected later interactions +*/ +static int vno=0; +static char *vmap=NULL; + +static void InitVMAP(void) +{ + TRACE; + + if (vno<MapSize(vertex)) + vmap=ReGrab(vmap,MapSize(vertex)); + + memset(vmap,FALSE,MapSize(vertex)); +} + + +/* ---------------------------------------- SECTOR LINEDEF MAP UTILS +*/ +static int lno=0; +static char *lmap=NULL; + +static void InitLMAP(void) +{ + TRACE; + + if (lno<MapSize(linedef)) + lmap=ReGrab(lmap,MapSize(linedef)); + + memset(lmap,FALSE,MapSize(linedef)); +} + + +/* ---------------------------------------- LINEDEF TRACK FUNCTIONS +*/ +List TrackLinedef(int line_no) +{ + EditSect *s; + EditLine *l; + List ll; + Iterator i; + int sec_no; + int done; + int f; + int vert_no; + + TRACE; + + if (!(l=GETLINE(line_no))) + return(NULL); + + InitLMAP(); + + lmap[line_no]=TRUE; + + ll=ListNew(sizeof(int)); + ListAppend(ll,&line_no); + + sec_no=l->sr->sector; + + if (!(s=GETSECT(sec_no))) + return(ll); + + vert_no=l->l.to; + + /* If the start LINEDEF is 2-sided and wholy within the sector, we only + track along connected 2-sided lines in the same sector. + + If the start line is 1-sided then we allow both 1 and 2 sided LINEDEFs + in the resulting list, but only 2 sided LINEDEFs that just have this + sector on one side of the line. + + To make this easier we mark the LMAP entries for those lines we wish to + ignore before starting. + */ + if ((l->sl)&&(l->sl->sector==sec_no)) + { + i=ListIterator(s->all); + + while(i) + { + memcpy(&l,IteratorData(i),sizeof(l)); + + if (!l->sl) + lmap[l->no]=TRUE; + else + if (!((l->sl->sector==sec_no)&&(l->sr->sector==sec_no))) + lmap[l->no]=TRUE; + + i=IteratorNext(i); + } + } + else + { + i=ListIterator(s->all); + + while(i) + { + memcpy(&l,IteratorData(i),sizeof(l)); + + if ((l->sl)&&(l->sl->sector==sec_no)&&(l->sr->sector==sec_no)) + lmap[l->no]=TRUE; + + i=IteratorNext(i); + } + } + + done=FALSE; + + while(!done) + { + done=TRUE; + + i=ListIterator(s->all); + + while(i) + { + memcpy(&l,IteratorData(i),sizeof(l)); + + f=l->no; + + if (!lmap[f]) + { + /* We need two seperate checks, as obviously left sidedefs + pointing into the sector will need TO, rather than FROM, + checking + */ + if ((l->sr->sector==sec_no)&&(l->l.from==vert_no)) + { + lmap[f]=TRUE; + ListAppend(ll,&f); + done=FALSE; + vert_no=l->l.to; + } + else if ((l->sl)&&(l->sl->sector==sec_no)&&(l->l.to==vert_no)) + { + lmap[f]=TRUE; + ListAppend(ll,&f); + done=FALSE; + vert_no=l->l.from; + } + } + + i=IteratorNext(i); + } + } + + return(ll); +} + + +/* ---------------------------------------- LINEDEF MERGING +*/ +void CheckMergeLinedef(EditVert *v) +{ + Iterator i; + int *f; + int r; + EditLine *ol,*cl; + int same_dir; + int merge; + + TRACE; + + i=ListIterator(v->l); + + while(i) + { + f=IteratorData(i); + + ol=GETLINE(*f); + + for(r=0;r<MapSize(linedef);r++) + if ((r!=*f)&&(cl=GETLINE(r))) + { + if (((cl->l.from==ol->l.from)&&(cl->l.to==ol->l.to))|| + ((cl->l.from==ol->l.to)&&(cl->l.to==ol->l.from))) + { + if ((cl->l.from==ol->l.from)&&(cl->l.to==ol->l.to)) + same_dir=TRUE; + else + same_dir=FALSE; + + if(merge_linedef==MERGE_ASK) + merge=YesNo("Linedefs %d and %d overlap. Merge?",*f,r); + else + merge=TRUE; + + if (merge) + { + if (same_dir) + { + if (cl->l.left!=-1) + { + DeleteLeftSidedef(ol); + ol->l.left=cl->l.left; + ol->sl=GETSIDE(ol->l.left); + ol->l.flags|=side2_mask; + + if (auto_block_linedefs) + ol->l.flags&=~block_mask; + } + } + else + { + DeleteLeftSidedef(ol); + ol->l.left=cl->l.right; + ol->sl=GETSIDE(ol->l.left); + ol->l.flags|=side2_mask; + + if (auto_block_linedefs) + ol->l.flags&=~block_mask; + } + + DeleteLinedef(r); + } + } + } + + i=IteratorNext(i); + } +} + + +/* ---------------------------------------- LINEDEF CREATION +*/ +int CreateNewLinedef(int from, int to, + int flags, int type, int tag, int two_sided, + int sr_ox, int sr_oy, int sr_sector, + DirName sr_upper, DirName sr_middle, DirName sr_lower, + int sl_ox, int sl_oy, int sl_sector, + DirName sl_upper, DirName sl_middle, DirName sl_lower) +{ + Object o; + EditLine *l; + Sidedef *s; + int ln,srn,sln; + + TRACE; + + ln=MapSize(linedef); + + srn=MapSize(sidedef); + + if (two_sided) + sln=srn+1; + else + sln=-1; + + o.select=SELECT_NONE; + + s=Grab(sizeof(Sidedef)); + s->x=sr_ox; + s->y=sr_oy; + s->sector=sr_sector; + strcpy(s->upper,sr_upper); + strcpy(s->middle,sr_middle); + strcpy(s->lower,sr_lower); + o.data=s; + MapAdd(sidedef,srn,&o); + + if (sln!=-1) + { + s=Grab(sizeof(Sidedef)); + s->x=sl_ox; + s->y=sl_oy; + s->sector=sl_sector; + strcpy(s->upper,sl_upper); + strcpy(s->middle,sl_middle); + strcpy(s->lower,sl_lower); + o.data=s; + MapAdd(sidedef,sln,&o); + } + + l=Grab(sizeof(EditLine)); + + l->no=ln; + + l->l.from=from; + l->l.to=to; + + l->l.flags=flags; + l->l.type=type; + l->l.tag=tag; + + l->v[0]=GETVERT(l->l.from); + l->v[1]=GETVERT(l->l.to); + + l->l.right=srn; + l->l.left=sln; + + l->sr=GETSIDE(srn); + + if (sln!=-1) + l->sl=GETSIDE(sln); + else + l->sl=NULL; + + if (edit_mode==LINEDEF_MODE) + switch(insert_select) + { + case HOVER_NONE: + o.select=SELECT_NONE; + break; + case HOVER_ADD: + case HOVER_SINGLE: + o.select=SELECT_SELECTED; + break; + } + else + o.select=SELECT_NONE; + + LineCalcBounding(l); + o.data=l; + MapAdd(linedef,ln,&o); + + if (edit_mode==LINEDEF_MODE) + switch(insert_select) + { + case HOVER_NONE: + break; + case HOVER_ADD: + ListAppend(selected,&ln); + break; + case HOVER_SINGLE: + ClearSelection(); + o.select=SELECT_SELECTED; + ListAppend(selected,&ln); + FullRedraw(); + break; + } + + return(ln); +} + + +/* ---------------------------------------- GENERIC LINEDEF FUNCS +*/ +int PositionOnObject_LINEDEF(int x,int y,void *data) +{ + EditLine *l; + + TRACE; + + l=data; + + /* + if (scale<4) + box=BOXBOUND_FUZZY(x,y,l->min_x,l->min_y,l->max_x,l->max_y,2); + else + box=BOXBOUND_FUZZY(x,y,l->min_x,l->min_y,l->max_x,l->max_y,scale/2); + + if (!box) + return(FALSE); + */ + + if(LinesCross(x-(scale*linedef_select),y,x+(scale*linedef_select),y, + l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y)) + return(TRUE); + + return(LinesCross(x,y-(scale*linedef_select),x,y+(scale*linedef_select), + l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y)); +} + + +void SelectBox_LINEDEF(int x1,int y1,int x2,int y2) +{ + Object *o; + EditLine *l; + int f; + + TRACE; + + for(f=0;f<MapSize(linedef);f++) + { + o=MapElem(linedef,f); + + if ((l=o->data)) + { + if ((o->select!=SELECT_SELECTED)&& + (BOXBOUND(l->v[0]->v.x,l->v[0]->v.y,x1,y1,x2,y2))&& + (BOXBOUND(l->v[1]->v.x,l->v[1]->v.y,x1,y1,x2,y2))) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } + } +} + + +void SelectByType_LINEDEF(void) +{ + Object *o; + EditLine *l; + int id; + int f; + + if ((id=SelectLinedef())!=LINEDEF_NULLID) + { + ClearSelection(); + + for(f=0;f<MapSize(linedef);f++) + if ((o=MapElem(linedef,f))) + if ((l=o->data)&&(l->l.type==id)) + { + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + } + } +} + + +void DrawObject_LINEDEF(void *data, int selmode) +{ + static List hilite=NULL; + static int drawn=FALSE; + Iterator i; + EditLine *l; + EditLine *sl=NULL; + EditSect *s; + Object *o; + int f; + + TRACE; + + if (!hilite) + hilite=ListNew(sizeof(int)); + + l=data; + + /* If the current object has changed, remove the highlighted tag objects + */ + if ((current==-1)&&(drawn)) + { + drawn=FALSE; + RemoveHighlights(hilite); + ListEmpty(hilite); + } + + /* Draw tagged sectors + */ + if ((tag_highlight)&&(current==l->no)) + { + RemoveHighlights(hilite); + ListEmpty(hilite); + + if (l->l.tag) + { + drawn=TRUE; + + for(f=0;f<MapSize(sector);f++) + if ((s=GETSECT(f))) + if ((s->s.tag==l->l.tag)&&(SectorOnDisplay(s))) + { + i=ListIterator(s->all); + + while(i) + { + memcpy(&sl,IteratorData(i),sizeof(sl)); + o=MapElem(linedef,sl->no); + + if (o->select==SELECT_NONE) + { + ListAppend(hilite,&(sl->no)); + DrawLinedef(sl,TAGCOL); + } + + i=IteratorNext(i); + } + } + } + + } + + /* Only draw the line if it's not been drawn tagged or is selected. + */ + if ((!tag_highlight)||(selmode==SELECT_SELECTED)|| + (!InIntList(hilite,l->no))) + DrawLinedef(data,SelColour(selmode)); +} + + +void DrawObjectInfo_LINEDEF(void) +{ + EditLine *l; + + TRACE; + + if (!draw_current_info) + return; + + if ((current!=-1)&&((l=GETLINE(current)))) + { + if (show_full_linedef_info) + GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE, + "Linedef No : %-5d|" + "Flags : %s|" + "Type [%4.4x]: %-35.35s|" + "Tag : %-5d", + current, + LinedefFlagText(l->l.flags), + l->l.type,LinedefName(l->l.type),l->l.tag); + else + GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE, + "Linedef No : %-5d|" + "Flags : %s|" + "Type [%4.4x]: %-20.20s|" + "Tag : %-5d", + current, + LinedefFlagText(l->l.flags), + l->l.type,LinedefClass(l->l.type),l->l.tag); + + GuiDrawInfoBox("RIGHT SIDEDEF",GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE, + "Offset : %d,%d|" + "Upper : %-10s|" + "Middle : %-10s|" + "Lower : %-10s|" + "Sector : %d", + l->sr->x,l->sr->y, + l->sr->upper,l->sr->middle,l->sr->lower, + l->sr->sector); + + if (l->sl) + GuiDrawInfoBox("LEFT SIDEDEF",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + "Offset : %d,%d|" + "Upper : %-10s|" + "Middle : %-10s|" + "Lower : %-10s|" + "Sector : %d", + l->sl->x,l->sl->y, + l->sl->upper,l->sl->middle,l->sl->lower, + l->sl->sector); + else + GuiDrawInfoBox("NO LEFT SIDEDEF",GUI_FLUSH_LEFT, + GUI_FLUSH_LOWER,FALSE, + " |" + " %-10s|" + " |" + " |" + " ",""); + } + else + { + if (show_full_linedef_info) + GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE, + "Linedef No : -|" + "Flags : -|" + "Type : %35s|" + "Tag : -",""); + else + GuiDrawInfoBox("LINEDEF",GUI_CENTRE,GUI_FLUSH_LOWER,FALSE, + "Linedef No : -|" + "Flags : -|" + "Type : %20s|" + "Tag : -",""); + + GuiDrawInfoBox("RIGHT SIDEDEF",GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE, + " |" + " %-10s|" + " |" + " |" + " ",""); + + GuiDrawInfoBox("LEFT SIDEDEF",GUI_FLUSH_LEFT,GUI_FLUSH_LOWER,FALSE, + " |" + " %-10s|" + " |" + " |" + " ",""); + } +} + + +void DrawObjectHeader_LINEDEF(void) +{ + if (tag_highlight) + GFX_print(0,FH,WHITE,"Tag highlight: ON"); + else + GFX_print(0,FH,WHITE,"Tag highlight: OFF"); +} + + +void MoveObject_LINEDEF(void) +{ + GFXEvent ev; + int omx,omy; + int dmx,dmy; + int done; + Iterator i; + Iterator i2; + EditLine *l; + List orig; + int *f,r; + Point p; + unsigned char *vmap; + int cancel; + + TRACE; + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + GFX_bounce(); + + done=FALSE; + cancel=FALSE; + orig=ListNew(sizeof(Point)); + + vmap=Grab(MapSize(vertex)); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + l=GETLINE(*f); + p.x=l->v[0]->v.x; + p.y=l->v[0]->v.y; + ListAppend(orig,&p); + p.x=l->v[1]->v.x; + p.y=l->v[1]->v.y; + ListAppend(orig,&p); + i=IteratorNext(i); + } + + while(!done) + { + GuiDrawInfoBox("Move LINEDEF",GUI_FLUSH_RIGHT,GUI_FLUSH_LOWER,FALSE, + "Left mouse button to place|ESC to cancel"); + + GFX_redraw(); + GFX_await_input_full(&ev); + + switch(ev.type) + { + case GFX_KEY_EVENT: + HandleMoveKey(ev.key,FALSE); + + /* Cancel the move + */ + if (ev.key.code==GFX_ESC) + { + cancel=TRUE; + + i=ListIterator(selected); + i2=ListIterator(orig); + + while(i2) + { + f=IteratorData(i); + + l=GETLINE(*f); + + memcpy(&p,IteratorData(i2),sizeof(Point)); + l->v[0]->v.x=p.x; + l->v[0]->v.y=p.y; + i2=IteratorNext(i2); + + memcpy(&p,IteratorData(i2),sizeof(Point)); + l->v[1]->v.x=p.x; + l->v[1]->v.y=p.y; + i2=IteratorNext(i2); + + i=IteratorNext(i); + } + + done=TRUE; + dmx=0; + dmy=0; + } + else + { + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + } + + break; + + case GFX_MOUSE_EVENT: + memcpy(&ms,&ev.mouse,sizeof(ev.mouse)); + + if (ms.b&GFX_BUTLEFT) + done=TRUE; + + dmx=SnapX(XToMap(ms.x))-omx; + dmy=SnapY(YToMap(ms.y))-omy; + break; + + default: + dmx=0; + dmy=0; + break; + } + + if ((dmx)||(dmy)) + { + for(r=0;r<MapSize(vertex);r++) + vmap[r]=FALSE; + + i=ListIterator(selected); + while(i) + { + f=IteratorData(i); + + l=GETLINE(*f); + + if (!vmap[l->l.from]) + { + l->v[0]->v.x+=dmx; + l->v[0]->v.y+=dmy; + vmap[l->l.from]=TRUE; + } + + if (!vmap[l->l.to]) + { + l->v[1]->v.x+=dmx; + l->v[1]->v.y+=dmy; + vmap[l->l.to]=TRUE; + } + + i=IteratorNext(i); + } + + omx=SnapX(XToMap(ms.x)); + omy=SnapY(YToMap(ms.y)); + + FullRedraw(); + } + } + + ListClear(orig); + Release(vmap); + + if ((clear_on_move)&&(!cancel)) + ClearSelection(); + + FullRedraw(); +} + + +void RotateObject_LINEDEF(double angle) +{ + int cx,cy; + int x,y; + int *f; + Iterator i; + EditLine *l; + + TRACE; + + InitVMAP(); + + LineSelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + l=GETLINE(*f); + + if (!vmap[l->l.from]) + { + vmap[l->l.from]=TRUE; + x=l->v[0]->v.x; + y=l->v[0]->v.y; + + Rotate(cx,cy,&x,&y,angle); + + l->v[0]->v.x=x; + l->v[0]->v.y=y; + } + + if (!vmap[l->l.to]) + { + vmap[l->l.to]=TRUE; + x=l->v[1]->v.x; + y=l->v[1]->v.y; + + Rotate(cx,cy,&x,&y,angle); + + l->v[1]->v.x=x; + l->v[1]->v.y=y; + } + + i=IteratorNext(i); + } +} + + +void ScaleObject_LINEDEF(double scale) +{ + int cx,cy; + int x,y; + int *f; + Iterator i; + EditLine *l; + + TRACE; + + LineSelectionCentre(&cx,&cy); + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + l=GETLINE(*f); + + x=l->v[0]->v.x; + y=l->v[0]->v.y; + + Scale(cx,cy,&x,&y,scale); + + l->v[0]->v.x=x; + l->v[0]->v.y=y; + + x=l->v[1]->v.x; + y=l->v[1]->v.y; + + Scale(cx,cy,&x,&y,scale); + + l->v[1]->v.x=x; + l->v[1]->v.y=y; + + i=IteratorNext(i); + } +} + + +void SetTagObject_LINEDEF(int tag) +{ + int *f; + Iterator i; + EditLine *l; + + TRACE; + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + l=GETLINE(*f); + l->l.tag=tag; + i=IteratorNext(i); + } +} + + +void LocateObject_LINEDEF(void *obj) +{ + int cx,cy; + EditLine *l; + + TRACE; + + l=obj; + cx=l->min_x+(l->max_x-l->min_x)/2; + cy=l->min_y+(l->max_y-l->min_y)/2; + ox=cx-scale*SCRW/2; + oy=cy+scale*SCRH/2; +} + + +void ObjectInsert_LINEDEF(void) +{ + int type; + int fl,two; + DirName sr_upper,sr_lower,sr_middle; + DirName sl_upper,sl_lower,sl_middle; + int ok; + int from,to; + int nl; + EditVert *v; + + TRACE; + + if (MapSize(vertex)<2) + { + GuiInfoBox("ERROR","Need more that 2 vertices|to make a line"); + FullRedraw(); + } + else + { + vertex_dialog[D_VERTEX_FROM].data.i=MapSize(vertex)-2; + vertex_dialog[D_VERTEX_TO].data.i=MapSize(vertex)-1; + + ok=GUI_dialog("Create LINEDEF",D_VERTEX_NO,vertex_dialog); + + if (ok) + { + from=vertex_dialog[D_VERTEX_FROM].data.i; + to=vertex_dialog[D_VERTEX_TO].data.i; + + if ((from>=MapSize(vertex))||(from<0)||(!GETVERT(from))) + { + GuiInfoBox("ERROR","%d (from) is an invalid vertex",from); + FullRedraw(); + ok=FALSE; + } + else if ((to>=MapSize(vertex))||(to<0)||(!GETVERT(to))) + { + GuiInfoBox("ERROR","%d (to) is an invalid vertex",to); + FullRedraw(); + ok=FALSE; + } + } + + if (ok) + if (GetLinedefValues(TRUE,0,0,0,0, + &type,&fl,&two, + sr_upper,sr_middle,sr_lower, + sl_upper,sl_middle,sl_lower)) + { + nl=CreateNewLinedef(from,to, + fl,type,0,two, + 0,0,0, + sr_upper,sr_middle,sr_lower, + 0,0,0, + sl_upper,sl_middle,sl_lower); + + v=GETVERT(from); + IntListUniqAdd(v->l,from); + v=GETVERT(to); + IntListUniqAdd(v->l,from); + + FullRedraw(); + } + } +} + + +void ObjectDelete_LINEDEF(void) +{ + Iterator i; + int *f; + + TRACE; + + i=ListIterator(selected); + + while(i) + { + f=IteratorData(i); + DeleteLinedef(*f); + i=IteratorNext(i); + } + + SectorCalcContainingAll(); + ClearSelection(); + FullRedraw(); +} + + +void ObjectMenu_LINEDEF(void) +{ + static int ax=0; + static int ay=0; + EditLine *l; + int f,*s; + Iterator i; + int cancel; + int opt; + + TRACE; + + s=NULL; + cancel=FALSE; + GFX_redraw(); + + opt=GUI_menu("Linedef/sidedef",ms.x,ms.y,linedef_popup,GUI_CANCEL); + + switch(opt) + { + case TM_RIGHT_SIDE: + opt=GUI_menu("Right sidedef",ms.x,ms.y,right_popup,GUI_CANCEL); + break; + + case TM_LEFT_SIDE: + opt=GUI_menu("Left sidedef",ms.x,ms.y,left_popup,GUI_CANCEL); + break; + + default: + break; + } + + switch(opt) + { + case TM_TYPE: + { + f=SelectLinedef(); + + if (f!=LINEDEF_NULLID) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + l->l.type=f; + i=IteratorNext(i); + } + + FullRedraw(); + } + break; + } + + case TM_FLAGS: + l=SelHead(); + f=l->l.flags; + + if (GUI_multi_box("Flags",LinedefFlagArray(),&f)) + { + int new_side; + List new; + + new=ListNew(sizeof(int)); + new_side=FALSE; + + i=ListIterator(selected); + + while(i) + { + int new_f; + + new_f=f; + s=IteratorData(i); + l=GETLINE(*s); + + /* If the line was 2 sided, and is now one - removed the + left sidedef + */ + if ((l->l.flags&side2_mask)&&(!(new_f&side2_mask))) + { + DeleteLeftSidedef(l); + + if (auto_block_linedefs) + new_f|=block_mask; + } + + /* If the line was 1 sided, and is now two - add the + left sidedef + */ + if ((!(l->l.flags&side2_mask))&&(new_f&side2_mask)) + { + Object o; + Sidedef *ns; + int n; + + ns=Grab(sizeof(Sidedef)); + ns->x=0; + ns->y=0; + strcpy(ns->upper,empty_texture); + strcpy(ns->middle,empty_texture); + strcpy(ns->lower,empty_texture); + ns->sector=-1; + + o.data=ns; + o.select=SELECT_NONE; + + n=MapSize(sidedef); + MapAdd(sidedef,n,&o); + l->sl=ns; + l->l.left=n; + + new_side=TRUE; + + ListAppend(new,s); + + if (auto_block_linedefs) + new_f&=~block_mask; + } + + l->l.flags=new_f; + i=IteratorNext(i); + } + + if (new_side) + switch(new_2sided_select) + { + case NEWSELECT_NEVER: + GuiInfoBox("NOTICE","Left SIDEDEFS have been added|" + "to some or all LINEDEFS"); + break; + + /* WARNING: This case cascades into the following + one + */ + case NEWSELECT_ASK: + if (!YesNo("New left SIDEDEFS created. " + "Select those LINEDEFS?")) + break; + case NEWSELECT_SELECT: + { + Object *o; + + new_selection=TRUE; + ClearSelection(); + i=ListIterator(new); + + while(i) + { + s=IteratorData(i); + o=MapElem(linedef,*s); + SetSelect(*s,SELECT_SELECTED); + ListAppend(selected,s); + i=IteratorNext(i); + } + break; + } + } + + ListClear(new); + + FullRedraw(); + } + + break; + + case TM_SWAP_SIDES: + { + int tmp; + Sidedef *tmp_s; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + + if (l->l.left!=-1) + { + tmp=l->l.left; + tmp_s=l->sl; + + l->sl=l->sr; + l->l.left=l->l.right; + + l->sr=tmp_s; + l->l.right=tmp; + + tmp=l->l.from; + l->l.from=l->l.to; + l->l.to=tmp; + + l->v[0]=GETVERT(l->l.from); + l->v[1]=GETVERT(l->l.to); + } + + i=IteratorNext(i); + } + + SectorCalcContainingAll(); + FullRedraw(); + + break; + } + + case TM_SPLIT_LINE: + { + List new; + int no; + Object *o; + + new=ListNew(sizeof(int)); + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + no=SplitLinedef(*s); + ListAppend(new,&no); + i=IteratorNext(i); + } + + i=ListIterator(new); + + while(i) + { + s=IteratorData(i); + o=MapElem(linedef,*s); + SetSelect(*s,SELECT_SELECTED); + + ListAppend(selected,s); + i=IteratorNext(i); + } + + ListClear(new); + SectorCalcContainingAll(); + FullRedraw(); + + break; + } + + case TM_TRACK_LINE: + { + List new; + Object *o; + + i=ListIterator(selected); + + *s=MapSize(linedef)+1; + + while(i) + { + s=IteratorData(i); + i=IteratorNext(i); + } + + if ((new=TrackLinedef(*s))) + { + ClearSelection(); + i=ListIterator(new); + + while(i) + { + s=IteratorData(i); + + o=MapElem(linedef,*s); + SetSelect(*s,SELECT_SELECTED); + ListAppend(selected,s); + + i=IteratorNext(i); + } + + ListClear(new); + new_selection=TRUE; + FullRedraw(); + } + + break; + } + + case TM_STEPS: + if (ListSize(selected)!=2) + GuiInfoBox("ERROR","Just select 2 linedefs|for this function"); + else + { + int *l1,*l2; + + i=ListIterator(selected); + l1=IteratorData(i); + i=IteratorNext(i); + l2=IteratorData(i); + IteratorClear(i); + + cancel=CreateSteps(*l1,*l2); + } + + FullRedraw(); + break; + + + case TM_OFFSET_R: + l=SelHead(); + + offset_dialog[D_OFFSET_OFFX].data.i=l->sr->x; + offset_dialog[D_OFFSET_OFFY].data.i=l->sr->y; + + if (GUI_dialog("Right offset",D_OFFSET_NO,offset_dialog)) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sr) + { + l->sr->x=offset_dialog[D_OFFSET_OFFX].data.i; + l->sr->y=offset_dialog[D_OFFSET_OFFY].data.i; + } + i=IteratorNext(i); + } + + i=IteratorClear(i); + FullRedraw(); + } + + break; + + case TM_ADJUST_R: + l=SelHead(); + + offset_dialog[D_OFFSET_OFFX].data.i=ax; + offset_dialog[D_OFFSET_OFFY].data.i=ay; + + if (GUI_dialog("Right offset adjustment",D_OFFSET_NO,offset_dialog)) + { + ax=offset_dialog[D_OFFSET_OFFX].data.i; + ay=offset_dialog[D_OFFSET_OFFY].data.i; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sr) + { + l->sr->x+=ax; + l->sr->y+=ay; + } + i=IteratorNext(i); + } + + i=IteratorClear(i); + FullRedraw(); + } + + break; + + case TM_SECTOR_R: + l=SelHead(); + + sectorn_dialog[D_SECTORN_SECNO].data.i=l->sr->sector; + + if (GUI_dialog("Right sector",D_SECTORN_NO,sectorn_dialog)) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sr) + l->sr->sector=sectorn_dialog[D_SECTORN_SECNO].data.i; + i=IteratorNext(i); + } + + i=IteratorClear(i); + SectorCalcContainingAll(); + FullRedraw(); + } + + break; + + case TM_UPPER_T_R: + { + DirName d; + + if ((GetTexture("Upper Right texture",d))) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + strcpy(l->sr->upper,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_MIDDLE_T_R: + { + DirName d; + + if ((GetTexture("Middle Right texture",d))) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + strcpy(l->sr->middle,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_LOWER_T_R: + { + DirName d; + + if ((GetTexture("Lower Right texture",d))) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + strcpy(l->sr->lower,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_ALIGN_R: + { + int tw; + int ox; + + l=SelHead(); + + tw=CalcTextureWidth(l->sr->upper,l->sr->middle,l->sr->lower); + + if (tw==0) + { + GuiInfoBox("ERROR","First selected linedef has no texture"); + FullRedraw(); + } + else + { + ox=l->sr->x; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + + l=GETLINE(*s); + + l->sr->x=ox; + + ox=(ox+Len(l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y))%tw; + + i=IteratorNext(i); + } + + FullRedraw(); + } + + } + break; + + + case TM_OFFSET_L: + l=SelHead(); + + if (l->sl) + { + offset_dialog[D_OFFSET_OFFX].data.i=l->sl->x; + offset_dialog[D_OFFSET_OFFY].data.i=l->sl->y; + } + + if (GUI_dialog("Left offset",D_OFFSET_NO,offset_dialog)) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sl) + { + l->sl->x=offset_dialog[D_OFFSET_OFFX].data.i; + l->sl->y=offset_dialog[D_OFFSET_OFFY].data.i; + } + i=IteratorNext(i); + } + + i=IteratorClear(i); + FullRedraw(); + } + + break; + + case TM_ADJUST_L: + l=SelHead(); + + offset_dialog[D_OFFSET_OFFX].data.i=ax; + offset_dialog[D_OFFSET_OFFY].data.i=ay; + + if (GUI_dialog("Left offset adjustment",D_OFFSET_NO,offset_dialog)) + { + ax=offset_dialog[D_OFFSET_OFFX].data.i; + ay=offset_dialog[D_OFFSET_OFFY].data.i; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sl) + { + l->sl->x+=ax; + l->sl->y+=ay; + } + i=IteratorNext(i); + } + + i=IteratorClear(i); + FullRedraw(); + } + + break; + + case TM_SECTOR_L: + l=SelHead(); + + if (l->sl) + sectorn_dialog[D_SECTORN_SECNO].data.i=l->sl->sector; + + if (GUI_dialog("Left sector",D_SECTORN_NO,sectorn_dialog)) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sl) + l->sl->sector=sectorn_dialog[D_SECTORN_SECNO].data.i; + i=IteratorNext(i); + } + + i=IteratorClear(i); + SectorCalcContainingAll(); + FullRedraw(); + } + + break; + + case TM_UPPER_T_L: + { + DirName d; + + if ((GetTexture("Upper Left texture",d))) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sl) + strcpy(l->sl->upper,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_MIDDLE_T_L: + { + DirName d; + + if ((GetTexture("Middle Left texture",d))) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sl) + strcpy(l->sl->middle,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_LOWER_T_L: + { + DirName d; + + if ((GetTexture("Lower Left texture",d))) + { + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + if (l->sl) + strcpy(l->sl->lower,d); + i=IteratorNext(i); + } + + FullRedraw(); + } + + break; + } + + case TM_ALIGN_L: + { + int tw; + int ox; + int ok; + + ok=TRUE; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + l=GETLINE(*s); + + if (!(l->sl)) + ok=FALSE; + + i=IteratorNext(i); + } + + if (!ok) + { + GuiInfoBox("ERROR","Some linedefs with no left sidedef"); + FullRedraw(); + } + else + { + l=SelHead(); + + tw=CalcTextureWidth(l->sl->upper,l->sl->middle,l->sl->lower); + + if (tw==0) + { + GuiInfoBox("ERROR","First selected linedef has no texture"); + FullRedraw(); + } + else + { + ox=l->sl->x; + + i=ListIterator(selected); + + while(i) + { + s=IteratorData(i); + + l=GETLINE(*s); + + l->sl->x=ox; + + ox=(ox+Len(l->v[0]->v.x,l->v[0]->v.y, + l->v[1]->v.x,l->v[1]->v.y))%tw; + + i=IteratorNext(i); + } + + FullRedraw(); + } + } + + } + break; + + + case TM_TAG: + l=SelHead(); + tag_dialog[D_TAG].data.i=l->l.tag; + + if (GUI_dialog("Tag",D_TAG_NO,tag_dialog)) + { + SetTagObject_LINEDEF(tag_dialog[D_TAG].data.i); + FullRedraw(); + } + + break; + + case TM_DELETE: + ObjectDelete_LINEDEF(); + break; + + case TM_MOVE: + MoveObject_LINEDEF(); + break; + + default: + cancel=TRUE; + break; + } + + if ((!cancel)&&(!new_selection)&&(clear_on_menu)) + { + ClearSelection(); + FullRedraw(); + } +} + + +void ObjectKey_LINEDEF(GFXKey k) +{ + char s[128]; + EditLine *l; + int f; + int change; + List li; + Iterator i; + EditSect *sr,*sl; + DirName d; + Object *o; + int apply; + + TRACE; + + switch(k.code) + { + case GFX_F12: + li=ListNew(sizeof(int)); + + change=FALSE; + + if (ListSize(selected)==0) + { + GuiInfoBox("ERROR","No linedefs selected"); + FullRedraw(); + return; + } + + i=ListIterator(selected); + + while(i) + { + memcpy(&f,IteratorData(i),sizeof(f)); + + if ((l=GETLINE(f))) + { + TRACE; + if (check_1side_lower) + if ((!l->sl)&&(strcmp(l->sr->lower,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is one-sided with a " + "lower texture. Remove?",f))) + { + strcpy(l->sr->lower,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + + TRACE; + if (check_1side_middle) + if ((!l->sl)&&(!strcmp(l->sr->middle,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is one-sided with no " + "middle texture. Add?",f))) + { + sprintf(s,"Pick MIDDLE texture " + "for LINEDEF %d",f); + + if (strcmp(linedef_check_default,empty_texture)) + { + apply=TRUE; + strcpy(d,linedef_check_default); + } + else + apply=GetTexture(s,d); + + if (apply) + { + strcpy(l->sr->middle,d); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + TRACE; + if (check_1side_upper) + if ((!l->sl)&&(strcmp(l->sr->upper,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is one-sided with a " + "upper texture. Remove?",f))) + { + strcpy(l->sr->upper,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + + TRACE; + if ((check_2side_lower)&&(l->sl)&&(l->sl->sector!=-1)&& + (l->sr->sector!=-1)) + { + sr=GETSECT(l->sr->sector); + sl=GETSECT(l->sl->sector); + + if ((sr->s.floor<sl->s.floor)&& + (!strcmp(l->sr->lower,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with no " + "lower texture. Add?",f))) + { + sprintf(s,"Pick LOWER texture " + "for LINEDEF %d",f); + + if (strcmp(linedef_check_default,empty_texture)) + { + apply=TRUE; + strcpy(d,linedef_check_default); + } + else + apply=GetTexture(s,d); + + if (apply) + { + strcpy(l->sr->lower,d); + strcpy(l->sl->lower,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + if ((sr->s.floor>sl->s.floor)&& + (!strcmp(l->sl->lower,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with no " + "lower texture. Add?",f))) + { + sprintf(s,"Pick LOWER texture " + "for LINEDEF %d",f); + + if (strcmp(linedef_check_default,empty_texture)) + { + apply=TRUE; + strcpy(d,linedef_check_default); + } + else + apply=GetTexture(s,d); + + if (apply) + { + strcpy(l->sl->lower,d); + strcpy(l->sr->lower,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + if ((sr->s.floor==sl->s.floor)&& + ((strcmp(l->sl->lower,empty_texture))|| + (strcmp(l->sr->lower,empty_texture)))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with pointless " + "lower texture. Remove?",f))) + { + strcpy(l->sl->lower,empty_texture); + strcpy(l->sr->lower,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + TRACE; + if ((check_2side_middle)&&(l->sl)&&(l->sl->sector!=-1)) + { + if (((strcmp(l->sr->middle,empty_texture))|| + (strcmp(l->sl->middle,empty_texture)))&& + (l->sl->sector!=l->sr->sector)) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with a " + "middle texture. Remove?",f))) + { + strcpy(l->sr->middle,empty_texture); + strcpy(l->sl->middle,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + TRACE; + if ((check_2side_upper)&&(l->sl)&&(l->sl->sector!=-1)&& + (l->sr->sector!=-1)) + { + sr=GETSECT(l->sr->sector); + sl=GETSECT(l->sl->sector); + + if ((sr->s.ceiling>sl->s.ceiling)&& + (!strcmp(l->sr->upper,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with no " + "upper texture. Add?",f))) + { + sprintf(s,"Pick UPPER texture " + "for LINEDEF %d",f); + + if (strcmp(linedef_check_default,empty_texture)) + { + apply=TRUE; + strcpy(d,linedef_check_default); + } + else + apply=GetTexture(s,d); + + if (apply) + { + strcpy(l->sr->upper,d); + strcpy(l->sl->upper,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + if ((sr->s.ceiling<sl->s.ceiling)&& + (!strcmp(l->sl->upper,empty_texture))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with no " + "upper texture. Add?",f))) + { + sprintf(s,"Pick UPPER texture " + "for LINEDEF %d",f); + + if (strcmp(linedef_check_default,empty_texture)) + { + apply=TRUE; + strcpy(d,linedef_check_default); + } + else + apply=GetTexture(s,d); + + if (apply) + { + strcpy(l->sl->upper,d); + strcpy(l->sr->upper,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + if ((sr->s.ceiling==sl->s.ceiling)&& + ((strcmp(l->sl->upper,empty_texture))|| + (strcmp(l->sr->upper,empty_texture)))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided with pointless " + "upper texture. Remove?",f))) + { + strcpy(l->sl->upper,empty_texture); + strcpy(l->sr->upper,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + TRACE; + if ((check_2side_same_sector)&&(l->sl)&&(l->sl->sector!=-1)) + { + if ((l->sl->sector==l->sr->sector)&& + ((strcmp(l->sr->lower,empty_texture))|| + (strcmp(l->sr->middle,empty_texture))|| + (strcmp(l->sr->upper,empty_texture))|| + (strcmp(l->sl->lower,empty_texture))|| + (strcmp(l->sl->middle,empty_texture))|| + (strcmp(l->sl->upper,empty_texture)))) + if ((check_line_assume_yes)|| + (YesNo("LINEDEF %d is two-sided within a " + "sector and is textured. Remove all?",f))) + { + strcpy(l->sr->lower,empty_texture); + strcpy(l->sl->lower,empty_texture); + strcpy(l->sr->middle,empty_texture); + strcpy(l->sl->middle,empty_texture); + strcpy(l->sr->upper,empty_texture); + strcpy(l->sl->upper,empty_texture); + change=TRUE; + IntListUniqAdd(li,f); + } + } + + } + + i=IteratorNext(i); + } + + if (change) + { + if (YesNo("Select altered LINEDEFs?")) + { + ClearSelection(); + i=ListIterator(li); + + while(i) + { + memcpy(&f,IteratorData(i),sizeof(int)); + o=MapElem(linedef,f); + SetSelect(f,SELECT_SELECTED); + ListAppend(selected,&f); + i=IteratorNext(i); + } + + FullRedraw(); + } + } + else + { + GuiInfoBox("NOTICE","No problems found"); + FullRedraw(); + } + + ListClear(li); + break; + + default: + + case GFX_ASCII: + switch(toupper(k.ascii)) + { + case 'H': + tag_highlight=!tag_highlight; + FullRedraw(); + break; + + default: + break; + } + break; + } +} + + +int ObjectHasTag_LINEDEF(void *obj, int tag) +{ + EditLine *l; + + return ((l=obj)&&(l->l.tag==tag)); +} + + +ObjDesc *ObjectOverlaid_LINEDEF(int x, int y, int *no) +{ + int n; + EditLine *l; + ObjDesc *od; + int f; + + TRACE; + + od=NULL; + + n=0; + + for(f=0;f<MapSize(linedef);f++) + { + l=GETLINE(f); + + if ((l)&&(PositionOnObject_LINEDEF(x,y,l))) + { + n++; + od=ReGrab(od,sizeof(ObjDesc)*n); + od[n-1].no=f; + + sprintf(od[n-1].detail,"%5d - %s (Tag %d)",f, + TrimStr(LinedefName(l->l.type),60), + l->l.tag); + } + } + + *no=n; + return(od); +} + + +/* END OF FILE */ |