DEADSOFTWARE

slightly better outlining in Holmes
[d2df-sdl.git] / src / game / g_holmes.pas
1 (* Copyright (C) DooM 2D:Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *)
16 {$INCLUDE ../shared/a_modes.inc}
17 unit g_holmes;
19 interface
21 uses
22 e_log,
23 g_textures, g_basic, e_graphics, g_phys, g_grid, g_player, g_monsters,
24 g_window, g_map, g_triggers, g_items, g_game, g_panel, g_console,
25 xprofiler;
28 type
29 THMouseEvent = record
30 public
31 const
32 // both for but and for bstate
33 Left = $0001;
34 Right = $0002;
35 Middle = $0004;
36 WheelUp = $0008;
37 WheelDown = $0010;
39 // event types
40 Release = 0;
41 Press = 1;
42 Motion = 2;
44 public
45 kind: Byte; // motion, press, release
46 x, y: Integer;
47 dx, dy: Integer; // for wheel this is wheel motion, otherwise this is relative mouse motion
48 but: Word; // current pressed/released button, or 0 for motion
49 bstate: Word; // button state
50 kstate: Word; // keyboard state (see THKeyEvent);
51 end;
53 THKeyEvent = record
54 public
55 const
56 // modifiers
57 ModCtrl = $0001;
58 ModAlt = $0002;
59 ModShift = $0004;
61 // event types
62 Release = 0;
63 Press = 1;
65 public
66 kind: Byte;
67 scan: Word; // SDL_SCANCODE_XXX
68 sym: Word; // SDLK_XXX
69 bstate: Word; // button state
70 kstate: Word; // keyboard state
71 end;
74 procedure g_Holmes_VidModeChanged ();
75 procedure g_Holmes_WindowFocused ();
76 procedure g_Holmes_WindowBlured ();
78 procedure g_Holmes_Draw ();
79 procedure g_Holmes_DrawUI ();
81 function g_Holmes_MouseEvent (var ev: THMouseEvent): Boolean; // returns `true` if event was eaten
82 function g_Holmes_KeyEvent (var ev: THKeyEvent): Boolean; // returns `true` if event was eaten
84 // hooks for player
85 procedure g_Holmes_plrView (viewPortX, viewPortY, viewPortW, viewPortH: Integer);
86 procedure g_Holmes_plrLaser (ax0, ay0, ax1, ay1: Integer);
89 var
90 g_holmes_enabled: Boolean = {$IF DEFINED(D2F_DEBUG)}true{$ELSE}false{$ENDIF};
93 implementation
95 uses
96 SysUtils, GL, SDL2,
97 MAPDEF, g_options;
100 var
101 //globalInited: Boolean = false;
102 msX: Integer = -666;
103 msY: Integer = -666;
104 msB: Word = 0; // button state
105 kbS: Word = 0; // keyboard modifiers state
106 showGrid: Boolean = true;
107 showMonsInfo: Boolean = false;
108 showMonsLOS2Plr: Boolean = false;
109 showAllMonsCells: Boolean = false;
110 showMapCurPos: Boolean = false;
113 // ////////////////////////////////////////////////////////////////////////// //
114 {$INCLUDE g_holmes.inc}
115 {$INCLUDE g_holmes_ui.inc}
118 // ////////////////////////////////////////////////////////////////////////// //
119 var
120 g_ol_nice: Boolean = false;
121 g_ol_rlayer_back: Boolean = false;
122 g_ol_rlayer_step: Boolean = false;
123 g_ol_rlayer_wall: Boolean = false;
124 g_ol_rlayer_door: Boolean = false;
125 g_ol_rlayer_acid1: Boolean = false;
126 g_ol_rlayer_acid2: Boolean = false;
127 g_ol_rlayer_water: Boolean = false;
128 g_ol_rlayer_fore: Boolean = false;
131 // ////////////////////////////////////////////////////////////////////////// //
132 var
133 winOptions: THTopWindow = nil;
134 winLayers: THTopWindow = nil;
135 winOutlines: THTopWindow = nil;
138 procedure createOptionsWindow ();
139 var
140 llb: THCtlCBListBox;
141 begin
142 llb := THCtlCBListBox.Create(0, 0);
143 llb.appendItem('map grid', @showGrid);
144 llb.appendItem('cursor position on map', @showMapCurPos);
145 llb.appendItem('monster info', @showMonsInfo);
146 llb.appendItem('monster LOS to player', @showMonsLOS2Plr);
147 llb.appendItem('monster cells (SLOW!)', @showAllMonsCells);
148 winOptions := THTopWindow.Create('Holmes Options', 100, 100);
149 winOptions.escClose := true;
150 winOptions.appendChild(llb);
151 end;
154 procedure createLayersWindow ();
155 var
156 llb: THCtlCBListBox;
157 begin
158 llb := THCtlCBListBox.Create(0, 0);
159 llb.appendItem('background', @g_rlayer_back);
160 llb.appendItem('steps', @g_rlayer_step);
161 llb.appendItem('walls', @g_rlayer_wall);
162 llb.appendItem('doors', @g_rlayer_door);
163 llb.appendItem('acid1', @g_rlayer_acid1);
164 llb.appendItem('acid2', @g_rlayer_acid2);
165 llb.appendItem('water', @g_rlayer_water);
166 llb.appendItem('foreground', @g_rlayer_fore);
167 winLayers := THTopWindow.Create('visible', 10, 10);
168 winLayers.escClose := true;
169 winLayers.appendChild(llb);
170 end;
173 procedure createOutlinesWindow ();
174 var
175 llb: THCtlCBListBox;
176 begin
177 llb := THCtlCBListBox.Create(0, 0);
178 llb.appendItem('background', @g_ol_rlayer_back);
179 llb.appendItem('steps', @g_ol_rlayer_step);
180 llb.appendItem('walls', @g_ol_rlayer_wall);
181 llb.appendItem('doors', @g_ol_rlayer_door);
182 llb.appendItem('acid1', @g_ol_rlayer_acid1);
183 llb.appendItem('acid2', @g_ol_rlayer_acid2);
184 llb.appendItem('water', @g_ol_rlayer_water);
185 llb.appendItem('foreground', @g_ol_rlayer_fore);
186 llb.appendItem('', nil);
187 llb.appendItem('slow''n''nice', @g_ol_nice);
188 winOutlines := THTopWindow.Create('outlines', 100, 10);
189 winOutlines.escClose := true;
190 winOutlines.appendChild(llb);
191 end;
194 // ////////////////////////////////////////////////////////////////////////// //
195 procedure g_Holmes_VidModeChanged ();
196 begin
197 e_WriteLog(Format('Inspector: videomode changed: %dx%d', [gScreenWidth, gScreenHeight]), MSG_NOTIFY);
198 // texture space is possibly lost here, idc
199 curtexid := 0;
200 font6texid := 0;
201 font8texid := 0;
202 prfont6texid := 0;
203 prfont8texid := 0;
204 //createCursorTexture();
205 end;
207 procedure g_Holmes_WindowFocused ();
208 begin
209 msB := 0;
210 kbS := 0;
211 end;
213 procedure g_Holmes_WindowBlured ();
214 begin
215 end;
218 // ////////////////////////////////////////////////////////////////////////// //
219 var
220 vpSet: Boolean = false;
221 vpx, vpy: Integer;
222 vpw, vph: Integer;
223 laserSet: Boolean = false;
224 laserX0, laserY0, laserX1, laserY1: Integer;
225 monMarkedUID: Integer = -1;
228 procedure g_Holmes_plrView (viewPortX, viewPortY, viewPortW, viewPortH: Integer);
229 begin
230 vpSet := true;
231 vpx := viewPortX;
232 vpy := viewPortY;
233 vpw := viewPortW;
234 vph := viewPortH;
235 end;
237 procedure g_Holmes_plrLaser (ax0, ay0, ax1, ay1: Integer);
238 begin
239 laserSet := true;
240 laserX0 := ax0;
241 laserY0 := ay0;
242 laserX1 := ax1;
243 laserY1 := ay1;
244 laserSet := laserSet; // shut up, fpc!
245 end;
248 function pmsCurMapX (): Integer; inline; begin result := msX+vpx; end;
249 function pmsCurMapY (): Integer; inline; begin result := msY+vpy; end;
252 procedure plrDebugMouse (var ev: THMouseEvent);
254 function wallToggle (pan: TPanel; tag: Integer): Boolean;
255 begin
256 result := false; // don't stop
257 e_WriteLog(Format('wall #%d(%d); enabled=%d (%d); (%d,%d)-(%d,%d)', [pan.arrIdx, pan.proxyId, Integer(pan.Enabled), Integer(mapGrid.proxyEnabled[pan.proxyId]), pan.X, pan.Y, pan.Width, pan.Height]), MSG_NOTIFY);
258 if ((kbS and THKeyEvent.ModAlt) <> 0) then
259 begin
260 if pan.Enabled then g_Map_DisableWall(pan.arrIdx) else g_Map_EnableWall(pan.arrIdx);
261 end;
262 end;
264 function monsAtDump (mon: TMonster; tag: Integer): Boolean;
265 begin
266 result := false; // don't stop
267 e_WriteLog(Format('monster #%d; UID=%d', [mon.arrIdx, mon.UID]), MSG_NOTIFY);
268 monMarkedUID := mon.UID;
269 //if pan.Enabled then g_Map_DisableWall(pan.arrIdx) else g_Map_EnableWall(pan.arrIdx);
270 end;
272 function monsInCell (mon: TMonster; tag: Integer): Boolean;
273 begin
274 result := false; // don't stop
275 e_WriteLog(Format('monster #%d (UID:%u) (proxyid:%d)', [mon.arrIdx, mon.UID, mon.proxyId]), MSG_NOTIFY);
276 end;
278 begin
279 //e_WriteLog(Format('mouse: x=%d; y=%d; but=%d; bstate=%d', [msx, msy, but, bstate]), MSG_NOTIFY);
280 if (gPlayer1 = nil) or not vpSet then exit;
281 if (ev.kind <> THMouseEvent.Press) then exit;
283 e_WriteLog(Format('mev: %d', [Integer(ev.kind)]), MSG_NOTIFY);
285 if (ev.but = THMouseEvent.Left) then
286 begin
287 if ((kbS and THKeyEvent.ModShift) <> 0) then
288 begin
289 // dump monsters in cell
290 e_WriteLog('===========================', MSG_NOTIFY);
291 monsGrid.forEachInCell(pmsCurMapX, pmsCurMapY, monsInCell);
292 e_WriteLog('---------------------------', MSG_NOTIFY);
293 end
294 else
295 begin
296 // toggle wall
297 e_WriteLog('=== TOGGLE WALL ===', MSG_NOTIFY);
298 mapGrid.forEachAtPoint(pmsCurMapX, pmsCurMapY, wallToggle, (GridTagWall or GridTagDoor));
299 e_WriteLog('--- toggle wall ---', MSG_NOTIFY);
300 end;
301 exit;
302 end;
304 if (ev.but = THMouseEvent.Right) then
305 begin
306 monMarkedUID := -1;
307 e_WriteLog('===========================', MSG_NOTIFY);
308 monsGrid.forEachAtPoint(pmsCurMapX, pmsCurMapY, monsAtDump);
309 e_WriteLog('---------------------------', MSG_NOTIFY);
310 exit;
311 end;
312 end;
315 var
316 edgeBmp: array of Byte = nil;
319 procedure drawOutlines ();
320 procedure clearEdgeBmp ();
321 begin
322 SetLength(edgeBmp, (gWinSizeX+4)*(gWinSizeY+4));
323 FillChar(edgeBmp[0], Length(edgeBmp)*sizeof(edgeBmp[0]), 0);
324 end;
326 procedure drawPanel (pan: TPanel);
327 var
328 sx, len, y0, y1: Integer;
329 begin
330 if (pan = nil) or (pan.Width < 1) or (pan.Height < 1) then exit;
331 if (pan.X+pan.Width <= vpx-1) or (pan.Y+pan.Height <= vpy-1) or (pan.X >= vpx+vpw+1) or (pan.Y >= vpy+vph+1) then exit;
332 if g_ol_nice then
333 begin
334 sx := pan.X-(vpx-1);
335 len := pan.Width;
336 if (len > vpw+2) then len := vpw+2;
337 if (sx < 0) then begin len += sx; sx := 0; end;
338 if (sx+len > vpw+2) then len := vpw+2-sx;
339 if (len < 1) then exit;
340 assert(sx >= 0);
341 assert(sx+len <= vpw+2);
342 y0 := pan.Y-(vpy-1);
343 y1 := y0+pan.Height;
344 if (y0 < 0) then y0 := 0;
345 if (y1 > vph+2) then y1 := vph+2;
346 while (y0 < y1) do
347 begin
348 FillChar(edgeBmp[y0*(gWinSizeX+4)+sx], len*sizeof(edgeBmp[0]), 1);
349 Inc(y0);
350 end;
351 end
352 else
353 begin
354 drawRect(pan.X, pan.Y, pan.Width, pan.Height, 255, 255, 255);
355 end;
356 end;
358 procedure drawEdges ();
359 var
360 x, y: Integer;
361 a: PByte;
362 begin
363 glDisable(GL_BLEND);
364 glDisable(GL_TEXTURE_2D);
365 glLineWidth(1);
366 glPointSize(1);
367 glDisable(GL_LINE_SMOOTH);
368 glDisable(GL_POLYGON_SMOOTH);
369 glColor4f(1.0, 1.0, 1.0, 1.0);
370 glBegin(GL_POINTS);
371 for y := 1 to vph do
372 begin
373 a := @edgeBmp[y*(gWinSizeX+4)+1];
374 for x := 1 to vpw do
375 begin
376 if (a[0] <> 0) then
377 begin
378 if (a[-1] = 0) or (a[1] = 0) or (a[-(gWinSizeX+4)] = 0) or (a[gWinSizeX+4] = 0) or
379 (a[-(gWinSizeX+4)-1] = 0) or (a[-(gWinSizeX+4)+1] = 0) or
380 (a[gWinSizeX+4-1] = 0) or (a[gWinSizeX+4+1] = 0) then
381 begin
382 glVertex2f(x-1+vpx+0.37, y-1+vpy+0.37);
383 end;
384 end;
385 Inc(a);
386 end;
387 end;
388 glEnd();
389 end;
391 procedure doWallsOld (parr: array of TPanel; ptype: Word);
392 var
393 f: Integer;
394 pan: TPanel;
395 begin
396 if g_ol_nice then clearEdgeBmp();
397 for f := 0 to High(parr) do
398 begin
399 pan := parr[f];
400 if (pan = nil) or not pan.Enabled or (pan.Width < 1) or (pan.Height < 1) then continue;
401 if ((pan.PanelType and ptype) = 0) then continue;
402 drawPanel(pan);
403 end;
404 if g_ol_nice then drawEdges();
405 end;
407 function doWallCB (pan: TPanel; tag: Integer): Boolean;
408 begin
409 result := false; // don't stop
410 //if (pan = nil) or not pan.Enabled or (pan.Width < 1) or (pan.Height < 1) then exit;
411 drawPanel(pan);
412 end;
414 procedure doWalls (parr: array of TPanel; ptype: Word);
415 begin
416 if g_ol_nice then clearEdgeBmp();
417 mapGrid.forEachInAABB(vpx-1, vpy-1, vpw+2, vph+2, doWallCB, panelTypeToTag(ptype));
418 if g_ol_nice then drawEdges();
419 end;
421 begin
422 if g_ol_rlayer_back then doWalls(gRenderBackgrounds, PANEL_BACK);
423 if g_ol_rlayer_step then doWalls(gSteps, PANEL_STEP);
424 if g_ol_rlayer_wall then doWalls(gWalls, PANEL_WALL);
425 if g_ol_rlayer_door then doWalls(gWalls, PANEL_OPENDOOR or PANEL_CLOSEDOOR);
426 if g_ol_rlayer_acid1 then doWalls(gAcid1, PANEL_ACID1);
427 if g_ol_rlayer_acid2 then doWalls(gAcid2, PANEL_ACID2);
428 if g_ol_rlayer_water then doWalls(gWater, PANEL_WATER);
429 if g_ol_rlayer_fore then doWalls(gRenderForegrounds, PANEL_FORE);
430 end;
433 procedure plrDebugDraw ();
435 procedure drawTileGrid ();
436 var
437 x, y: Integer;
438 begin
439 for y := 0 to (mapGrid.gridHeight div mapGrid.tileSize) do
440 begin
441 drawLine(mapGrid.gridX0, mapGrid.gridY0+y*mapGrid.tileSize, mapGrid.gridX0+mapGrid.gridWidth, mapGrid.gridY0+y*mapGrid.tileSize, 96, 96, 96, 255);
442 end;
444 for x := 0 to (mapGrid.gridWidth div mapGrid.tileSize) do
445 begin
446 drawLine(mapGrid.gridX0+x*mapGrid.tileSize, mapGrid.gridY0, mapGrid.gridX0+x*mapGrid.tileSize, mapGrid.gridY0+y*mapGrid.gridHeight, 96, 96, 96, 255);
447 end;
448 end;
450 procedure hilightCell (cx, cy: Integer);
451 begin
452 fillRect(cx, cy, monsGrid.tileSize, monsGrid.tileSize, 0, 128, 0, 64);
453 end;
455 procedure hilightCell1 (cx, cy: Integer);
456 begin
457 //e_WriteLog(Format('h1: (%d,%d)', [cx, cy]), MSG_NOTIFY);
458 fillRect(cx, cy, monsGrid.tileSize, monsGrid.tileSize, 255, 255, 0, 92);
459 end;
461 function hilightWallTrc (pan: TPanel; tag: Integer; x, y, prevx, prevy: Integer): Boolean;
462 begin
463 result := false; // don't stop
464 if (pan = nil) then exit; // cell completion, ignore
465 //e_WriteLog(Format('h1: (%d,%d)', [cx, cy]), MSG_NOTIFY);
466 fillRect(pan.X, pan.Y, pan.Width, pan.Height, 0, 128, 128, 64);
467 end;
469 function monsCollector (mon: TMonster; tag: Integer): Boolean;
470 var
471 ex, ey: Integer;
472 mx, my, mw, mh: Integer;
473 begin
474 result := false;
475 mon.getMapBox(mx, my, mw, mh);
476 e_DrawQuad(mx, my, mx+mw-1, my+mh-1, 255, 255, 0, 96);
477 if lineAABBIntersects(laserX0, laserY0, laserX1, laserY1, mx, my, mw, mh, ex, ey) then
478 begin
479 e_DrawPoint(8, ex, ey, 0, 255, 0);
480 end;
481 end;
483 procedure drawMonsterInfo (mon: TMonster);
484 var
485 mx, my, mw, mh: Integer;
487 procedure drawMonsterTargetLine ();
488 var
489 emx, emy, emw, emh: Integer;
490 enemy: TMonster;
491 eplr: TPlayer;
492 ex, ey: Integer;
493 begin
494 if (g_GetUIDType(mon.MonsterTargetUID) = UID_PLAYER) then
495 begin
496 eplr := g_Player_Get(mon.MonsterTargetUID);
497 if (eplr <> nil) then eplr.getMapBox(emx, emy, emw, emh) else exit;
498 end
499 else if (g_GetUIDType(mon.MonsterTargetUID) = UID_MONSTER) then
500 begin
501 enemy := g_Monsters_ByUID(mon.MonsterTargetUID);
502 if (enemy <> nil) then enemy.getMapBox(emx, emy, emw, emh) else exit;
503 end
504 else
505 begin
506 exit;
507 end;
508 mon.getMapBox(mx, my, mw, mh);
509 drawLine(mx+mw div 2, my+mh div 2, emx+emw div 2, emy+emh div 2, 255, 0, 0, 255);
510 if (g_Map_traceToNearestWall(mx+mw div 2, my+mh div 2, emx+emw div 2, emy+emh div 2, @ex, @ey) <> nil) then
511 begin
512 drawLine(mx+mw div 2, my+mh div 2, ex, ey, 0, 255, 0, 255);
513 end;
514 end;
516 procedure drawLOS2Plr ();
517 var
518 emx, emy, emw, emh: Integer;
519 eplr: TPlayer;
520 ex, ey: Integer;
521 begin
522 eplr := gPlayers[0];
523 if (eplr = nil) then exit;
524 eplr.getMapBox(emx, emy, emw, emh);
525 mon.getMapBox(mx, my, mw, mh);
526 drawLine(mx+mw div 2, my+mh div 2, emx+emw div 2, emy+emh div 2, 255, 0, 0, 255);
527 {$IF DEFINED(D2F_DEBUG)}
528 //mapGrid.dbgRayTraceTileHitCB := hilightCell1;
529 {$ENDIF}
530 if (g_Map_traceToNearestWall(mx+mw div 2, my+mh div 2, emx+emw div 2, emy+emh div 2, @ex, @ey) <> nil) then
531 //if (mapGrid.traceRay(ex, ey, mx+mw div 2, my+mh div 2, emx+emw div 2, emy+emh div 2, hilightWallTrc, (GridTagWall or GridTagDoor)) <> nil) then
532 begin
533 drawLine(mx+mw div 2, my+mh div 2, ex, ey, 0, 255, 0, 255);
534 end;
535 {$IF DEFINED(D2F_DEBUG)}
536 //mapGrid.dbgRayTraceTileHitCB := nil;
537 {$ENDIF}
538 end;
540 begin
541 if (mon = nil) then exit;
542 mon.getMapBox(mx, my, mw, mh);
543 //mx += mw div 2;
545 monsGrid.forEachBodyCell(mon.proxyId, hilightCell);
547 if showMonsInfo then
548 begin
549 //fillRect(mx-4, my-7*8-6, 110, 7*8+6, 0, 0, 94, 250);
550 darkenRect(mx-4, my-7*8-6, 110, 7*8+6, 128);
551 my -= 8;
552 my -= 2;
554 // type
555 drawText6(mx, my, Format('%s(U:%u)', [monsTypeToString(mon.MonsterType), mon.UID]), 255, 127, 0); my -= 8;
556 // beh
557 drawText6(mx, my, Format('Beh: %s', [monsBehToString(mon.MonsterBehaviour)]), 255, 127, 0); my -= 8;
558 // state
559 drawText6(mx, my, Format('State:%s (%d)', [monsStateToString(mon.MonsterState), mon.MonsterSleep]), 255, 127, 0); my -= 8;
560 // health
561 drawText6(mx, my, Format('Health:%d', [mon.MonsterHealth]), 255, 127, 0); my -= 8;
562 // ammo
563 drawText6(mx, my, Format('Ammo:%d', [mon.MonsterAmmo]), 255, 127, 0); my -= 8;
564 // target
565 drawText6(mx, my, Format('TgtUID:%u', [mon.MonsterTargetUID]), 255, 127, 0); my -= 8;
566 drawText6(mx, my, Format('TgtTime:%d', [mon.MonsterTargetTime]), 255, 127, 0); my -= 8;
567 end;
569 drawMonsterTargetLine();
570 if showMonsLOS2Plr then drawLOS2Plr();
572 property MonsterRemoved: Boolean read FRemoved write FRemoved;
573 property MonsterPain: Integer read FPain write FPain;
574 property MonsterAnim: Byte read FCurAnim write FCurAnim;
576 end;
578 function highlightAllMonsterCells (mon: TMonster): Boolean;
579 begin
580 result := false; // don't stop
581 monsGrid.forEachBodyCell(mon.proxyId, hilightCell);
582 end;
584 var
585 mon: TMonster;
586 mx, my, mw, mh: Integer;
587 begin
588 if (gPlayer1 = nil) then exit;
590 glEnable(GL_SCISSOR_TEST);
591 glScissor(0, gWinSizeY-gPlayerScreenSize.Y-1, vpw, vph);
593 glPushMatrix();
594 glTranslatef(-vpx, -vpy, 0);
596 if (showGrid) then drawTileGrid();
597 drawOutlines();
599 if (laserSet) then g_Mons_AlongLine(laserX0, laserY0, laserX1, laserY1, monsCollector, true);
601 if (monMarkedUID <> -1) then
602 begin
603 mon := g_Monsters_ByUID(monMarkedUID);
604 if (mon <> nil) then
605 begin
606 mon.getMapBox(mx, my, mw, mh);
607 e_DrawQuad(mx, my, mx+mw-1, my+mh-1, 255, 0, 0, 30);
608 drawMonsterInfo(mon);
609 end;
610 end;
612 if showAllMonsCells then g_Mons_ForEach(highlightAllMonsterCells);
614 glPopMatrix();
616 glDisable(GL_SCISSOR_TEST);
618 if showMapCurPos then drawText8(4, gWinSizeY-10, Format('mappos:(%d,%d)', [pmsCurMapX, pmsCurMapY]), 255, 255, 0);
619 end;
622 // ////////////////////////////////////////////////////////////////////////// //
623 function g_Holmes_MouseEvent (var ev: THMouseEvent): Boolean;
624 begin
625 result := true;
626 msX := ev.x;
627 msY := ev.y;
628 msB := ev.bstate;
629 kbS := ev.kstate;
630 msB := msB;
631 if not uiMouseEvent(ev) then plrDebugMouse(ev);
632 end;
635 function g_Holmes_KeyEvent (var ev: THKeyEvent): Boolean;
636 var
637 mon: TMonster;
638 pan: TPanel;
639 x, y, w, h: Integer;
640 ex, ey: Integer;
641 dx, dy: Integer;
643 procedure dummyWallTrc (cx, cy: Integer);
644 begin
645 end;
647 begin
648 result := false;
649 msB := ev.bstate;
650 kbS := ev.kstate;
651 case ev.scan of
652 SDL_SCANCODE_LCTRL, SDL_SCANCODE_RCTRL,
653 SDL_SCANCODE_LALT, SDL_SCANCODE_RALT,
654 SDL_SCANCODE_LSHIFT, SDL_SCANCODE_RSHIFT:
655 result := true;
656 end;
657 if uiKeyEvent(ev) then begin result := true; exit; end;
658 // press
659 if (ev.kind = THKeyEvent.Press) then
660 begin
661 // M-M: one monster think step
662 if (ev.scan = SDL_SCANCODE_M) and ((ev.kstate and THKeyEvent.ModAlt) <> 0) then
663 begin
664 result := true;
665 gmon_debug_think := false;
666 gmon_debug_one_think_step := true; // do one step
667 exit;
668 end;
669 // M-I: toggle monster info
670 if (ev.scan = SDL_SCANCODE_I) and ((ev.kstate and THKeyEvent.ModAlt) <> 0) then
671 begin
672 result := true;
673 showMonsInfo := not showMonsInfo;
674 exit;
675 end;
676 // M-L: toggle monster LOS to player
677 if (ev.scan = SDL_SCANCODE_L) and ((ev.kstate and THKeyEvent.ModAlt) <> 0) then
678 begin
679 result := true;
680 showMonsLOS2Plr := not showMonsLOS2Plr;
681 exit;
682 end;
683 // M-G: toggle "show all cells occupied by monsters"
684 if (ev.scan = SDL_SCANCODE_G) and ((ev.kstate and THKeyEvent.ModAlt) <> 0) then
685 begin
686 result := true;
687 showAllMonsCells := not showAllMonsCells;
688 exit;
689 end;
690 // M-A: wake up monster
691 if (ev.scan = SDL_SCANCODE_A) and ((ev.kstate and THKeyEvent.ModAlt) <> 0) then
692 begin
693 result := true;
694 if (monMarkedUID <> -1) then
695 begin
696 mon := g_Monsters_ByUID(monMarkedUID);
697 if (mon <> nil) then mon.WakeUp();
698 end;
699 exit;
700 end;
701 // C-T: teleport player
702 if (ev.scan = SDL_SCANCODE_T) and ((ev.kstate and THKeyEvent.ModCtrl) <> 0) then
703 begin
704 result := true;
705 //e_WriteLog(Format('TELEPORT: (%d,%d)', [pmsCurMapX, pmsCurMapY]), MSG_NOTIFY);
706 if (gPlayers[0] <> nil) then
707 begin
708 gPlayers[0].getMapBox(x, y, w, h);
709 gPlayers[0].TeleportTo(pmsCurMapX-w div 2, pmsCurMapY-h div 2, true, 69); // 69: don't change dir
710 end;
711 exit;
712 end;
713 // C-P: show cursor position on the map
714 if (ev.scan = SDL_SCANCODE_P) and ((ev.kstate and THKeyEvent.ModCtrl) <> 0) then
715 begin
716 result := true;
717 showMapCurPos := not showMapCurPos;
718 exit;
719 end;
720 // C-G: toggle grid
721 if (ev.scan = SDL_SCANCODE_G) and ((ev.kstate and THKeyEvent.ModCtrl) <> 0) then
722 begin
723 result := true;
724 showGrid := not showGrid;
725 exit;
726 end;
727 // C-L: toggle layers window
728 if (ev.scan = SDL_SCANCODE_L) and ((ev.kstate and THKeyEvent.ModCtrl) <> 0) then
729 begin
730 result := true;
731 if (winLayers = nil) then createLayersWindow();
732 if not uiVisibleWindow(winLayers) then uiAddWindow(winLayers) else uiRemoveWindow(winLayers);
733 exit;
734 end;
735 // C-O: toggle outlines window
736 if (ev.scan = SDL_SCANCODE_O) and ((ev.kstate and THKeyEvent.ModCtrl) <> 0) then
737 begin
738 result := true;
739 if (winOutlines = nil) then createOutlinesWindow();
740 if not uiVisibleWindow(winOutlines) then uiAddWindow(winOutlines) else uiRemoveWindow(winOutlines);
741 exit;
742 end;
743 // F1: toggle options window
744 if (ev.scan = SDL_SCANCODE_F1) and (ev.kstate = 0) then
745 begin
746 result := true;
747 if (winOptions = nil) then createOptionsWindow();
748 if not uiVisibleWindow(winOptions) then uiAddWindow(winOptions) else uiRemoveWindow(winOptions);
749 exit;
750 end;
751 // C-UP, C-DOWN, C-LEFT, C-RIGHT: trace 10 pixels from cursor in the respective direction
752 if ((ev.scan = SDL_SCANCODE_UP) or (ev.scan = SDL_SCANCODE_DOWN) or (ev.scan = SDL_SCANCODE_LEFT) or (ev.scan = SDL_SCANCODE_RIGHT)) and
753 ((ev.kstate and THKeyEvent.ModCtrl) <> 0) then
754 begin
755 result := true;
756 dx := pmsCurMapX;
757 dy := pmsCurMapY;
758 case ev.scan of
759 SDL_SCANCODE_UP: dy -= 120;
760 SDL_SCANCODE_DOWN: dy += 120;
761 SDL_SCANCODE_LEFT: dx -= 120;
762 SDL_SCANCODE_RIGHT: dx += 120;
763 end;
764 {$IF DEFINED(D2F_DEBUG)}
765 //mapGrid.dbgRayTraceTileHitCB := dummyWallTrc;
766 mapGrid.dbgShowTraceLog := true;
767 {$ENDIF}
768 pan := g_Map_traceToNearest(pmsCurMapX, pmsCurMapY, dx, dy, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey);
769 {$IF DEFINED(D2F_DEBUG)}
770 //mapGrid.dbgRayTraceTileHitCB := nil;
771 mapGrid.dbgShowTraceLog := false;
772 {$ENDIF}
773 e_LogWritefln('v-trace: (%d,%d)-(%d,%d); end=(%d,%d); hit=%d', [pmsCurMapX, pmsCurMapY, dx, dy, ex, ey, (pan <> nil)]);
774 exit;
775 end;
776 end;
777 end;
780 // ////////////////////////////////////////////////////////////////////////// //
781 procedure g_Holmes_Draw ();
782 begin
783 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // modify color buffer
784 glDisable(GL_STENCIL_TEST);
785 glDisable(GL_BLEND);
786 glDisable(GL_SCISSOR_TEST);
787 glDisable(GL_TEXTURE_2D);
789 if gGameOn then
790 begin
791 plrDebugDraw();
792 end;
794 laserSet := false;
795 end;
798 procedure g_Holmes_DrawUI ();
799 begin
800 uiDraw();
801 drawCursor();
802 end;
805 end.