am_map.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350
  1. // Emacs style mode select -*- C++ -*-
  2. //-----------------------------------------------------------------------------
  3. //
  4. // $Id:$
  5. //
  6. // Copyright (C) 1993-1996 by id Software, Inc.
  7. //
  8. // This source is available for distribution and/or modification
  9. // only under the terms of the DOOM Source Code License as
  10. // published by id Software. All rights reserved.
  11. //
  12. // The source is distributed in the hope that it will be useful,
  13. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
  15. // for more details.
  16. //
  17. //
  18. // $Log:$
  19. //
  20. // DESCRIPTION: the automap code
  21. //
  22. //-----------------------------------------------------------------------------
  23. static const char rcsid[] = "$Id: am_map.c,v 1.4 1997/02/03 21:24:33 b1 Exp $";
  24. #include <stdio.h>
  25. #include "z_zone.h"
  26. #include "doomdef.h"
  27. #include "st_stuff.h"
  28. #include "p_local.h"
  29. #include "w_wad.h"
  30. #include "m_cheat.h"
  31. #include "i_system.h"
  32. // Needs access to LFB.
  33. #include "v_video.h"
  34. // State.
  35. #include "doomstat.h"
  36. #include "r_state.h"
  37. // Data.
  38. #include "dstrings.h"
  39. #include "am_map.h"
  40. // For use if I do walls with outsides/insides
  41. #define REDS (256-5*16)
  42. #define REDRANGE 16
  43. #define BLUES (256-4*16+8)
  44. #define BLUERANGE 8
  45. #define GREENS (7*16)
  46. #define GREENRANGE 16
  47. #define GRAYS (6*16)
  48. #define GRAYSRANGE 16
  49. #define BROWNS (4*16)
  50. #define BROWNRANGE 16
  51. #define YELLOWS (256-32+7)
  52. #define YELLOWRANGE 1
  53. #define BLACK 0
  54. #define WHITE (256-47)
  55. // Automap colors
  56. #define BACKGROUND BLACK
  57. #define YOURCOLORS WHITE
  58. #define YOURRANGE 0
  59. #define WALLCOLORS REDS
  60. #define WALLRANGE REDRANGE
  61. #define TSWALLCOLORS GRAYS
  62. #define TSWALLRANGE GRAYSRANGE
  63. #define FDWALLCOLORS BROWNS
  64. #define FDWALLRANGE BROWNRANGE
  65. #define CDWALLCOLORS YELLOWS
  66. #define CDWALLRANGE YELLOWRANGE
  67. #define THINGCOLORS GREENS
  68. #define THINGRANGE GREENRANGE
  69. #define SECRETWALLCOLORS WALLCOLORS
  70. #define SECRETWALLRANGE WALLRANGE
  71. #define GRIDCOLORS (GRAYS + GRAYSRANGE/2)
  72. #define GRIDRANGE 0
  73. #define XHAIRCOLORS GRAYS
  74. // drawing stuff
  75. #define FB 0
  76. #define AM_PANDOWNKEY KEY_DOWNARROW
  77. #define AM_PANUPKEY KEY_UPARROW
  78. #define AM_PANRIGHTKEY KEY_RIGHTARROW
  79. #define AM_PANLEFTKEY KEY_LEFTARROW
  80. #define AM_ZOOMINKEY '='
  81. #define AM_ZOOMOUTKEY '-'
  82. #define AM_STARTKEY KEY_TAB
  83. #define AM_ENDKEY KEY_TAB
  84. #define AM_GOBIGKEY '0'
  85. #define AM_FOLLOWKEY 'f'
  86. #define AM_GRIDKEY 'g'
  87. #define AM_MARKKEY 'm'
  88. #define AM_CLEARMARKKEY 'c'
  89. #define AM_NUMMARKPOINTS 10
  90. // scale on entry
  91. #define INITSCALEMTOF (.2*FRACUNIT)
  92. // how much the automap moves window per tic in frame-buffer coordinates
  93. // moves 140 pixels in 1 second
  94. #define F_PANINC 4
  95. // how much zoom-in per tic
  96. // goes to 2x in 1 second
  97. #define M_ZOOMIN ((int) (1.02*FRACUNIT))
  98. // how much zoom-out per tic
  99. // pulls out to 0.5x in 1 second
  100. #define M_ZOOMOUT ((int) (FRACUNIT/1.02))
  101. // translates between frame-buffer and map distances
  102. #define FTOM(x) FixedMul(((x)<<16),scale_ftom)
  103. #define MTOF(x) (FixedMul((x),scale_mtof)>>16)
  104. // translates between frame-buffer and map coordinates
  105. #define CXMTOF(x) (f_x + MTOF((x)-m_x))
  106. #define CYMTOF(y) (f_y + (f_h - MTOF((y)-m_y)))
  107. // the following is crap
  108. #define LINE_NEVERSEE ML_DONTDRAW
  109. typedef struct
  110. {
  111. int x, y;
  112. } fpoint_t;
  113. typedef struct
  114. {
  115. fpoint_t a, b;
  116. } fline_t;
  117. typedef struct
  118. {
  119. fixed_t x,y;
  120. } mpoint_t;
  121. typedef struct
  122. {
  123. mpoint_t a, b;
  124. } mline_t;
  125. typedef struct
  126. {
  127. fixed_t slp, islp;
  128. } islope_t;
  129. //
  130. // The vector graphics for the automap.
  131. // A line drawing of the player pointing right,
  132. // starting from the middle.
  133. //
  134. #define R ((8*PLAYERRADIUS)/7)
  135. mline_t player_arrow[] = {
  136. { { -R+R/8, 0 }, { R, 0 } }, // -----
  137. { { R, 0 }, { R-R/2, R/4 } }, // ----->
  138. { { R, 0 }, { R-R/2, -R/4 } },
  139. { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >---->
  140. { { -R+R/8, 0 }, { -R-R/8, -R/4 } },
  141. { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>--->
  142. { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }
  143. };
  144. #undef R
  145. #define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t))
  146. #define R ((8*PLAYERRADIUS)/7)
  147. mline_t cheat_player_arrow[] = {
  148. { { -R+R/8, 0 }, { R, 0 } }, // -----
  149. { { R, 0 }, { R-R/2, R/6 } }, // ----->
  150. { { R, 0 }, { R-R/2, -R/6 } },
  151. { { -R+R/8, 0 }, { -R-R/8, R/6 } }, // >----->
  152. { { -R+R/8, 0 }, { -R-R/8, -R/6 } },
  153. { { -R+3*R/8, 0 }, { -R+R/8, R/6 } }, // >>----->
  154. { { -R+3*R/8, 0 }, { -R+R/8, -R/6 } },
  155. { { -R/2, 0 }, { -R/2, -R/6 } }, // >>-d--->
  156. { { -R/2, -R/6 }, { -R/2+R/6, -R/6 } },
  157. { { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } },
  158. { { -R/6, 0 }, { -R/6, -R/6 } }, // >>-dd-->
  159. { { -R/6, -R/6 }, { 0, -R/6 } },
  160. { { 0, -R/6 }, { 0, R/4 } },
  161. { { R/6, R/4 }, { R/6, -R/7 } }, // >>-ddt->
  162. { { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } },
  163. { { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } }
  164. };
  165. #undef R
  166. #define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t))
  167. #define R (FRACUNIT)
  168. mline_t triangle_guy[] = {
  169. { { -.867*R, -.5*R }, { .867*R, -.5*R } },
  170. { { .867*R, -.5*R } , { 0, R } },
  171. { { 0, R }, { -.867*R, -.5*R } }
  172. };
  173. #undef R
  174. #define NUMTRIANGLEGUYLINES (sizeof(triangle_guy)/sizeof(mline_t))
  175. #define R (FRACUNIT)
  176. mline_t thintriangle_guy[] = {
  177. { { -.5*R, -.7*R }, { R, 0 } },
  178. { { R, 0 }, { -.5*R, .7*R } },
  179. { { -.5*R, .7*R }, { -.5*R, -.7*R } }
  180. };
  181. #undef R
  182. #define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t))
  183. static int cheating = 0;
  184. static int grid = 0;
  185. static int leveljuststarted = 1; // kluge until AM_LevelInit() is called
  186. boolean automapactive = false;
  187. static int finit_width = SCREENWIDTH;
  188. static int finit_height = SCREENHEIGHT - 32;
  189. // location of window on screen
  190. static int f_x;
  191. static int f_y;
  192. // size of window on screen
  193. static int f_w;
  194. static int f_h;
  195. static int lightlev; // used for funky strobing effect
  196. static byte* fb; // pseudo-frame buffer
  197. static int amclock;
  198. static mpoint_t m_paninc; // how far the window pans each tic (map coords)
  199. static fixed_t mtof_zoommul; // how far the window zooms in each tic (map coords)
  200. static fixed_t ftom_zoommul; // how far the window zooms in each tic (fb coords)
  201. static fixed_t m_x, m_y; // LL x,y where the window is on the map (map coords)
  202. static fixed_t m_x2, m_y2; // UR x,y where the window is on the map (map coords)
  203. //
  204. // width/height of window on map (map coords)
  205. //
  206. static fixed_t m_w;
  207. static fixed_t m_h;
  208. // based on level size
  209. static fixed_t min_x;
  210. static fixed_t min_y;
  211. static fixed_t max_x;
  212. static fixed_t max_y;
  213. static fixed_t max_w; // max_x-min_x,
  214. static fixed_t max_h; // max_y-min_y
  215. // based on player size
  216. static fixed_t min_w;
  217. static fixed_t min_h;
  218. static fixed_t min_scale_mtof; // used to tell when to stop zooming out
  219. static fixed_t max_scale_mtof; // used to tell when to stop zooming in
  220. // old stuff for recovery later
  221. static fixed_t old_m_w, old_m_h;
  222. static fixed_t old_m_x, old_m_y;
  223. // old location used by the Follower routine
  224. static mpoint_t f_oldloc;
  225. // used by MTOF to scale from map-to-frame-buffer coords
  226. static fixed_t scale_mtof = INITSCALEMTOF;
  227. // used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof)
  228. static fixed_t scale_ftom;
  229. static player_t *plr; // the player represented by an arrow
  230. static patch_t *marknums[10]; // numbers used for marking by the automap
  231. static mpoint_t markpoints[AM_NUMMARKPOINTS]; // where the points are
  232. static int markpointnum = 0; // next point to be assigned
  233. static int followplayer = 1; // specifies whether to follow the player around
  234. static unsigned char cheat_amap_seq[] = { 0xb2, 0x26, 0x26, 0x2e, 0xff };
  235. static cheatseq_t cheat_amap = { cheat_amap_seq, 0 };
  236. static boolean stopped = true;
  237. extern boolean viewactive;
  238. //extern byte screens[][SCREENWIDTH*SCREENHEIGHT];
  239. void
  240. V_MarkRect
  241. ( int x,
  242. int y,
  243. int width,
  244. int height );
  245. // Calculates the slope and slope according to the x-axis of a line
  246. // segment in map coordinates (with the upright y-axis n' all) so
  247. // that it can be used with the brain-dead drawing stuff.
  248. void
  249. AM_getIslope
  250. ( mline_t* ml,
  251. islope_t* is )
  252. {
  253. int dx, dy;
  254. dy = ml->a.y - ml->b.y;
  255. dx = ml->b.x - ml->a.x;
  256. if (!dy) is->islp = (dx<0?-MAXINT:MAXINT);
  257. else is->islp = FixedDiv(dx, dy);
  258. if (!dx) is->slp = (dy<0?-MAXINT:MAXINT);
  259. else is->slp = FixedDiv(dy, dx);
  260. }
  261. //
  262. //
  263. //
  264. void AM_activateNewScale(void)
  265. {
  266. m_x += m_w/2;
  267. m_y += m_h/2;
  268. m_w = FTOM(f_w);
  269. m_h = FTOM(f_h);
  270. m_x -= m_w/2;
  271. m_y -= m_h/2;
  272. m_x2 = m_x + m_w;
  273. m_y2 = m_y + m_h;
  274. }
  275. //
  276. //
  277. //
  278. void AM_saveScaleAndLoc(void)
  279. {
  280. old_m_x = m_x;
  281. old_m_y = m_y;
  282. old_m_w = m_w;
  283. old_m_h = m_h;
  284. }
  285. //
  286. //
  287. //
  288. void AM_restoreScaleAndLoc(void)
  289. {
  290. m_w = old_m_w;
  291. m_h = old_m_h;
  292. if (!followplayer)
  293. {
  294. m_x = old_m_x;
  295. m_y = old_m_y;
  296. } else {
  297. m_x = plr->mo->x - m_w/2;
  298. m_y = plr->mo->y - m_h/2;
  299. }
  300. m_x2 = m_x + m_w;
  301. m_y2 = m_y + m_h;
  302. // Change the scaling multipliers
  303. scale_mtof = FixedDiv(f_w<<FRACBITS, m_w);
  304. scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
  305. }
  306. //
  307. // adds a marker at the current location
  308. //
  309. void AM_addMark(void)
  310. {
  311. markpoints[markpointnum].x = m_x + m_w/2;
  312. markpoints[markpointnum].y = m_y + m_h/2;
  313. markpointnum = (markpointnum + 1) % AM_NUMMARKPOINTS;
  314. }
  315. //
  316. // Determines bounding box of all vertices,
  317. // sets global variables controlling zoom range.
  318. //
  319. void AM_findMinMaxBoundaries(void)
  320. {
  321. int i;
  322. fixed_t a;
  323. fixed_t b;
  324. min_x = min_y = MAXINT;
  325. max_x = max_y = -MAXINT;
  326. for (i=0;i<numvertexes;i++)
  327. {
  328. if (vertexes[i].x < min_x)
  329. min_x = vertexes[i].x;
  330. else if (vertexes[i].x > max_x)
  331. max_x = vertexes[i].x;
  332. if (vertexes[i].y < min_y)
  333. min_y = vertexes[i].y;
  334. else if (vertexes[i].y > max_y)
  335. max_y = vertexes[i].y;
  336. }
  337. max_w = max_x - min_x;
  338. max_h = max_y - min_y;
  339. min_w = 2*PLAYERRADIUS; // const? never changed?
  340. min_h = 2*PLAYERRADIUS;
  341. a = FixedDiv(f_w<<FRACBITS, max_w);
  342. b = FixedDiv(f_h<<FRACBITS, max_h);
  343. min_scale_mtof = a < b ? a : b;
  344. max_scale_mtof = FixedDiv(f_h<<FRACBITS, 2*PLAYERRADIUS);
  345. }
  346. //
  347. //
  348. //
  349. void AM_changeWindowLoc(void)
  350. {
  351. if (m_paninc.x || m_paninc.y)
  352. {
  353. followplayer = 0;
  354. f_oldloc.x = MAXINT;
  355. }
  356. m_x += m_paninc.x;
  357. m_y += m_paninc.y;
  358. if (m_x + m_w/2 > max_x)
  359. m_x = max_x - m_w/2;
  360. else if (m_x + m_w/2 < min_x)
  361. m_x = min_x - m_w/2;
  362. if (m_y + m_h/2 > max_y)
  363. m_y = max_y - m_h/2;
  364. else if (m_y + m_h/2 < min_y)
  365. m_y = min_y - m_h/2;
  366. m_x2 = m_x + m_w;
  367. m_y2 = m_y + m_h;
  368. }
  369. //
  370. //
  371. //
  372. void AM_initVariables(void)
  373. {
  374. int pnum;
  375. static event_t st_notify = { ev_keyup, AM_MSGENTERED };
  376. automapactive = true;
  377. fb = screens[0];
  378. f_oldloc.x = MAXINT;
  379. amclock = 0;
  380. lightlev = 0;
  381. m_paninc.x = m_paninc.y = 0;
  382. ftom_zoommul = FRACUNIT;
  383. mtof_zoommul = FRACUNIT;
  384. m_w = FTOM(f_w);
  385. m_h = FTOM(f_h);
  386. // find player to center on initially
  387. if (!playeringame[pnum = consoleplayer])
  388. for (pnum=0;pnum<MAXPLAYERS;pnum++)
  389. if (playeringame[pnum])
  390. break;
  391. plr = &players[pnum];
  392. m_x = plr->mo->x - m_w/2;
  393. m_y = plr->mo->y - m_h/2;
  394. AM_changeWindowLoc();
  395. // for saving & restoring
  396. old_m_x = m_x;
  397. old_m_y = m_y;
  398. old_m_w = m_w;
  399. old_m_h = m_h;
  400. // inform the status bar of the change
  401. ST_Responder(&st_notify);
  402. }
  403. //
  404. //
  405. //
  406. void AM_loadPics(void)
  407. {
  408. int i;
  409. char namebuf[9];
  410. for (i=0;i<10;i++)
  411. {
  412. sprintf(namebuf, "AMMNUM%d", i);
  413. marknums[i] = W_CacheLumpName(namebuf, PU_STATIC);
  414. }
  415. }
  416. void AM_unloadPics(void)
  417. {
  418. int i;
  419. for (i=0;i<10;i++)
  420. Z_ChangeTag(marknums[i], PU_CACHE);
  421. }
  422. void AM_clearMarks(void)
  423. {
  424. int i;
  425. for (i=0;i<AM_NUMMARKPOINTS;i++)
  426. markpoints[i].x = -1; // means empty
  427. markpointnum = 0;
  428. }
  429. //
  430. // should be called at the start of every level
  431. // right now, i figure it out myself
  432. //
  433. void AM_LevelInit(void)
  434. {
  435. leveljuststarted = 0;
  436. f_x = f_y = 0;
  437. f_w = finit_width;
  438. f_h = finit_height;
  439. AM_clearMarks();
  440. AM_findMinMaxBoundaries();
  441. scale_mtof = FixedDiv(min_scale_mtof, (int) (0.7*FRACUNIT));
  442. if (scale_mtof > max_scale_mtof)
  443. scale_mtof = min_scale_mtof;
  444. scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
  445. }
  446. //
  447. //
  448. //
  449. void AM_Stop (void)
  450. {
  451. static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED };
  452. AM_unloadPics();
  453. automapactive = false;
  454. ST_Responder(&st_notify);
  455. stopped = true;
  456. }
  457. //
  458. //
  459. //
  460. void AM_Start (void)
  461. {
  462. static int lastlevel = -1, lastepisode = -1;
  463. if (!stopped) AM_Stop();
  464. stopped = false;
  465. if (lastlevel != gamemap || lastepisode != gameepisode)
  466. {
  467. AM_LevelInit();
  468. lastlevel = gamemap;
  469. lastepisode = gameepisode;
  470. }
  471. AM_initVariables();
  472. AM_loadPics();
  473. }
  474. //
  475. // set the window scale to the maximum size
  476. //
  477. void AM_minOutWindowScale(void)
  478. {
  479. scale_mtof = min_scale_mtof;
  480. scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
  481. AM_activateNewScale();
  482. }
  483. //
  484. // set the window scale to the minimum size
  485. //
  486. void AM_maxOutWindowScale(void)
  487. {
  488. scale_mtof = max_scale_mtof;
  489. scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
  490. AM_activateNewScale();
  491. }
  492. //
  493. // Handle events (user inputs) in automap mode
  494. //
  495. boolean
  496. AM_Responder
  497. ( event_t* ev )
  498. {
  499. int rc;
  500. static int cheatstate=0;
  501. static int bigstate=0;
  502. static char buffer[20];
  503. rc = false;
  504. if (!automapactive)
  505. {
  506. if (ev->type == ev_keydown && ev->data1 == AM_STARTKEY)
  507. {
  508. AM_Start ();
  509. viewactive = false;
  510. rc = true;
  511. }
  512. }
  513. else if (ev->type == ev_keydown)
  514. {
  515. rc = true;
  516. switch(ev->data1)
  517. {
  518. case AM_PANRIGHTKEY: // pan right
  519. if (!followplayer) m_paninc.x = FTOM(F_PANINC);
  520. else rc = false;
  521. break;
  522. case AM_PANLEFTKEY: // pan left
  523. if (!followplayer) m_paninc.x = -FTOM(F_PANINC);
  524. else rc = false;
  525. break;
  526. case AM_PANUPKEY: // pan up
  527. if (!followplayer) m_paninc.y = FTOM(F_PANINC);
  528. else rc = false;
  529. break;
  530. case AM_PANDOWNKEY: // pan down
  531. if (!followplayer) m_paninc.y = -FTOM(F_PANINC);
  532. else rc = false;
  533. break;
  534. case AM_ZOOMOUTKEY: // zoom out
  535. mtof_zoommul = M_ZOOMOUT;
  536. ftom_zoommul = M_ZOOMIN;
  537. break;
  538. case AM_ZOOMINKEY: // zoom in
  539. mtof_zoommul = M_ZOOMIN;
  540. ftom_zoommul = M_ZOOMOUT;
  541. break;
  542. case AM_ENDKEY:
  543. bigstate = 0;
  544. viewactive = true;
  545. AM_Stop ();
  546. break;
  547. case AM_GOBIGKEY:
  548. bigstate = !bigstate;
  549. if (bigstate)
  550. {
  551. AM_saveScaleAndLoc();
  552. AM_minOutWindowScale();
  553. }
  554. else AM_restoreScaleAndLoc();
  555. break;
  556. case AM_FOLLOWKEY:
  557. followplayer = !followplayer;
  558. f_oldloc.x = MAXINT;
  559. plr->message = followplayer ? AMSTR_FOLLOWON : AMSTR_FOLLOWOFF;
  560. break;
  561. case AM_GRIDKEY:
  562. grid = !grid;
  563. plr->message = grid ? AMSTR_GRIDON : AMSTR_GRIDOFF;
  564. break;
  565. case AM_MARKKEY:
  566. sprintf(buffer, "%s %d", AMSTR_MARKEDSPOT, markpointnum);
  567. plr->message = buffer;
  568. AM_addMark();
  569. break;
  570. case AM_CLEARMARKKEY:
  571. AM_clearMarks();
  572. plr->message = AMSTR_MARKSCLEARED;
  573. break;
  574. default:
  575. cheatstate=0;
  576. rc = false;
  577. }
  578. if (!deathmatch && cht_CheckCheat(&cheat_amap, ev->data1))
  579. {
  580. rc = false;
  581. cheating = (cheating+1) % 3;
  582. }
  583. }
  584. else if (ev->type == ev_keyup)
  585. {
  586. rc = false;
  587. switch (ev->data1)
  588. {
  589. case AM_PANRIGHTKEY:
  590. if (!followplayer) m_paninc.x = 0;
  591. break;
  592. case AM_PANLEFTKEY:
  593. if (!followplayer) m_paninc.x = 0;
  594. break;
  595. case AM_PANUPKEY:
  596. if (!followplayer) m_paninc.y = 0;
  597. break;
  598. case AM_PANDOWNKEY:
  599. if (!followplayer) m_paninc.y = 0;
  600. break;
  601. case AM_ZOOMOUTKEY:
  602. case AM_ZOOMINKEY:
  603. mtof_zoommul = FRACUNIT;
  604. ftom_zoommul = FRACUNIT;
  605. break;
  606. }
  607. }
  608. return rc;
  609. }
  610. //
  611. // Zooming
  612. //
  613. void AM_changeWindowScale(void)
  614. {
  615. // Change the scaling multipliers
  616. scale_mtof = FixedMul(scale_mtof, mtof_zoommul);
  617. scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
  618. if (scale_mtof < min_scale_mtof)
  619. AM_minOutWindowScale();
  620. else if (scale_mtof > max_scale_mtof)
  621. AM_maxOutWindowScale();
  622. else
  623. AM_activateNewScale();
  624. }
  625. //
  626. //
  627. //
  628. void AM_doFollowPlayer(void)
  629. {
  630. if (f_oldloc.x != plr->mo->x || f_oldloc.y != plr->mo->y)
  631. {
  632. m_x = FTOM(MTOF(plr->mo->x)) - m_w/2;
  633. m_y = FTOM(MTOF(plr->mo->y)) - m_h/2;
  634. m_x2 = m_x + m_w;
  635. m_y2 = m_y + m_h;
  636. f_oldloc.x = plr->mo->x;
  637. f_oldloc.y = plr->mo->y;
  638. // m_x = FTOM(MTOF(plr->mo->x - m_w/2));
  639. // m_y = FTOM(MTOF(plr->mo->y - m_h/2));
  640. // m_x = plr->mo->x - m_w/2;
  641. // m_y = plr->mo->y - m_h/2;
  642. }
  643. }
  644. //
  645. //
  646. //
  647. void AM_updateLightLev(void)
  648. {
  649. static nexttic = 0;
  650. //static int litelevels[] = { 0, 3, 5, 6, 6, 7, 7, 7 };
  651. static int litelevels[] = { 0, 4, 7, 10, 12, 14, 15, 15 };
  652. static int litelevelscnt = 0;
  653. // Change light level
  654. if (amclock>nexttic)
  655. {
  656. lightlev = litelevels[litelevelscnt++];
  657. if (litelevelscnt == sizeof(litelevels)/sizeof(int)) litelevelscnt = 0;
  658. nexttic = amclock + 6 - (amclock % 6);
  659. }
  660. }
  661. //
  662. // Updates on Game Tick
  663. //
  664. void AM_Ticker (void)
  665. {
  666. if (!automapactive)
  667. return;
  668. amclock++;
  669. if (followplayer)
  670. AM_doFollowPlayer();
  671. // Change the zoom if necessary
  672. if (ftom_zoommul != FRACUNIT)
  673. AM_changeWindowScale();
  674. // Change x,y location
  675. if (m_paninc.x || m_paninc.y)
  676. AM_changeWindowLoc();
  677. // Update light level
  678. // AM_updateLightLev();
  679. }
  680. //
  681. // Clear automap frame buffer.
  682. //
  683. void AM_clearFB(int color)
  684. {
  685. memset(fb, color, f_w*f_h);
  686. }
  687. //
  688. // Automap clipping of lines.
  689. //
  690. // Based on Cohen-Sutherland clipping algorithm but with a slightly
  691. // faster reject and precalculated slopes. If the speed is needed,
  692. // use a hash algorithm to handle the common cases.
  693. //
  694. boolean
  695. AM_clipMline
  696. ( mline_t* ml,
  697. fline_t* fl )
  698. {
  699. enum
  700. {
  701. LEFT =1,
  702. RIGHT =2,
  703. BOTTOM =4,
  704. TOP =8
  705. };
  706. register outcode1 = 0;
  707. register outcode2 = 0;
  708. register outside;
  709. fpoint_t tmp;
  710. int dx;
  711. int dy;
  712. #define DOOUTCODE(oc, mx, my) \
  713. (oc) = 0; \
  714. if ((my) < 0) (oc) |= TOP; \
  715. else if ((my) >= f_h) (oc) |= BOTTOM; \
  716. if ((mx) < 0) (oc) |= LEFT; \
  717. else if ((mx) >= f_w) (oc) |= RIGHT;
  718. // do trivial rejects and outcodes
  719. if (ml->a.y > m_y2)
  720. outcode1 = TOP;
  721. else if (ml->a.y < m_y)
  722. outcode1 = BOTTOM;
  723. if (ml->b.y > m_y2)
  724. outcode2 = TOP;
  725. else if (ml->b.y < m_y)
  726. outcode2 = BOTTOM;
  727. if (outcode1 & outcode2)
  728. return false; // trivially outside
  729. if (ml->a.x < m_x)
  730. outcode1 |= LEFT;
  731. else if (ml->a.x > m_x2)
  732. outcode1 |= RIGHT;
  733. if (ml->b.x < m_x)
  734. outcode2 |= LEFT;
  735. else if (ml->b.x > m_x2)
  736. outcode2 |= RIGHT;
  737. if (outcode1 & outcode2)
  738. return false; // trivially outside
  739. // transform to frame-buffer coordinates.
  740. fl->a.x = CXMTOF(ml->a.x);
  741. fl->a.y = CYMTOF(ml->a.y);
  742. fl->b.x = CXMTOF(ml->b.x);
  743. fl->b.y = CYMTOF(ml->b.y);
  744. DOOUTCODE(outcode1, fl->a.x, fl->a.y);
  745. DOOUTCODE(outcode2, fl->b.x, fl->b.y);
  746. if (outcode1 & outcode2)
  747. return false;
  748. while (outcode1 | outcode2)
  749. {
  750. // may be partially inside box
  751. // find an outside point
  752. if (outcode1)
  753. outside = outcode1;
  754. else
  755. outside = outcode2;
  756. // clip to each side
  757. if (outside & TOP)
  758. {
  759. dy = fl->a.y - fl->b.y;
  760. dx = fl->b.x - fl->a.x;
  761. tmp.x = fl->a.x + (dx*(fl->a.y))/dy;
  762. tmp.y = 0;
  763. }
  764. else if (outside & BOTTOM)
  765. {
  766. dy = fl->a.y - fl->b.y;
  767. dx = fl->b.x - fl->a.x;
  768. tmp.x = fl->a.x + (dx*(fl->a.y-f_h))/dy;
  769. tmp.y = f_h-1;
  770. }
  771. else if (outside & RIGHT)
  772. {
  773. dy = fl->b.y - fl->a.y;
  774. dx = fl->b.x - fl->a.x;
  775. tmp.y = fl->a.y + (dy*(f_w-1 - fl->a.x))/dx;
  776. tmp.x = f_w-1;
  777. }
  778. else if (outside & LEFT)
  779. {
  780. dy = fl->b.y - fl->a.y;
  781. dx = fl->b.x - fl->a.x;
  782. tmp.y = fl->a.y + (dy*(-fl->a.x))/dx;
  783. tmp.x = 0;
  784. }
  785. if (outside == outcode1)
  786. {
  787. fl->a = tmp;
  788. DOOUTCODE(outcode1, fl->a.x, fl->a.y);
  789. }
  790. else
  791. {
  792. fl->b = tmp;
  793. DOOUTCODE(outcode2, fl->b.x, fl->b.y);
  794. }
  795. if (outcode1 & outcode2)
  796. return false; // trivially outside
  797. }
  798. return true;
  799. }
  800. #undef DOOUTCODE
  801. //
  802. // Classic Bresenham w/ whatever optimizations needed for speed
  803. //
  804. void
  805. AM_drawFline
  806. ( fline_t* fl,
  807. int color )
  808. {
  809. register int x;
  810. register int y;
  811. register int dx;
  812. register int dy;
  813. register int sx;
  814. register int sy;
  815. register int ax;
  816. register int ay;
  817. register int d;
  818. static fuck = 0;
  819. // For debugging only
  820. if ( fl->a.x < 0 || fl->a.x >= f_w
  821. || fl->a.y < 0 || fl->a.y >= f_h
  822. || fl->b.x < 0 || fl->b.x >= f_w
  823. || fl->b.y < 0 || fl->b.y >= f_h)
  824. {
  825. fprintf(stderr, "fuck %d \r", fuck++);
  826. return;
  827. }
  828. #define PUTDOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(cc)
  829. dx = fl->b.x - fl->a.x;
  830. ax = 2 * (dx<0 ? -dx : dx);
  831. sx = dx<0 ? -1 : 1;
  832. dy = fl->b.y - fl->a.y;
  833. ay = 2 * (dy<0 ? -dy : dy);
  834. sy = dy<0 ? -1 : 1;
  835. x = fl->a.x;
  836. y = fl->a.y;
  837. if (ax > ay)
  838. {
  839. d = ay - ax/2;
  840. while (1)
  841. {
  842. PUTDOT(x,y,color);
  843. if (x == fl->b.x) return;
  844. if (d>=0)
  845. {
  846. y += sy;
  847. d -= ax;
  848. }
  849. x += sx;
  850. d += ay;
  851. }
  852. }
  853. else
  854. {
  855. d = ax - ay/2;
  856. while (1)
  857. {
  858. PUTDOT(x, y, color);
  859. if (y == fl->b.y) return;
  860. if (d >= 0)
  861. {
  862. x += sx;
  863. d -= ay;
  864. }
  865. y += sy;
  866. d += ax;
  867. }
  868. }
  869. }
  870. //
  871. // Clip lines, draw visible part sof lines.
  872. //
  873. void
  874. AM_drawMline
  875. ( mline_t* ml,
  876. int color )
  877. {
  878. static fline_t fl;
  879. if (AM_clipMline(ml, &fl))
  880. AM_drawFline(&fl, color); // draws it on frame buffer using fb coords
  881. }
  882. //
  883. // Draws flat (floor/ceiling tile) aligned grid lines.
  884. //
  885. void AM_drawGrid(int color)
  886. {
  887. fixed_t x, y;
  888. fixed_t start, end;
  889. mline_t ml;
  890. // Figure out start of vertical gridlines
  891. start = m_x;
  892. if ((start-bmaporgx)%(MAPBLOCKUNITS<<FRACBITS))
  893. start += (MAPBLOCKUNITS<<FRACBITS)
  894. - ((start-bmaporgx)%(MAPBLOCKUNITS<<FRACBITS));
  895. end = m_x + m_w;
  896. // draw vertical gridlines
  897. ml.a.y = m_y;
  898. ml.b.y = m_y+m_h;
  899. for (x=start; x<end; x+=(MAPBLOCKUNITS<<FRACBITS))
  900. {
  901. ml.a.x = x;
  902. ml.b.x = x;
  903. AM_drawMline(&ml, color);
  904. }
  905. // Figure out start of horizontal gridlines
  906. start = m_y;
  907. if ((start-bmaporgy)%(MAPBLOCKUNITS<<FRACBITS))
  908. start += (MAPBLOCKUNITS<<FRACBITS)
  909. - ((start-bmaporgy)%(MAPBLOCKUNITS<<FRACBITS));
  910. end = m_y + m_h;
  911. // draw horizontal gridlines
  912. ml.a.x = m_x;
  913. ml.b.x = m_x + m_w;
  914. for (y=start; y<end; y+=(MAPBLOCKUNITS<<FRACBITS))
  915. {
  916. ml.a.y = y;
  917. ml.b.y = y;
  918. AM_drawMline(&ml, color);
  919. }
  920. }
  921. //
  922. // Determines visible lines, draws them.
  923. // This is LineDef based, not LineSeg based.
  924. //
  925. void AM_drawWalls(void)
  926. {
  927. int i;
  928. static mline_t l;
  929. for (i=0;i<numlines;i++)
  930. {
  931. l.a.x = lines[i].v1->x;
  932. l.a.y = lines[i].v1->y;
  933. l.b.x = lines[i].v2->x;
  934. l.b.y = lines[i].v2->y;
  935. if (cheating || (lines[i].flags & ML_MAPPED))
  936. {
  937. if ((lines[i].flags & LINE_NEVERSEE) && !cheating)
  938. continue;
  939. if (!lines[i].backsector)
  940. {
  941. AM_drawMline(&l, WALLCOLORS+lightlev);
  942. }
  943. else
  944. {
  945. if (lines[i].special == 39)
  946. { // teleporters
  947. AM_drawMline(&l, WALLCOLORS+WALLRANGE/2);
  948. }
  949. else if (lines[i].flags & ML_SECRET) // secret door
  950. {
  951. if (cheating) AM_drawMline(&l, SECRETWALLCOLORS + lightlev);
  952. else AM_drawMline(&l, WALLCOLORS+lightlev);
  953. }
  954. else if (lines[i].backsector->floorheight
  955. != lines[i].frontsector->floorheight) {
  956. AM_drawMline(&l, FDWALLCOLORS + lightlev); // floor level change
  957. }
  958. else if (lines[i].backsector->ceilingheight
  959. != lines[i].frontsector->ceilingheight) {
  960. AM_drawMline(&l, CDWALLCOLORS+lightlev); // ceiling level change
  961. }
  962. else if (cheating) {
  963. AM_drawMline(&l, TSWALLCOLORS+lightlev);
  964. }
  965. }
  966. }
  967. else if (plr->powers[pw_allmap])
  968. {
  969. if (!(lines[i].flags & LINE_NEVERSEE)) AM_drawMline(&l, GRAYS+3);
  970. }
  971. }
  972. }
  973. //
  974. // Rotation in 2D.
  975. // Used to rotate player arrow line character.
  976. //
  977. void
  978. AM_rotate
  979. ( fixed_t* x,
  980. fixed_t* y,
  981. angle_t a )
  982. {
  983. fixed_t tmpx;
  984. tmpx =
  985. FixedMul(*x,finecosine[a>>ANGLETOFINESHIFT])
  986. - FixedMul(*y,finesine[a>>ANGLETOFINESHIFT]);
  987. *y =
  988. FixedMul(*x,finesine[a>>ANGLETOFINESHIFT])
  989. + FixedMul(*y,finecosine[a>>ANGLETOFINESHIFT]);
  990. *x = tmpx;
  991. }
  992. void
  993. AM_drawLineCharacter
  994. ( mline_t* lineguy,
  995. int lineguylines,
  996. fixed_t scale,
  997. angle_t angle,
  998. int color,
  999. fixed_t x,
  1000. fixed_t y )
  1001. {
  1002. int i;
  1003. mline_t l;
  1004. for (i=0;i<lineguylines;i++)
  1005. {
  1006. l.a.x = lineguy[i].a.x;
  1007. l.a.y = lineguy[i].a.y;
  1008. if (scale)
  1009. {
  1010. l.a.x = FixedMul(scale, l.a.x);
  1011. l.a.y = FixedMul(scale, l.a.y);
  1012. }
  1013. if (angle)
  1014. AM_rotate(&l.a.x, &l.a.y, angle);
  1015. l.a.x += x;
  1016. l.a.y += y;
  1017. l.b.x = lineguy[i].b.x;
  1018. l.b.y = lineguy[i].b.y;
  1019. if (scale)
  1020. {
  1021. l.b.x = FixedMul(scale, l.b.x);
  1022. l.b.y = FixedMul(scale, l.b.y);
  1023. }
  1024. if (angle)
  1025. AM_rotate(&l.b.x, &l.b.y, angle);
  1026. l.b.x += x;
  1027. l.b.y += y;
  1028. AM_drawMline(&l, color);
  1029. }
  1030. }
  1031. void AM_drawPlayers(void)
  1032. {
  1033. int i;
  1034. player_t* p;
  1035. static int their_colors[] = { GREENS, GRAYS, BROWNS, REDS };
  1036. int their_color = -1;
  1037. int color;
  1038. if (!netgame)
  1039. {
  1040. if (cheating)
  1041. AM_drawLineCharacter
  1042. (cheat_player_arrow, NUMCHEATPLYRLINES, 0,
  1043. plr->mo->angle, WHITE, plr->mo->x, plr->mo->y);
  1044. else
  1045. AM_drawLineCharacter
  1046. (player_arrow, NUMPLYRLINES, 0, plr->mo->angle,
  1047. WHITE, plr->mo->x, plr->mo->y);
  1048. return;
  1049. }
  1050. for (i=0;i<MAXPLAYERS;i++)
  1051. {
  1052. their_color++;
  1053. p = &players[i];
  1054. if ( (deathmatch && !singledemo) && p != plr)
  1055. continue;
  1056. if (!playeringame[i])
  1057. continue;
  1058. if (p->powers[pw_invisibility])
  1059. color = 246; // *close* to black
  1060. else
  1061. color = their_colors[their_color];
  1062. AM_drawLineCharacter
  1063. (player_arrow, NUMPLYRLINES, 0, p->mo->angle,
  1064. color, p->mo->x, p->mo->y);
  1065. }
  1066. }
  1067. void
  1068. AM_drawThings
  1069. ( int colors,
  1070. int colorrange)
  1071. {
  1072. int i;
  1073. mobj_t* t;
  1074. for (i=0;i<numsectors;i++)
  1075. {
  1076. t = sectors[i].thinglist;
  1077. while (t)
  1078. {
  1079. AM_drawLineCharacter
  1080. (thintriangle_guy, NUMTHINTRIANGLEGUYLINES,
  1081. 16<<FRACBITS, t->angle, colors+lightlev, t->x, t->y);
  1082. t = t->snext;
  1083. }
  1084. }
  1085. }
  1086. void AM_drawMarks(void)
  1087. {
  1088. int i, fx, fy, w, h;
  1089. for (i=0;i<AM_NUMMARKPOINTS;i++)
  1090. {
  1091. if (markpoints[i].x != -1)
  1092. {
  1093. // w = SHORT(marknums[i]->width);
  1094. // h = SHORT(marknums[i]->height);
  1095. w = 5; // because something's wrong with the wad, i guess
  1096. h = 6; // because something's wrong with the wad, i guess
  1097. fx = CXMTOF(markpoints[i].x);
  1098. fy = CYMTOF(markpoints[i].y);
  1099. if (fx >= f_x && fx <= f_w - w && fy >= f_y && fy <= f_h - h)
  1100. V_DrawPatch(fx, fy, FB, marknums[i]);
  1101. }
  1102. }
  1103. }
  1104. void AM_drawCrosshair(int color)
  1105. {
  1106. fb[(f_w*(f_h+1))/2] = color; // single point for now
  1107. }
  1108. void AM_Drawer (void)
  1109. {
  1110. if (!automapactive) return;
  1111. AM_clearFB(BACKGROUND);
  1112. if (grid)
  1113. AM_drawGrid(GRIDCOLORS);
  1114. AM_drawWalls();
  1115. AM_drawPlayers();
  1116. if (cheating==2)
  1117. AM_drawThings(THINGCOLORS, THINGRANGE);
  1118. AM_drawCrosshair(XHAIRCOLORS);
  1119. AM_drawMarks();
  1120. V_MarkRect(f_x, f_y, f_w, f_h);
  1121. }