am_map.cpp 24 KB

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