📄 am_map.c
字号:
}
else AM_restoreScaleAndLoc();
break;
case AM_FOLLOWKEY:
followplayer = !followplayer;
f_oldloc.x = MAXINT;
plr->message = followplayer ? AMSTR_FOLLOWON : AMSTR_FOLLOWOFF;
break;
case AM_GRIDKEY:
grid = !grid;
plr->message = grid ? AMSTR_GRIDON : AMSTR_GRIDOFF;
break;
case AM_MARKKEY:
sprintf(buffer, "%s %d", AMSTR_MARKEDSPOT, markpointnum);
plr->message = buffer;
AM_addMark();
break;
case AM_CLEARMARKKEY:
AM_clearMarks();
plr->message = AMSTR_MARKSCLEARED;
break;
default:
cheatstate=0;
rc = false;
}
if (!deathmatch && cht_CheckCheat(&cheat_amap, ev->data1))
{
rc = false;
cheating = (cheating+1) % 3;
}
}
else if (ev->type == ev_keyup)
{
rc = false;
switch (ev->data1)
{
case AM_PANRIGHTKEY:
if (!followplayer) m_paninc.x = 0;
break;
case AM_PANLEFTKEY:
if (!followplayer) m_paninc.x = 0;
break;
case AM_PANUPKEY:
if (!followplayer) m_paninc.y = 0;
break;
case AM_PANDOWNKEY:
if (!followplayer) m_paninc.y = 0;
break;
case AM_ZOOMOUTKEY:
case AM_ZOOMINKEY:
mtof_zoommul = FRACUNIT;
ftom_zoommul = FRACUNIT;
break;
}
}
return rc;
}
//
// Zooming
//
void AM_changeWindowScale(void)
{
// Change the scaling multipliers
scale_mtof = FixedMul(scale_mtof, mtof_zoommul);
scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
if (scale_mtof < min_scale_mtof)
AM_minOutWindowScale();
else if (scale_mtof > max_scale_mtof)
AM_maxOutWindowScale();
else
AM_activateNewScale();
}
//
//
//
void AM_doFollowPlayer(void)
{
if (f_oldloc.x != plr->mo->x || f_oldloc.y != plr->mo->y)
{
m_x = FTOM(MTOF(plr->mo->x)) - m_w/2;
m_y = FTOM(MTOF(plr->mo->y)) - m_h/2;
m_x2 = m_x + m_w;
m_y2 = m_y + m_h;
f_oldloc.x = plr->mo->x;
f_oldloc.y = plr->mo->y;
// m_x = FTOM(MTOF(plr->mo->x - m_w/2));
// m_y = FTOM(MTOF(plr->mo->y - m_h/2));
// m_x = plr->mo->x - m_w/2;
// m_y = plr->mo->y - m_h/2;
}
}
//
//
//
void AM_updateLightLev(void)
{
static nexttic = 0;
//static int litelevels[] = { 0, 3, 5, 6, 6, 7, 7, 7 };
static int litelevels[] = { 0, 4, 7, 10, 12, 14, 15, 15 };
static int litelevelscnt = 0;
// Change light level
if (amclock>nexttic)
{
lightlev = litelevels[litelevelscnt++];
if (litelevelscnt == sizeof(litelevels)/sizeof(int)) litelevelscnt = 0;
nexttic = amclock + 6 - (amclock % 6);
}
}
//
// Updates on Game Tick
//
void AM_Ticker (void)
{
if (!automapactive)
return;
amclock++;
if (followplayer)
AM_doFollowPlayer();
// Change the zoom if necessary
if (ftom_zoommul != FRACUNIT)
AM_changeWindowScale();
// Change x,y location
if (m_paninc.x || m_paninc.y)
AM_changeWindowLoc();
// Update light level
// AM_updateLightLev();
}
//
// Clear automap frame buffer.
//
void AM_clearFB(int color)
{
memset(fb, color, f_w*f_h);
}
//
// Automap clipping of lines.
//
// Based on Cohen-Sutherland clipping algorithm but with a slightly
// faster reject and precalculated slopes. If the speed is needed,
// use a hash algorithm to handle the common cases.
//
boolean
AM_clipMline
( mline_t* ml,
fline_t* fl )
{
enum
{
LEFT =1,
RIGHT =2,
BOTTOM =4,
TOP =8
};
register outcode1 = 0;
register outcode2 = 0;
register outside;
fpoint_t tmp;
int dx;
int dy;
#define DOOUTCODE(oc, mx, my) \
(oc) = 0; \
if ((my) < 0) (oc) |= TOP; \
else if ((my) >= f_h) (oc) |= BOTTOM; \
if ((mx) < 0) (oc) |= LEFT; \
else if ((mx) >= f_w) (oc) |= RIGHT;
// do trivial rejects and outcodes
if (ml->a.y > m_y2)
outcode1 = TOP;
else if (ml->a.y < m_y)
outcode1 = BOTTOM;
if (ml->b.y > m_y2)
outcode2 = TOP;
else if (ml->b.y < m_y)
outcode2 = BOTTOM;
if (outcode1 & outcode2)
return false; // trivially outside
if (ml->a.x < m_x)
outcode1 |= LEFT;
else if (ml->a.x > m_x2)
outcode1 |= RIGHT;
if (ml->b.x < m_x)
outcode2 |= LEFT;
else if (ml->b.x > m_x2)
outcode2 |= RIGHT;
if (outcode1 & outcode2)
return false; // trivially outside
// transform to frame-buffer coordinates.
fl->a.x = CXMTOF(ml->a.x);
fl->a.y = CYMTOF(ml->a.y);
fl->b.x = CXMTOF(ml->b.x);
fl->b.y = CYMTOF(ml->b.y);
DOOUTCODE(outcode1, fl->a.x, fl->a.y);
DOOUTCODE(outcode2, fl->b.x, fl->b.y);
if (outcode1 & outcode2)
return false;
while (outcode1 | outcode2)
{
// may be partially inside box
// find an outside point
if (outcode1)
outside = outcode1;
else
outside = outcode2;
// clip to each side
if (outside & TOP)
{
dy = fl->a.y - fl->b.y;
dx = fl->b.x - fl->a.x;
tmp.x = fl->a.x + (dx*(fl->a.y))/dy;
tmp.y = 0;
}
else if (outside & BOTTOM)
{
dy = fl->a.y - fl->b.y;
dx = fl->b.x - fl->a.x;
tmp.x = fl->a.x + (dx*(fl->a.y-f_h))/dy;
tmp.y = f_h-1;
}
else if (outside & RIGHT)
{
dy = fl->b.y - fl->a.y;
dx = fl->b.x - fl->a.x;
tmp.y = fl->a.y + (dy*(f_w-1 - fl->a.x))/dx;
tmp.x = f_w-1;
}
else if (outside & LEFT)
{
dy = fl->b.y - fl->a.y;
dx = fl->b.x - fl->a.x;
tmp.y = fl->a.y + (dy*(-fl->a.x))/dx;
tmp.x = 0;
}
if (outside == outcode1)
{
fl->a = tmp;
DOOUTCODE(outcode1, fl->a.x, fl->a.y);
}
else
{
fl->b = tmp;
DOOUTCODE(outcode2, fl->b.x, fl->b.y);
}
if (outcode1 & outcode2)
return false; // trivially outside
}
return true;
}
#undef DOOUTCODE
//
// Classic Bresenham w/ whatever optimizations needed for speed
//
void
AM_drawFline
( fline_t* fl,
int color )
{
register int x;
register int y;
register int dx;
register int dy;
register int sx;
register int sy;
register int ax;
register int ay;
register int d;
static fuck = 0;
// For debugging only
if ( fl->a.x < 0 || fl->a.x >= f_w
|| fl->a.y < 0 || fl->a.y >= f_h
|| fl->b.x < 0 || fl->b.x >= f_w
|| fl->b.y < 0 || fl->b.y >= f_h)
{
fprintf(stderr, "fuck %d \r", fuck++);
return;
}
#define PUTDOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(cc)
dx = fl->b.x - fl->a.x;
ax = 2 * (dx<0 ? -dx : dx);
sx = dx<0 ? -1 : 1;
dy = fl->b.y - fl->a.y;
ay = 2 * (dy<0 ? -dy : dy);
sy = dy<0 ? -1 : 1;
x = fl->a.x;
y = fl->a.y;
if (ax > ay)
{
d = ay - ax/2;
while (1)
{
PUTDOT(x,y,color);
if (x == fl->b.x) return;
if (d>=0)
{
y += sy;
d -= ax;
}
x += sx;
d += ay;
}
}
else
{
d = ax - ay/2;
while (1)
{
PUTDOT(x, y, color);
if (y == fl->b.y) return;
if (d >= 0)
{
x += sx;
d -= ay;
}
y += sy;
d += ax;
}
}
}
//
// Clip lines, draw visible part sof lines.
//
void
AM_drawMline
( mline_t* ml,
int color )
{
static fline_t fl;
if (AM_clipMline(ml, &fl))
AM_drawFline(&fl, color); // draws it on frame buffer using fb coords
}
//
// Draws flat (floor/ceiling tile) aligned grid lines.
//
void AM_drawGrid(int color)
{
fixed_t x, y;
fixed_t start, end;
mline_t ml;
// Figure out start of vertical gridlines
start = m_x;
if ((start-bmaporgx)%(MAPBLOCKUNITS<<FRACBITS))
start += (MAPBLOCKUNITS<<FRACBITS)
- ((start-bmaporgx)%(MAPBLOCKUNITS<<FRACBITS));
end = m_x + m_w;
// draw vertical gridlines
ml.a.y = m_y;
ml.b.y = m_y+m_h;
for (x=start; x<end; x+=(MAPBLOCKUNITS<<FRACBITS))
{
ml.a.x = x;
ml.b.x = x;
AM_drawMline(&ml, color);
}
// Figure out start of horizontal gridlines
start = m_y;
if ((start-bmaporgy)%(MAPBLOCKUNITS<<FRACBITS))
start += (MAPBLOCKUNITS<<FRACBITS)
- ((start-bmaporgy)%(MAPBLOCKUNITS<<FRACBITS));
end = m_y + m_h;
// draw horizontal gridlines
ml.a.x = m_x;
ml.b.x = m_x + m_w;
for (y=start; y<end; y+=(MAPBLOCKUNITS<<FRACBITS))
{
ml.a.y = y;
ml.b.y = y;
AM_drawMline(&ml, color);
}
}
//
// Determines visible lines, draws them.
// This is LineDef based, not LineSeg based.
//
void AM_drawWalls(void)
{
int i;
static mline_t l;
for (i=0;i<numlines;i++)
{
l.a.x = lines[i].v1->x;
l.a.y = lines[i].v1->y;
l.b.x = lines[i].v2->x;
l.b.y = lines[i].v2->y;
if (cheating || (lines[i].flags & ML_MAPPED))
{
if ((lines[i].flags & LINE_NEVERSEE) && !cheating)
continue;
if (!lines[i].backsector)
{
AM_drawMline(&l, WALLCOLORS+lightlev);
}
else
{
if (lines[i].special == 39)
{ // teleporters
AM_drawMline(&l, WALLCOLORS+WALLRANGE/2);
}
else if (lines[i].flags & ML_SECRET) // secret door
{
if (cheating) AM_drawMline(&l, SECRETWALLCOLORS + lightlev);
else AM_drawMline(&l, WALLCOLORS+lightlev);
}
else if (lines[i].backsector->floorheight
!= lines[i].frontsector->floorheight) {
AM_drawMline(&l, FDWALLCOLORS + lightlev); // floor level change
}
else if (lines[i].backsector->ceilingheight
!= lines[i].frontsector->ceilingheight) {
AM_drawMline(&l, CDWALLCOLORS+lightlev); // ceiling level change
}
else if (cheating) {
AM_drawMline(&l, TSWALLCOLORS+lightlev);
}
}
}
else if (plr->powers[pw_allmap])
{
if (!(lines[i].flags & LINE_NEVERSEE)) AM_drawMline(&l, GRAYS+3);
}
}
}
//
// Rotation in 2D.
// Used to rotate player arrow line character.
//
void
AM_rotate
( fixed_t* x,
fixed_t* y,
angle_t a )
{
fixed_t tmpx;
tmpx =
FixedMul(*x,finecosine[a>>ANGLETOFINESHIFT])
- FixedMul(*y,finesine[a>>ANGLETOFINESHIFT]);
*y =
FixedMul(*x,finesine[a>>ANGLETOFINESHIFT])
+ FixedMul(*y,finecosine[a>>ANGLETOFINESHIFT]);
*x = tmpx;
}
void
AM_drawLineCharacter
( mline_t* lineguy,
int lineguylines,
fixed_t scale,
angle_t angle,
int color,
fixed_t x,
fixed_t y )
{
int i;
mline_t l;
for (i=0;i<lineguylines;i++)
{
l.a.x = lineguy[i].a.x;
l.a.y = lineguy[i].a.y;
if (scale)
{
l.a.x = FixedMul(scale, l.a.x);
l.a.y = FixedMul(scale, l.a.y);
}
if (angle)
AM_rotate(&l.a.x, &l.a.y, angle);
l.a.x += x;
l.a.y += y;
l.b.x = lineguy[i].b.x;
l.b.y = lineguy[i].b.y;
if (scale)
{
l.b.x = FixedMul(scale, l.b.x);
l.b.y = FixedMul(scale, l.b.y);
}
if (angle)
AM_rotate(&l.b.x, &l.b.y, angle);
l.b.x += x;
l.b.y += y;
AM_drawMline(&l, color);
}
}
void AM_drawPlayers(void)
{
int i;
player_t* p;
static int their_colors[] = { GREENS, GRAYS, BROWNS, REDS };
int their_color = -1;
int color;
if (!netgame)
{
if (cheating)
AM_drawLineCharacter
(cheat_player_arrow, NUMCHEATPLYRLINES, 0,
plr->mo->angle, WHITE, plr->mo->x, plr->mo->y);
else
AM_drawLineCharacter
(player_arrow, NUMPLYRLINES, 0, plr->mo->angle,
WHITE, plr->mo->x, plr->mo->y);
return;
}
for (i=0;i<MAXPLAYERS;i++)
{
their_color++;
p = &players[i];
if ( (deathmatch && !singledemo) && p != plr)
continue;
if (!playeringame[i])
continue;
if (p->powers[pw_invisibility])
color = 246; // *close* to black
else
color = their_colors[their_color];
AM_drawLineCharacter
(player_arrow, NUMPLYRLINES, 0, p->mo->angle,
color, p->mo->x, p->mo->y);
}
}
void
AM_drawThings
( int colors,
int colorrange)
{
int i;
mobj_t* t;
for (i=0;i<numsectors;i++)
{
t = sectors[i].thinglist;
while (t)
{
AM_drawLineCharacter
(thintriangle_guy, NUMTHINTRIANGLEGUYLINES,
16<<FRACBITS, t->angle, colors+lightlev, t->x, t->y);
t = t->snext;
}
}
}
void AM_drawMarks(void)
{
int i, fx, fy, w, h;
for (i=0;i<AM_NUMMARKPOINTS;i++)
{
if (markpoints[i].x != -1)
{
// w = SHORT(marknums[i]->width);
// h = SHORT(marknums[i]->height);
w = 5; // because something's wrong with the wad, i guess
h = 6; // because something's wrong with the wad, i guess
fx = CXMTOF(markpoints[i].x);
fy = CYMTOF(markpoints[i].y);
if (fx >= f_x && fx <= f_w - w && fy >= f_y && fy <= f_h - h)
V_DrawPatch(fx, fy, FB, marknums[i]);
}
}
}
void AM_drawCrosshair(int color)
{
fb[(f_w*(f_h+1))/2] = color; // single point for now
}
void AM_Drawer (void)
{
if (!automapactive) return;
AM_clearFB(BACKGROUND);
if (grid)
AM_drawGrid(GRIDCOLORS);
AM_drawWalls();
AM_drawPlayers();
if (cheating==2)
AM_drawThings(THINGCOLORS, THINGRANGE);
AM_drawCrosshair(XHAIRCOLORS);
AM_drawMarks();
V_MarkRect(f_x, f_y, f_w, f_h);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -