Merge branch 'minigen' into 'master'

minigen

See merge request KartKrew/Kart!900
This commit is contained in:
Oni 2023-01-25 05:54:12 +00:00
commit f57dd43e36
16 changed files with 658 additions and 170 deletions

View file

@ -26,43 +26,39 @@
#endif
// For use if I do walls with outsides/insides
static const UINT8 REDS = (8*16);
static const UINT8 REDS = (2*16);
static const UINT8 REDRANGE = 16;
static const UINT8 GRAYS = (1*16);
static const UINT8 GRAYSRANGE = 16;
static const UINT8 BROWNS = (3*16);
static const UINT8 YELLOWS = (7*16);
static const UINT8 GREENS = (10*16);
static const UINT8 BROWNS = (15*16);
static const UINT8 YELLOWS = (5*16)+8;
static const UINT8 GREENS = (6*16);
static const UINT8 CYANS = (8*16);
static const UINT8 BLUES = (9*16);
static const UINT8 DBLACK = 31;
static const UINT8 DWHITE = 0;
static const UINT8 NOCLIMBREDS = 248;
static const UINT8 NOCLIMBREDRANGE = 8;
static const UINT8 NOCLIMBGRAYS = 204;
static const UINT8 NOCLIMBBROWNS = (2*16);
static const UINT8 NOCLIMBYELLOWS = (11*16);
// Automap colors
#define BACKGROUND DBLACK
#define WALLCOLORS (REDS + REDRANGE/2)
#define WALLRANGE (REDRANGE/2)
#define NOCLIMBWALLCOLORS (NOCLIMBREDS + NOCLIMBREDRANGE/2)
#define NOCLIMBWALLRANGE (NOCLIMBREDRANGE/2)
#define THOKWALLCOLORS REDS
#define THOKWALLRANGE REDRANGE
#define NOCLIMBTHOKWALLCOLORS NOCLIMBREDS
#define NOCLIMBTHOKWALLRANGE NOCLIMBREDRANGE
#define TSWALLCOLORS GRAYS
#define TSWALLRANGE GRAYSRANGE
#define NOCLIMBTSWALLCOLORS NOCLIMBGRAYS
#define TSWALLCOLORS DWHITE
#define TSFINISHLINE GRAYS
#define TSTRIPWIRE (CYANS + 4)
#define TSFOFINFO (BLUES + 4)
#define FDWALLCOLORS BROWNS
#define NOCLIMBFDWALLCOLORS NOCLIMBBROWNS
#define CDWALLCOLORS YELLOWS
#define NOCLIMBCDWALLCOLORS NOCLIMBYELLOWS
#define THINGCOLORS GREENS
#define GRIDCOLORS (GRAYS + GRAYSRANGE/2)
#define XHAIRCOLORS DWHITE
#define XHAIRCOLORS GRAYS
// Automap passes
#define PASS_SOLID 1
#define PASS_INTANGIBLE 2
#define PASS_FOF 4
// controls
#define AM_PANUPKEY KEY_UPARROW
@ -156,6 +152,9 @@ static boolean draw_grid = false;
boolean automapactive = false;
boolean am_recalc = false; //added : 05-02-98 : true when screen size changes
static boolean am_stopped = true;
static boolean am_minigen = false;
static UINT8 *am_buf = NULL;
static INT32 f_x, f_y; // location of window on screen (always zero for both)
static INT32 f_w, f_h; // size of window on screen (always the screen width and height respectively)
@ -256,28 +255,15 @@ static inline void AM_restoreScaleAndLoc(void)
*/
static void AM_findMinMaxBoundaries(void)
{
size_t i;
fixed_t a;
fixed_t b;
fixed_t a, b;
min_x = min_y = +INT32_MAX;
max_x = max_y = -INT32_MAX;
min_x = minimapinfo.min_x << MAPBITS;
max_x = minimapinfo.max_x << MAPBITS;
min_y = minimapinfo.min_y << MAPBITS;
max_y = minimapinfo.max_y << MAPBITS;
for (i = 0; i < numvertexes; i++)
{
if (vertexes[i].x < min_x)
min_x = vertexes[i].x;
else if (vertexes[i].x > max_x)
max_x = vertexes[i].x;
if (vertexes[i].y < min_y)
min_y = vertexes[i].y;
else if (vertexes[i].y > max_y)
max_y = vertexes[i].y;
}
max_w = (max_x >>= FRACTOMAPBITS) - (min_x >>= FRACTOMAPBITS);
max_h = (max_y >>= FRACTOMAPBITS) - (min_y >>= FRACTOMAPBITS);
max_w = minimapinfo.map_w << MAPBITS;
max_h = minimapinfo.map_h << MAPBITS;
a = FixedDiv(f_w<<FRACBITS, max_w);
b = FixedDiv(f_h<<FRACBITS, max_h);
@ -354,6 +340,7 @@ static void AM_FrameBufferInit(void)
f_x = f_y = 0;
f_w = vid.width;
f_h = vid.height;
am_buf = screens[0];
}
//
@ -784,10 +771,9 @@ static boolean AM_clipMline(const mline_t *ml, fline_t *fl)
//
static void AM_drawPixel(INT32 xx, INT32 yy, INT32 cc)
{
UINT8 *dest = screens[0];
if (xx < 0 || yy < 0 || xx >= vid.width || yy >= vid.height)
if (xx < 0 || yy < 0 || xx >= f_w || yy >= f_h)
return; // off the screen
dest[(yy*vid.width) + xx] = cc;
am_buf[(yy*f_w) + xx] = cc;
}
//
@ -912,14 +898,93 @@ static void AM_drawGrid(INT32 color)
}
}
#define SLOPEPARAMS(slope, end1, end2, normalheight) \
end1 = (P_GetZAt(slope, lines[i].v1->x, lines[i].v1->y, normalheight) + FRACUNIT/2) >> FRACBITS; \
end2 = (P_GetZAt(slope, lines[i].v2->x, lines[i].v2->y, normalheight) + FRACUNIT/2) >> FRACBITS;
static ffloor_t *AM_CompareFOFs(size_t i, ffloor_t *rover, ffloor_t *secondarystore)
{
ffloor_t *secondaryrover = NULL;
for (; rover; rover = rover->next)
{
fixed_t rovt1, rovt2;
fixed_t rovb1, rovb2;
if (!(rover->fofflags & FOF_EXISTS))
continue;
if (!(rover->fofflags & FOF_BLOCKPLAYER))
continue;
SLOPEPARAMS(*rover->t_slope, rovt1, rovt2, *rover->topheight)
SLOPEPARAMS(*rover->b_slope, rovb1, rovb2, *rover->bottomheight)
for (secondaryrover = secondarystore; secondaryrover; secondaryrover = secondaryrover->next)
{
fixed_t sect1, sect2;
fixed_t secb1, secb2;
terrain_t *terrain1 = NULL;
terrain_t *terrain2 = NULL;
if (!(secondaryrover->fofflags & FOF_EXISTS))
continue;
if (!(secondaryrover->fofflags & FOF_BLOCKPLAYER))
continue;
if (secondaryrover->secnum == rover->secnum)
break;
SLOPEPARAMS(*secondaryrover->t_slope, sect1, sect2, *secondaryrover->topheight)
SLOPEPARAMS(*secondaryrover->b_slope, secb1, secb2, *secondaryrover->bottomheight)
if (rovt1 != sect1)
continue;
if (rovt2 != sect2)
continue;
if (rovb1 != secb1)
continue;
if (rovb2 != secb2)
continue;
if (sectors[rover->secnum].damagetype != sectors[secondaryrover->secnum].damagetype
|| sectors[rover->secnum].friction != sectors[secondaryrover->secnum].friction
|| sectors[rover->secnum].offroad != sectors[secondaryrover->secnum].offroad)
continue;
if (*rover->toppic != *secondaryrover->toppic)
{
terrain1 = K_GetTerrainForFlatNum(*rover->toppic);
terrain2 = K_GetTerrainForFlatNum(*secondaryrover->toppic);
}
else if (*rover->bottompic != *secondaryrover->bottompic)
{
terrain1 = K_GetTerrainForFlatNum(*rover->bottompic);
terrain2 = K_GetTerrainForFlatNum(*secondaryrover->bottompic);
}
if ((terrain1 && K_TerrainHasAffect(terrain1, false))
|| (terrain2 && K_TerrainHasAffect(terrain2, false)))
continue;
break;
}
if (secondaryrover == NULL)
break;
}
return rover;
}
//
// Determines visible lines, draws them.
// This is LineDef based, not LineSeg based.
//
static inline void AM_drawWalls(void)
static void AM_drawWalls(UINT8 pass)
{
size_t i;
static mline_t l;
const fixed_t maxstep = P_BaseStepUp()>>FRACBITS;
fixed_t frontf1,frontf2, frontc1, frontc2; // front floor/ceiling ends
fixed_t backf1 = 0, backf2 = 0, backc1 = 0, backc2 = 0; // back floor ceiling ends
@ -930,71 +995,180 @@ static inline void AM_drawWalls(void)
l.b.x = lines[i].v2->x >> FRACTOMAPBITS;
l.b.y = lines[i].v2->y >> FRACTOMAPBITS;
#define SLOPEPARAMS(slope, end1, end2, normalheight) \
end1 = P_GetZAt(slope, lines[i].v1->x, lines[i].v1->y, normalheight); \
end2 = P_GetZAt(slope, lines[i].v2->x, lines[i].v2->y, normalheight);
SLOPEPARAMS(lines[i].frontsector->f_slope, frontf1, frontf2, lines[i].frontsector->floorheight)
SLOPEPARAMS(lines[i].frontsector->c_slope, frontc1, frontc2, lines[i].frontsector->ceilingheight)
if (lines[i].backsector) {
SLOPEPARAMS(lines[i].backsector->f_slope, backf1, backf2, lines[i].backsector->floorheight)
SLOPEPARAMS(lines[i].backsector->c_slope, backc1, backc2, lines[i].backsector->ceilingheight)
}
#undef SLOPEPARAMS
if (!lines[i].backsector) // 1-sided
{
if (lines[i].flags & ML_NOCLIMB)
AM_drawMline(&l, NOCLIMBWALLCOLORS);
else
if (!(pass & PASS_SOLID))
;
else if (frontf1 != frontc1 || frontf2 != frontc2 || lines[i].frontsector->f_slope)
{
AM_drawMline(&l, TSWALLCOLORS);
}
else if (!am_minigen)
{
AM_drawMline(&l, WALLCOLORS);
}
continue;
}
else if ((backf1 == backc1 && backf2 == backc2) // Back is thok barrier
SLOPEPARAMS(lines[i].backsector->f_slope, backf1, backf2, lines[i].backsector->floorheight)
SLOPEPARAMS(lines[i].backsector->c_slope, backc1, backc2, lines[i].backsector->ceilingheight)
if ((backf1 == backc1 && backf2 == backc2) // Back is thok barrier
|| (frontf1 == frontc1 && frontf2 == frontc2)) // Front is thok barrier
{
if (backf1 == backc1 && backf2 == backc2
&& frontf1 == frontc1 && frontf2 == frontc2) // BOTH are thok barriers
{
if (lines[i].flags & ML_NOCLIMB)
AM_drawMline(&l, NOCLIMBTSWALLCOLORS);
else
AM_drawMline(&l, TSWALLCOLORS);
if (!am_minigen && (pass & PASS_INTANGIBLE))
{
AM_drawMline(&l, GRIDCOLORS);
}
}
else
else if (pass & PASS_SOLID)
{
if (lines[i].flags & ML_NOCLIMB)
AM_drawMline(&l, NOCLIMBTHOKWALLCOLORS);
else
AM_drawMline(&l, THOKWALLCOLORS);
AM_drawMline(&l, TSWALLCOLORS);
}
}
else
{
if (lines[i].flags & ML_NOCLIMB) {
if (backf1 != frontf1 || backf2 != frontf2) {
AM_drawMline(&l, NOCLIMBFDWALLCOLORS); // floor level change
}
else if (backc1 != frontc1 || backc2 != frontc2) {
AM_drawMline(&l, NOCLIMBCDWALLCOLORS); // ceiling level change
if (lines[i].flags & (ML_IMPASSABLE|ML_BLOCKPLAYERS))
{
if (pass & PASS_SOLID)
AM_drawMline(&l, TSWALLCOLORS); // Completely solid course boundary
}
else if ((lines[i].flags & ML_MIDSOLID)
&& sides[lines->sidenum[0]].midtexture)
{
if (pass & PASS_SOLID)
AM_drawMline(&l, TSWALLCOLORS); // solid midtexture, likely a course boundary
}
if ((backf1 != frontf1 && abs(backf1 - frontf1) > maxstep)
|| (backf2 != frontf2 && abs(backf2 - frontf2) > maxstep))
{
if (pass & PASS_SOLID)
AM_drawMline(&l, TSWALLCOLORS); // floor-wall, likely a course boundary
}
else if (lines[i].special == 2001)
{
if (pass & PASS_SOLID)
AM_drawMline(&l, TSFINISHLINE); // finish line
}
else if (P_IsLineTripWire(&lines[i]))
{
if (pass & PASS_SOLID)
AM_drawMline(&l, TSTRIPWIRE); // tripwire shortcut
}
else if (backf1 != frontf1 || backf2 != frontf2)
{
if (pass & PASS_INTANGIBLE)
AM_drawMline(&l, FDWALLCOLORS); // floorlevel change
}
else if (backc1 != frontc1 || backc2 != frontc2)
{
if (!(pass & PASS_INTANGIBLE))
;
else if (abs(backc1 - frontc1) < maxstep
|| abs(backc2 - frontc2) < maxstep)
{
AM_drawMline(&l, CDWALLCOLORS); // ceilinglevel change
}
else
AM_drawMline(&l, NOCLIMBTSWALLCOLORS);
{
AM_drawMline(&l, GRIDCOLORS); // ceiling-wall, not likely to be a course boundary but flagged up just in case
}
}
else if (lines[i].frontsector->damagetype != lines[i].backsector->damagetype
|| lines[i].frontsector->friction != lines[i].backsector->friction
|| lines[i].frontsector->offroad != lines[i].backsector->offroad)
{
if (pass & PASS_INTANGIBLE)
AM_drawMline(&l, FDWALLCOLORS); // Functionality boundary
}
else
{
if (backf1 != frontf1 || backf2 != frontf2) {
AM_drawMline(&l, FDWALLCOLORS); // floor level change
terrain_t *terrain1 = NULL;
terrain_t *terrain2 = NULL;
UINT8 defercol = GRIDCOLORS;
if (lines[i].frontsector->floorpic != lines[i].backsector->floorpic)
{
terrain1 = K_GetTerrainForFlatNum(lines[i].frontsector->floorpic);
terrain2 = K_GetTerrainForFlatNum(lines[i].backsector->floorpic);
defercol = FDWALLCOLORS; // possible floor offroad boundary
}
else if (backc1 != frontc1 || backc2 != frontc2) {
AM_drawMline(&l, CDWALLCOLORS); // ceiling level change
else if (lines[i].frontsector->ceilingpic != lines[i].backsector->ceilingpic)
{
terrain1 = K_GetTerrainForFlatNum(lines[i].frontsector->ceilingpic);
terrain2 = K_GetTerrainForFlatNum(lines[i].backsector->ceilingpic);
defercol = CDWALLCOLORS; // possible ceiling offroad boundary
}
if ((terrain1 && K_TerrainHasAffect(terrain1, false))
|| (terrain2 && K_TerrainHasAffect(terrain2, false)))
{
if (pass & PASS_INTANGIBLE)
AM_drawMline(&l, defercol); // Yep, definitely a functionality boundary
}
else
AM_drawMline(&l, TSWALLCOLORS);
{
ffloor_t *rover = NULL;
if (lines[i].frontsector->ffloors || lines[i].backsector->ffloors)
{
if (lines[i].backsector->ffloors == NULL)
{
// Check frontside for one solid
for (rover = lines[i].frontsector->ffloors; rover; rover = rover->next)
{
if (!(rover->fofflags & FOF_EXISTS))
continue;
if (!(rover->fofflags & FOF_BLOCKPLAYER))
continue;
break;
}
}
else if (lines[i].frontsector->ffloors == NULL)
{
// Check backside for one solid
for (rover = lines[i].backsector->ffloors; rover; rover = rover->next)
{
if (!(rover->fofflags & FOF_EXISTS))
continue;
if (!(rover->fofflags & FOF_BLOCKPLAYER))
continue;
break;
}
}
else
{
// Check to see if any secnums exist in one but not the other.
rover = AM_CompareFOFs(i, lines[i].frontsector->ffloors, lines[i].backsector->ffloors);
if (rover == NULL)
rover = AM_CompareFOFs(i, lines[i].backsector->ffloors, lines[i].frontsector->ffloors);
}
}
if (rover != NULL)
{
if (pass & PASS_FOF)
AM_drawMline(&l, TSFOFINFO); // a FOF is here but we don't know how to distinguish them yet
}
else if (!am_minigen)
{
if (pass & PASS_INTANGIBLE)
AM_drawMline(&l, GRIDCOLORS); // likely low-relevance line
}
}
}
}
}
}
#undef SLOPEPARAMS
//
// Rotation in 2D.
// Used to rotate player arrow line character.
@ -1065,13 +1239,6 @@ static inline void AM_drawPlayers(void)
player_t *p;
INT32 color = GREENS;
if (!multiplayer)
{
AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 16<<FRACBITS, plr->mo->angle, DWHITE, plr->mo->x, plr->mo->y);
return;
}
// multiplayer (how??)
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
@ -1095,7 +1262,46 @@ static inline void AM_drawThings(UINT8 colors)
t = sectors[i].thinglist;
while (t)
{
AM_drawLineCharacter(thintriangle_guy, NUMTHINTRIANGLEGUYLINES, 16<<FRACBITS, t->angle, colors, t->x, t->y);
if (!t->player)
AM_drawLineCharacter(thintriangle_guy, NUMTHINTRIANGLEGUYLINES, 16<<FRACBITS, t->angle, colors, t->x, t->y);
t = t->snext;
}
}
}
static inline void AM_drawSpecialThingsOnly(UINT8 colors)
{
size_t i;
for (i = 0; i < numsectors; i++)
{
terrain_t *terrain = NULL;
mobj_t *t = NULL;
if (sectors[i].damagetype != 0
|| sectors[i].friction < ORIG_FRICTION
|| sectors[i].offroad != 0)
continue;
terrain = K_GetTerrainForFlatNum(sectors[i].floorpic);
if (!terrain)
terrain = K_GetTerrainForFlatNum(sectors[i].ceilingpic);
if (terrain && K_TerrainHasAffect(terrain, true))
continue;
t = sectors[i].thinglist;
while (t)
{
if (t->type == MT_RANDOMITEM
|| t->type == MT_PAPERITEMSPOT
|| t->type == MT_OVERTIME_CENTER
|| t->type == MT_RING
|| t->type == MT_BLUESPHERE
|| t->type == MT_WAYPOINT
|| t->type == MT_ITEMCAPSULE
|| t->flags & MF_SPRING)
AM_drawLineCharacter(thintriangle_guy, NUMTHINTRIANGLEGUYLINES, 16<<FRACBITS, t->angle, colors, t->x, t->y);
t = t->snext;
}
}
@ -1142,9 +1348,73 @@ void AM_Drawer(void)
AM_clearFB(BACKGROUND);
if (draw_grid) AM_drawGrid(GRIDCOLORS);
AM_drawWalls();
AM_drawPlayers();
AM_drawWalls(PASS_FOF|PASS_INTANGIBLE|PASS_SOLID);
AM_drawThings(THINGCOLORS);
AM_drawPlayers();
if (!followplayer) AM_drawCrosshair(XHAIRCOLORS);
}
minigen_t *AM_MinimapGenerate(INT32 mul)
{
static minigen_t ret = {0};
if (automapactive)
return NULL;
am_minigen = true;
AM_drawFline = AM_drawFline_soft; // yes, even in GL
//AM_FrameBufferInit();
f_x = f_y = 0;
ret.w = f_w = minimapinfo.minimap_w * mul;
ret.h = f_h = minimapinfo.minimap_h * mul;
am_buf = ret.buf = NULL;
//AM_LevelInit();
AM_findMinMaxBoundaries();
scale_mtof = min_scale_mtof - (min_scale_mtof/20);
scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
//AM_initVariables();
f_oldloc.x = INT32_MAX;
m_paninc.x = m_paninc.y = 0;
ftom_zoommul = FRACUNIT;
mtof_zoommul = FRACUNIT;
m_w = FTOM(f_w);
m_h = FTOM(f_h);
//AM_changeWindowLoc();
m_x = min_x - FixedMul(m_w, FRACUNIT/40);
m_y = min_y - FixedMul(m_h, FRACUNIT/40);
m_x2 = m_x + m_w;
m_y2 = m_y + m_h;
// for saving & restoring
old_m_x = m_x;
old_m_y = m_y;
old_m_w = m_w;
old_m_h = m_h;
am_buf = ret.buf = malloc((f_w*f_h));
if (ret.buf == NULL)
return NULL;
//AM_clearFB(BACKGROUND);
memset(am_buf, 0xff, (f_w*f_h));
AM_drawSpecialThingsOnly(BACKGROUND);
AM_drawWalls(PASS_FOF);
AM_drawWalls(PASS_INTANGIBLE);
AM_drawWalls(PASS_SOLID);
am_buf = NULL;
am_recalc = true;
am_minigen = false;
return &ret;
}

View file

@ -48,6 +48,15 @@ void AM_Start(void);
// Called to force the automap to quit if the level is completed while it is up.
void AM_Stop(void);
struct minigen_t
{
INT32 w, h;
UINT8 *buf;
};
// Minimap generation
minigen_t *AM_MinimapGenerate(INT32 mul);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -895,6 +895,7 @@ void D_RegisterClientCommands(void)
COM_AddCommand("screenshot", M_ScreenShot);
COM_AddCommand("startmovie", Command_StartMovie_f);
COM_AddCommand("stopmovie", Command_StopMovie_f);
COM_AddCommand("minigen", M_MinimapGenerate);
CV_RegisterVar(&cv_screenshot_option);
CV_RegisterVar(&cv_screenshot_folder);

View file

@ -5272,6 +5272,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_ANGLEMAN",
"MT_POLYANCHOR",
"MT_POLYSPAWN",
"MT_MINIMAPBOUND",
// Skybox objects
"MT_SKYBOX",

View file

@ -2398,7 +2398,8 @@ static void HU_DrawRankings(void)
UINT32 whiteplayer = MAXPLAYERS;
boolean timedone = false, pointsdone = false;
V_DrawFadeScreen(0xFF00, 16); // A little more readable, and prevents cheating the fades under other circumstances.
if (!automapactive)
V_DrawFadeScreen(0xFF00, 16); // A little more readable, and prevents cheating the fades under other circumstances.
// draw the current gametype in the lower right
if (grandprixinfo.gp == true)

View file

@ -21497,6 +21497,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_MINIMAPBOUND
770, // doomednum
S_INVISIBLE, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
12*FRACUNIT, // radius
24*FRACUNIT, // height
0, // display offset
10, // mass
0, // damage
sfx_None, // activesound
MF_SCENERY|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
S_NULL // raisestate
},
{ // MT_SKYBOX
780, // doomednum
S_INVISIBLE, // spawnstate

View file

@ -6340,6 +6340,7 @@ typedef enum mobj_type
MT_ANGLEMAN,
MT_POLYANCHOR,
MT_POLYSPAWN,
MT_MINIMAPBOUND,
// Skybox objects
MT_SKYBOX,

View file

@ -3733,7 +3733,7 @@ static void K_drawKartNameTags(void)
}
}
static void K_drawKartMinimapIcon(fixed_t objx, fixed_t objy, INT32 hudx, INT32 hudy, INT32 flags, patch_t *icon, UINT8 *colormap, patch_t *AutomapPic)
static void K_drawKartMinimapIcon(fixed_t objx, fixed_t objy, INT32 hudx, INT32 hudy, INT32 flags, patch_t *icon, UINT8 *colormap)
{
// amnum xpos & ypos are the icon's speed around the HUD.
// The number being divided by is for how fast it moves.
@ -3745,71 +3745,21 @@ static void K_drawKartMinimapIcon(fixed_t objx, fixed_t objy, INT32 hudx, INT32
fixed_t amnumxpos, amnumypos;
INT32 amxpos, amypos;
node_t *bsp = &nodes[numnodes-1];
fixed_t maxx, minx, maxy, miny;
fixed_t mapwidth, mapheight;
fixed_t xoffset, yoffset;
fixed_t xscale, yscale, zoom;
maxx = maxy = INT32_MAX;
minx = miny = INT32_MIN;
minx = bsp->bbox[0][BOXLEFT];
maxx = bsp->bbox[0][BOXRIGHT];
miny = bsp->bbox[0][BOXBOTTOM];
maxy = bsp->bbox[0][BOXTOP];
if (bsp->bbox[1][BOXLEFT] < minx)
minx = bsp->bbox[1][BOXLEFT];
if (bsp->bbox[1][BOXRIGHT] > maxx)
maxx = bsp->bbox[1][BOXRIGHT];
if (bsp->bbox[1][BOXBOTTOM] < miny)
miny = bsp->bbox[1][BOXBOTTOM];
if (bsp->bbox[1][BOXTOP] > maxy)
maxy = bsp->bbox[1][BOXTOP];
// You might be wondering why these are being bitshift here
// it's because mapwidth and height would otherwise overflow for maps larger than half the size possible...
// map boundaries and sizes will ALWAYS be whole numbers thankfully
// later calculations take into consideration that these are actually not in terms of FRACUNIT though
minx >>= FRACBITS;
maxx >>= FRACBITS;
miny >>= FRACBITS;
maxy >>= FRACBITS;
mapwidth = maxx - minx;
mapheight = maxy - miny;
// These should always be small enough to be bitshift back right now
xoffset = (minx + mapwidth/2)<<FRACBITS;
yoffset = (miny + mapheight/2)<<FRACBITS;
xscale = FixedDiv(AutomapPic->width, mapwidth);
yscale = FixedDiv(AutomapPic->height, mapheight);
zoom = FixedMul(min(xscale, yscale), FRACUNIT-FRACUNIT/20);
amnumxpos = (FixedMul(objx, zoom) - FixedMul(xoffset, zoom));
amnumypos = -(FixedMul(objy, zoom) - FixedMul(yoffset, zoom));
amnumxpos = (FixedMul(objx, minimapinfo.zoom) - minimapinfo.offs_x);
amnumypos = -(FixedMul(objy, minimapinfo.zoom) - minimapinfo.offs_y);
if (encoremode)
amnumxpos = -amnumxpos;
amxpos = amnumxpos + ((hudx + AutomapPic->width/2 - (icon->width/2))<<FRACBITS);
amypos = amnumypos + ((hudy + AutomapPic->height/2 - (icon->height/2))<<FRACBITS);
// do we want this? it feels unnecessary. easier to just modify the amnumxpos?
/*if (encoremode)
{
flags |= V_FLIP;
amxpos = -amnumxpos + ((hudx + AutomapPic->width/2 + (icon->width/2))<<FRACBITS);
}*/
amxpos = amnumxpos + ((hudx + (SHORT(minimapinfo.minimap_pic->width)-SHORT(icon->width))/2)<<FRACBITS);
amypos = amnumypos + ((hudy + (SHORT(minimapinfo.minimap_pic->height)-SHORT(icon->height))/2)<<FRACBITS);
V_DrawFixedPatch(amxpos, amypos, FRACUNIT, flags, icon, colormap);
}
static void K_drawKartMinimap(void)
{
patch_t *AutomapPic, *workingPic;
patch_t *workingPic;
INT32 i = 0;
INT32 x, y;
INT32 minimaptrans = 4;
@ -3831,9 +3781,7 @@ static void K_drawKartMinimap(void)
if (stplyr != &players[displayplayers[0]])
return;
AutomapPic = mapheaderinfo[gamemap-1]->minimapPic;
if (!AutomapPic)
if (minimapinfo.minimap_pic == NULL)
{
return; // no pic, just get outta here
}
@ -3856,28 +3804,25 @@ static void K_drawKartMinimap(void)
if (!minimaptrans)
return;
x = MINI_X - (AutomapPic->width/2);
y = MINI_Y - (AutomapPic->height/2);
x = MINI_X - (SHORT(minimapinfo.minimap_pic->width)/2);
y = MINI_Y - (SHORT(minimapinfo.minimap_pic->height)/2);
minimaptrans = ((10-minimaptrans)<<FF_TRANSSHIFT);
splitflags |= minimaptrans;
if (encoremode)
V_DrawScaledPatch(x+(AutomapPic->width), y, splitflags|V_FLIP, AutomapPic);
V_DrawScaledPatch(x+SHORT(minimapinfo.minimap_pic->width), y, splitflags|minimaptrans|V_FLIP, minimapinfo.minimap_pic);
else
V_DrawScaledPatch(x, y, splitflags, AutomapPic);
V_DrawScaledPatch(x, y, splitflags|minimaptrans, minimapinfo.minimap_pic);
{
splitflags &= ~minimaptrans;
splitflags |= V_HUDTRANSHALF;
}
// most icons will be rendered semi-ghostly.
splitflags |= V_HUDTRANSHALF;
// let offsets transfer to the heads, too!
if (encoremode)
x += SHORT(AutomapPic->leftoffset);
x += SHORT(minimapinfo.minimap_pic->leftoffset);
else
x -= SHORT(AutomapPic->leftoffset);
y -= SHORT(AutomapPic->topoffset);
x -= SHORT(minimapinfo.minimap_pic->leftoffset);
y -= SHORT(minimapinfo.minimap_pic->topoffset);
// Draw the super item in Battle
if ((gametyperules & GTR_OVERTIME) && battleovertime.enabled)
@ -3888,7 +3833,7 @@ static void K_drawKartMinimap(void)
splitflags &= ~V_HUDTRANSHALF;
splitflags |= V_HUDTRANS;
colormap = R_GetTranslationColormap(TC_RAINBOW, K_RainbowColor(leveltime), GTC_CACHE);
K_drawKartMinimapIcon(battleovertime.x, battleovertime.y, x, y, splitflags, kp_itemminimap, colormap, AutomapPic);
K_drawKartMinimapIcon(battleovertime.x, battleovertime.y, x, y, splitflags, kp_itemminimap, colormap);
splitflags = prevsplitflags;
}
}
@ -3920,7 +3865,7 @@ static void K_drawKartMinimap(void)
interpx = R_InterpolateFixed(g->mo->old_x, g->mo->x);
interpy = R_InterpolateFixed(g->mo->old_y, g->mo->y);
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, faceprefix[skin][FACE_MINIMAP], colormap, AutomapPic);
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, faceprefix[skin][FACE_MINIMAP], colormap);
g = g->next;
}
@ -3987,13 +3932,13 @@ static void K_drawKartMinimap(void)
interpx = R_InterpolateFixed(mobj->old_x, mobj->x);
interpy = R_InterpolateFixed(mobj->old_y, mobj->y);
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, faceprefix[skin][FACE_MINIMAP], colormap, AutomapPic);
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, faceprefix[skin][FACE_MINIMAP], colormap);
// Target reticule
if (((gametyperules & GTR_CIRCUIT) && players[i].position == spbplace)
|| ((gametyperules & (GTR_BOSS|GTR_POINTLIMIT)) == GTR_POINTLIMIT && K_IsPlayerWanted(&players[i])))
{
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, kp_wantedreticle, NULL, AutomapPic);
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, kp_wantedreticle, NULL);
}
}
}
@ -4039,7 +3984,7 @@ static void K_drawKartMinimap(void)
interpx = R_InterpolateFixed(mobj->old_x, mobj->x);
interpy = R_InterpolateFixed(mobj->old_y, mobj->y);
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, workingPic, colormap, AutomapPic);
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, workingPic, colormap);
}
// draw our local players here, opaque.
@ -4072,7 +4017,7 @@ static void K_drawKartMinimap(void)
interpy = R_InterpolateFixed(bossinfo.weakspots[i].spot->old_y, bossinfo.weakspots[i].spot->y);
// temporary graphic?
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, kp_wantedreticle, colormap, AutomapPic);
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, kp_wantedreticle, colormap);
}
}
@ -4114,13 +4059,13 @@ static void K_drawKartMinimap(void)
interpx = R_InterpolateFixed(mobj->old_x, mobj->x);
interpy = R_InterpolateFixed(mobj->old_y, mobj->y);
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, workingPic, colormap, AutomapPic);
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, workingPic, colormap);
// Target reticule
if (((gametyperules & GTR_CIRCUIT) && players[localplayers[i]].position == spbplace)
|| ((gametyperules & (GTR_BOSS|GTR_POINTLIMIT)) == GTR_POINTLIMIT && K_IsPlayerWanted(&players[localplayers[i]])))
{
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, kp_wantedreticle, NULL, AutomapPic);
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, kp_wantedreticle, NULL);
}
}
}

View file

@ -1536,6 +1536,30 @@ static void K_TerrainDefaults(terrain_t *terrain)
terrain->flags = 0;
}
/*--------------------------------------------------
boolean K_TerrainHasAffect(terrain_t *terrain)
See header file for description.
--------------------------------------------------*/
boolean K_TerrainHasAffect(terrain_t *terrain, boolean badonly)
{
if (terrain->friction > 0
|| terrain->offroad != 0
|| terrain->damageType != -1
|| (terrain->flags & TRF_STAIRJANK))
return true;
if (badonly)
return false;
return (terrain->friction != 0
|| terrain->trickPanel != 0
|| terrain->speedPad != 0
|| terrain->springStrength != 0
|| terrain->flags != 0);
}
/*--------------------------------------------------
static void K_NewTerrainDefs(void)

View file

@ -569,6 +569,21 @@ void K_UpdateTerrainOverlay(mobj_t *mo);
void K_InitTerrain(UINT16 wadNum);
/*--------------------------------------------------
boolean K_TerrainHasAffect(terrain_t *terrain, boolean badonly)
Checks if Terrain block has a gameplay-affecting property.
Input Arguments:-
terrain - Terrain structure to compare with default.
badonly - Only checks for negative properties if true
Return:-
false if functionally default, otherwise true.
--------------------------------------------------*/
boolean K_TerrainHasAffect(terrain_t *terrain, boolean badonly);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -247,8 +247,8 @@ boolean cht_Responder(event_t *ev)
#define REQUIRE_INLEVEL if (gamestate != GS_LEVEL || demo.playback)\
{ CONS_Printf(M_GetText("You must be in a level to use this.\n")); return; }
#define REQUIRE_SINGLEPLAYER if (netgame || multiplayer)\
{ CONS_Printf(M_GetText("This only works in single player.\n")); return; }
#define REQUIRE_SINGLEPLAYER if (netgame)\
{ CONS_Printf(M_GetText("This only works offline.\n")); return; }
// command that can be typed at the console!
void Command_CheatNoClip_f(void)

View file

@ -1749,6 +1749,83 @@ boolean M_ScreenshotResponder(event_t *ev)
return true;
}
void M_MinimapGenerate(void)
{
#ifdef USE_PNG
char *filepath;
boolean ret = false;
minigen_t *minigen = NULL;
size_t option_scale;
INT32 mul = 1;
if (gamestate != GS_LEVEL)
{
CONS_Alert(CONS_ERROR, "You must be in a level to generate a preliminary minimap!\n");
return;
}
if (automapactive)
{
CONS_Alert(CONS_ERROR, "The automap is active! Please deactivate it and try again.\n");
return;
}
option_scale = COM_CheckPartialParm("-m");
if (option_scale)
{
if (COM_Argc() < option_scale + 2)/* no argument after? */
{
CONS_Alert(CONS_ERROR,
"No multiplier follows parameter '%s'.\n",
COM_Argv(option_scale));
return;
}
mul = atoi(COM_Argv(option_scale + 1));
if (mul < 1 || mul > 10)
{
CONS_Alert(CONS_ERROR,
"Multiplier %d must be within range 1-10.\n",
mul);
return;
}
filepath = va("%s" PATHSEP "MINIMAP-%d.png", srb2home, mul);
}
else
{
filepath = va("%s" PATHSEP "MINIMAP.png", srb2home);
}
minigen = AM_MinimapGenerate(mul);
if (minigen == NULL || minigen->buf == NULL)
goto failure;
M_CreateScreenShotPalette();
ret = M_SavePNG(filepath, minigen->buf, minigen->w, minigen->h, screenshot_palette);
failure:
if (minigen->buf != NULL)
free(minigen->buf);
if (ret)
{
CONS_Printf(M_GetText("%s saved.\nRemember that this is not a complete minimap,\nand must be edited before putting in-game.\n"), filepath);
if (mul != 1)
{
CONS_Printf("You should divide its size by %d!\n", mul);
}
}
else
{
CONS_Alert(CONS_ERROR, M_GetText("Couldn't create %s\n"), filepath);
}
#endif //#ifdef USE_PNG
}
// ==========================================================================
// TRANSLATION FUNCTIONS
// ==========================================================================

View file

@ -89,6 +89,8 @@ void M_ScreenShot(void);
void M_DoScreenShot(void);
boolean M_ScreenshotResponder(event_t *ev);
void M_MinimapGenerate(void);
void Command_SaveConfig_f(void);
void Command_LoadConfig_f(void);
void Command_ChangeConfig_f(void);

View file

@ -504,6 +504,17 @@ extern fixed_t bmaporgx;
extern fixed_t bmaporgy; // origin of block map
extern mobj_t **blocklinks; // for thing chains
extern struct minimapinfo
{
patch_t *minimap_pic;
INT32 min_x, min_y;
INT32 max_x, max_y;
INT32 map_w, map_h;
INT32 minimap_w, minimap_h;
fixed_t offs_x, offs_y;
fixed_t zoom;
} minimapinfo;
//
// P_INTER
//

View file

@ -7354,6 +7354,107 @@ static void P_InitGametype(void)
CV_SetValue(&cv_menujam_update, 1);
}
struct minimapinfo minimapinfo;
static void P_InitMinimapInfo(void)
{
size_t i, count;
fixed_t a;
fixed_t b;
node_t *bsp = &nodes[numnodes-1];
minimapinfo.minimap_pic = mapheaderinfo[gamemap-1]->minimapPic;
minimapinfo.min_x = minimapinfo.max_x = minimapinfo.min_y = minimapinfo.max_y = INT32_MAX;
count = 0;
for (i = 0; i < nummapthings; i++)
{
if (mapthings[i].type != mobjinfo[MT_MINIMAPBOUND].doomednum)
continue;
count++;
if (mapthings[i].x < minimapinfo.min_x)
{
minimapinfo.max_x = minimapinfo.min_x;
minimapinfo.min_x = mapthings[i].x;
}
else
{
minimapinfo.max_x = mapthings[i].x;
}
if (mapthings[i].y < minimapinfo.min_y)
{
minimapinfo.max_y = minimapinfo.min_y;
minimapinfo.min_y = mapthings[i].y;
}
else
{
minimapinfo.max_y = mapthings[i].y;
}
}
if (count == 0)
{
minimapinfo.min_x = bsp->bbox[0][BOXLEFT];
minimapinfo.max_x = bsp->bbox[0][BOXRIGHT];
minimapinfo.min_y = bsp->bbox[0][BOXBOTTOM];
minimapinfo.max_y = bsp->bbox[0][BOXTOP];
if (bsp->bbox[1][BOXLEFT] < minimapinfo.min_x)
minimapinfo.min_x = bsp->bbox[1][BOXLEFT];
if (bsp->bbox[1][BOXRIGHT] > minimapinfo.max_x)
minimapinfo.max_x = bsp->bbox[1][BOXRIGHT];
if (bsp->bbox[1][BOXBOTTOM] < minimapinfo.min_y)
minimapinfo.min_y = bsp->bbox[1][BOXBOTTOM];
if (bsp->bbox[1][BOXTOP] > minimapinfo.max_y)
minimapinfo.max_y = bsp->bbox[1][BOXTOP];
// You might be wondering why these are being bitshift here
// it's because mapwidth and height would otherwise overflow for maps larger than half the size possible...
// map boundaries and sizes will ALWAYS be whole numbers thankfully
// later calculations take into consideration that these are actually not in terms of FRACUNIT though
minimapinfo.min_x >>= FRACBITS;
minimapinfo.max_x >>= FRACBITS;
minimapinfo.min_y >>= FRACBITS;
minimapinfo.max_y >>= FRACBITS;
}
else if (count != 2)
{
I_Error("P_InitMinimapInfo: Too %s minimap helper objects! (found %s of mapthingnum %d, should have 2)",
(count < 2 ? "few" : "many"), sizeu1(count), mobjinfo[MT_MINIMAPBOUND].doomednum);
}
minimapinfo.map_w = minimapinfo.max_x - minimapinfo.min_x;
minimapinfo.map_h = minimapinfo.max_y - minimapinfo.min_y;
minimapinfo.minimap_w = minimapinfo.minimap_h = 100;
a = FixedDiv(minimapinfo.minimap_w<<FRACBITS, minimapinfo.map_w<<4);
b = FixedDiv(minimapinfo.minimap_h<<FRACBITS, minimapinfo.map_h<<4);
if (a < b)
{
minimapinfo.minimap_h = FixedMul(a, minimapinfo.map_h)>>(FRACBITS-4);
minimapinfo.zoom = a;
}
else
{
if (a != b)
{
minimapinfo.minimap_w = FixedMul(b, minimapinfo.map_w)>>(FRACBITS-4);
}
minimapinfo.zoom = b;
}
minimapinfo.zoom >>= (FRACBITS-4);
minimapinfo.zoom -= (minimapinfo.zoom/20);
// These should always be small enough to be bitshift back right now
minimapinfo.offs_x = FixedMul((minimapinfo.min_x + minimapinfo.map_w/2) << FRACBITS, minimapinfo.zoom);
minimapinfo.offs_y = FixedMul((minimapinfo.min_y + minimapinfo.map_h/2) << FRACBITS, minimapinfo.zoom);
}
/** Loads a level from a lump or external wad.
*
* \param fromnetsave If true, skip some stuff because we're loading a netgame snapshot.
@ -7642,6 +7743,8 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
P_SpawnMapThings(!fromnetsave);
P_InitMinimapInfo();
for (numcoopstarts = 0; numcoopstarts < MAXPLAYERS; numcoopstarts++)
if (!playerstarts[numcoopstarts])
break;

View file

@ -26,6 +26,7 @@ extern "C" {
// am_map.h
TYPEDEF (fpoint_t);
TYPEDEF (fline_t);
TYPEDEF (minigen_t);
// command.h
TYPEDEF (vsbuf_t);