DEADSOFTWARE

Holmes UI fixes
[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;
111 showLayersWindow: Boolean = false;
112 showOutlineWindow: Boolean = false;
113 oldShowLayersWindow: Boolean = false;
114 oldShowOutlineWindow: Boolean = false;
116 // ////////////////////////////////////////////////////////////////////////// //
117 {$INCLUDE g_holmes.inc}
118 {$INCLUDE g_holmes_ui.inc}
121 // ////////////////////////////////////////////////////////////////////////// //
122 var
123 g_ol_nice: Boolean = false;
124 g_ol_fill_walls: Boolean = false;
125 g_ol_rlayer_back: Boolean = false;
126 g_ol_rlayer_step: Boolean = false;
127 g_ol_rlayer_wall: Boolean = false;
128 g_ol_rlayer_door: Boolean = false;
129 g_ol_rlayer_acid1: Boolean = false;
130 g_ol_rlayer_acid2: Boolean = false;
131 g_ol_rlayer_water: Boolean = false;
132 g_ol_rlayer_fore: Boolean = false;
135 // ////////////////////////////////////////////////////////////////////////// //
136 var
137 winOptions: THTopWindow = nil;
138 winLayers: THTopWindow = nil;
139 winOutlines: THTopWindow = nil;
142 procedure createOptionsWindow ();
143 var
144 llb: THCtlCBListBox;
145 begin
146 llb := THCtlCBListBox.Create(0, 0);
147 llb.appendItem('map grid', @showGrid);
148 llb.appendItem('cursor position on map', @showMapCurPos);
149 llb.appendItem('monster info', @showMonsInfo);
150 llb.appendItem('monster LOS to player', @showMonsLOS2Plr);
151 llb.appendItem('monster cells (SLOW!)', @showAllMonsCells);
152 llb.appendItem('WINDOWS', nil);
153 llb.appendItem('layers window', @showLayersWindow);
154 llb.appendItem('outline window', @showOutlineWindow);
155 winOptions := THTopWindow.Create('Holmes Options', 100, 100);
156 winOptions.escClose := true;
157 winOptions.appendChild(llb);
158 end;
161 procedure createLayersWindow ();
162 var
163 llb: THCtlCBListBox;
164 begin
165 llb := THCtlCBListBox.Create(0, 0);
166 llb.appendItem('background', @g_rlayer_back);
167 llb.appendItem('steps', @g_rlayer_step);
168 llb.appendItem('walls', @g_rlayer_wall);
169 llb.appendItem('doors', @g_rlayer_door);
170 llb.appendItem('acid1', @g_rlayer_acid1);
171 llb.appendItem('acid2', @g_rlayer_acid2);
172 llb.appendItem('water', @g_rlayer_water);
173 llb.appendItem('foreground', @g_rlayer_fore);
174 winLayers := THTopWindow.Create('visible', 10, 10);
175 winLayers.escClose := true;
176 winLayers.appendChild(llb);
177 end;
180 procedure createOutlinesWindow ();
181 var
182 llb: THCtlCBListBox;
183 begin
184 llb := THCtlCBListBox.Create(0, 0);
185 llb.appendItem('background', @g_ol_rlayer_back);
186 llb.appendItem('steps', @g_ol_rlayer_step);
187 llb.appendItem('walls', @g_ol_rlayer_wall);
188 llb.appendItem('doors', @g_ol_rlayer_door);
189 llb.appendItem('acid1', @g_ol_rlayer_acid1);
190 llb.appendItem('acid2', @g_ol_rlayer_acid2);
191 llb.appendItem('water', @g_ol_rlayer_water);
192 llb.appendItem('foreground', @g_ol_rlayer_fore);
193 llb.appendItem('OPTIONS', nil);
194 llb.appendItem('fill walls', @g_ol_fill_walls);
195 llb.appendItem('contours', @g_ol_nice);
196 winOutlines := THTopWindow.Create('outlines', 100, 10);
197 winOutlines.escClose := true;
198 winOutlines.appendChild(llb);
199 end;
202 // ////////////////////////////////////////////////////////////////////////// //
203 procedure g_Holmes_VidModeChanged ();
204 begin
205 e_WriteLog(Format('Holmes: videomode changed: %dx%d', [gScreenWidth, gScreenHeight]), MSG_NOTIFY);
206 // texture space is possibly lost here, idc
207 curtexid := 0;
208 font6texid := 0;
209 font8texid := 0;
210 prfont6texid := 0;
211 prfont8texid := 0;
212 //createCursorTexture();
213 end;
215 procedure g_Holmes_WindowFocused ();
216 begin
217 msB := 0;
218 kbS := 0;
219 end;
221 procedure g_Holmes_WindowBlured ();
222 begin
223 end;
226 // ////////////////////////////////////////////////////////////////////////// //
227 var
228 vpSet: Boolean = false;
229 vpx, vpy: Integer;
230 vpw, vph: Integer;
231 laserSet: Boolean = false;
232 laserX0, laserY0, laserX1, laserY1: Integer;
233 monMarkedUID: Integer = -1;
236 procedure g_Holmes_plrView (viewPortX, viewPortY, viewPortW, viewPortH: Integer);
237 begin
238 vpSet := true;
239 vpx := viewPortX;
240 vpy := viewPortY;
241 vpw := viewPortW;
242 vph := viewPortH;
243 end;
245 procedure g_Holmes_plrLaser (ax0, ay0, ax1, ay1: Integer);
246 begin
247 laserSet := true;
248 laserX0 := ax0;
249 laserY0 := ay0;
250 laserX1 := ax1;
251 laserY1 := ay1;
252 laserSet := laserSet; // shut up, fpc!
253 end;
256 function pmsCurMapX (): Integer; inline; begin result := msX+vpx; end;
257 function pmsCurMapY (): Integer; inline; begin result := msY+vpy; end;
260 procedure plrDebugMouse (var ev: THMouseEvent);
262 function wallToggle (pan: TPanel; tag: Integer): Boolean;
263 begin
264 result := false; // don't stop
265 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);
266 if ((kbS and THKeyEvent.ModAlt) <> 0) then
267 begin
268 if pan.Enabled then g_Map_DisableWall(pan.arrIdx) else g_Map_EnableWall(pan.arrIdx);
269 end;
270 end;
272 function monsAtDump (mon: TMonster; tag: Integer): Boolean;
273 begin
274 result := false; // don't stop
275 e_WriteLog(Format('monster #%d; UID=%d', [mon.arrIdx, mon.UID]), MSG_NOTIFY);
276 monMarkedUID := mon.UID;
277 //if pan.Enabled then g_Map_DisableWall(pan.arrIdx) else g_Map_EnableWall(pan.arrIdx);
278 end;
280 function monsInCell (mon: TMonster; tag: Integer): Boolean;
281 begin
282 result := false; // don't stop
283 e_WriteLog(Format('monster #%d (UID:%u) (proxyid:%d)', [mon.arrIdx, mon.UID, mon.proxyId]), MSG_NOTIFY);
284 end;
286 begin
287 //e_WriteLog(Format('mouse: x=%d; y=%d; but=%d; bstate=%d', [msx, msy, but, bstate]), MSG_NOTIFY);
288 if (gPlayer1 = nil) or not vpSet then exit;
289 if (ev.kind <> THMouseEvent.Press) then exit;
291 e_WriteLog(Format('mev: %d', [Integer(ev.kind)]), MSG_NOTIFY);
293 if (ev.but = THMouseEvent.Left) then
294 begin
295 if ((kbS and THKeyEvent.ModShift) <> 0) then
296 begin
297 // dump monsters in cell
298 e_WriteLog('===========================', MSG_NOTIFY);
299 monsGrid.forEachInCell(pmsCurMapX, pmsCurMapY, monsInCell);
300 e_WriteLog('---------------------------', MSG_NOTIFY);
301 end
302 else
303 begin
304 // toggle wall
305 e_WriteLog('=== TOGGLE WALL ===', MSG_NOTIFY);
306 mapGrid.forEachAtPoint(pmsCurMapX, pmsCurMapY, wallToggle, (GridTagWall or GridTagDoor));
307 e_WriteLog('--- toggle wall ---', MSG_NOTIFY);
308 end;
309 exit;
310 end;
312 if (ev.but = THMouseEvent.Right) then
313 begin
314 monMarkedUID := -1;
315 e_WriteLog('===========================', MSG_NOTIFY);
316 monsGrid.forEachAtPoint(pmsCurMapX, pmsCurMapY, monsAtDump);
317 e_WriteLog('---------------------------', MSG_NOTIFY);
318 exit;
319 end;
320 end;
323 var
324 edgeBmp: array of Byte = nil;
327 procedure drawOutlines ();
328 var
329 r, g, b: Integer;
331 procedure clearEdgeBmp ();
332 begin
333 SetLength(edgeBmp, (gWinSizeX+4)*(gWinSizeY+4));
334 FillChar(edgeBmp[0], Length(edgeBmp)*sizeof(edgeBmp[0]), 0);
335 end;
337 procedure drawPanel (pan: TPanel);
338 var
339 sx, len, y0, y1: Integer;
340 begin
341 if (pan = nil) or (pan.Width < 1) or (pan.Height < 1) then exit;
342 if (pan.X+pan.Width <= vpx-1) or (pan.Y+pan.Height <= vpy-1) then exit;
343 if (pan.X >= vpx+vpw+1) or (pan.Y >= vpy+vph+1) then exit;
344 if g_ol_nice or g_ol_fill_walls then
345 begin
346 sx := pan.X-(vpx-1);
347 len := pan.Width;
348 if (len > gWinSizeX+4) then len := gWinSizeX+4;
349 if (sx < 0) then begin len += sx; sx := 0; end;
350 if (sx+len > gWinSizeX+4) then len := gWinSizeX+4-sx;
351 if (len < 1) then exit;
352 assert(sx >= 0);
353 assert(sx+len <= gWinSizeX+4);
354 y0 := pan.Y-(vpy-1);
355 y1 := y0+pan.Height;
356 if (y0 < 0) then y0 := 0;
357 if (y1 > gWinSizeY+4) then y1 := gWinSizeY+4;
358 while (y0 < y1) do
359 begin
360 FillChar(edgeBmp[y0*(gWinSizeX+4)+sx], len*sizeof(edgeBmp[0]), 1);
361 Inc(y0);
362 end;
363 end
364 else
365 begin
366 drawRect(pan.X, pan.Y, pan.Width, pan.Height, r, g, b);
367 end;
368 end;
370 var
371 lsx: Integer = -1;
372 lex: Integer = -1;
373 lsy: Integer = -1;
375 procedure flushLine ();
376 begin
377 if (lsy > 0) and (lsx > 0) then
378 begin
379 if (lex = lsx) then
380 begin
381 glBegin(GL_POINTS);
382 glVertex2f(lsx-1+vpx+0.37, lsy-1+vpy+0.37);
383 glEnd();
384 end
385 else
386 begin
387 glBegin(GL_LINES);
388 glVertex2f(lsx-1+vpx+0.37, lsy-1+vpy+0.37);
389 glVertex2f(lex-0+vpx+0.37, lsy-1+vpy+0.37);
390 glEnd();
391 end;
392 end;
393 lsx := -1;
394 lex := -1;
395 end;
397 procedure startLine (y: Integer);
398 begin
399 flushLine();
400 lsy := y;
401 end;
403 procedure putPixel (x: Integer);
404 begin
405 if (x < 1) then exit;
406 if (lex+1 <> x) then flushLine();
407 if (lsx < 0) then lsx := x;
408 lex := x;
409 end;
411 procedure drawEdges ();
412 var
413 x, y: Integer;
414 a: PByte;
415 begin
416 glDisable(GL_BLEND);
417 glDisable(GL_TEXTURE_2D);
418 glLineWidth(1);
419 glPointSize(1);
420 glDisable(GL_LINE_SMOOTH);
421 glDisable(GL_POLYGON_SMOOTH);
422 glColor4f(r/255.0, g/255.0, b/255.0, 1.0);
423 for y := 1 to vph do
424 begin
425 a := @edgeBmp[y*(gWinSizeX+4)+1];
426 startLine(y);
427 for x := 1 to vpw do
428 begin
429 if (a[0] <> 0) then
430 begin
431 if (a[-1] = 0) or (a[1] = 0) or (a[-(gWinSizeX+4)] = 0) or (a[gWinSizeX+4] = 0) or
432 (a[-(gWinSizeX+4)-1] = 0) or (a[-(gWinSizeX+4)+1] = 0) or
433 (a[gWinSizeX+4-1] = 0) or (a[gWinSizeX+4+1] = 0) then
434 begin
435 putPixel(x);
436 end;
437 end;
438 Inc(a);
439 end;
440 flushLine();
441 end;
442 end;
444 procedure drawFilledWalls ();
445 var
446 x, y: Integer;
447 a: PByte;
448 begin
449 glDisable(GL_BLEND);
450 glDisable(GL_TEXTURE_2D);
451 glLineWidth(1);
452 glPointSize(1);
453 glDisable(GL_LINE_SMOOTH);
454 glDisable(GL_POLYGON_SMOOTH);
455 glColor4f(r/255.0, g/255.0, b/255.0, 1.0);
456 for y := 1 to vph do
457 begin
458 a := @edgeBmp[y*(gWinSizeX+4)+1];
459 startLine(y);
460 for x := 1 to vpw do
461 begin
462 if (a[0] <> 0) then putPixel(x);
463 Inc(a);
464 end;
465 flushLine();
466 end;
467 end;
469 procedure doWallsOld (parr: array of TPanel; ptype: Word; ar, ag, ab: Integer);
470 var
471 f: Integer;
472 pan: TPanel;
473 begin
474 r := ar;
475 g := ag;
476 b := ab;
477 if g_ol_nice or g_ol_fill_walls then clearEdgeBmp();
478 for f := 0 to High(parr) do
479 begin
480 pan := parr[f];
481 if (pan = nil) or not pan.Enabled or (pan.Width < 1) or (pan.Height < 1) then continue;
482 if ((pan.PanelType and ptype) = 0) then continue;
483 drawPanel(pan);
484 end;
485 if g_ol_nice then drawEdges();
486 if g_ol_fill_walls then drawFilledWalls();
487 end;
489 var
490 xptag: Word;
492 function doWallCB (pan: TPanel; tag: Integer): Boolean;
493 begin
494 result := false; // don't stop
495 //if (pan = nil) or not pan.Enabled or (pan.Width < 1) or (pan.Height < 1) then exit;
496 if ((pan.PanelType and xptag) = 0) then exit;
497 drawPanel(pan);
498 end;
500 procedure doWalls (parr: array of TPanel; ptype: Word; ar, ag, ab: Integer);
501 begin
502 r := ar;
503 g := ag;
504 b := ab;
505 xptag := ptype;
506 if ((ptype and (PANEL_WALL or PANEL_OPENDOOR or PANEL_CLOSEDOOR)) <> 0) then ptype := GridTagWall or GridTagDoor
507 else panelTypeToTag(ptype);
508 if g_ol_nice or g_ol_fill_walls then clearEdgeBmp();
509 mapGrid.forEachInAABB(vpx-1, vpy-1, vpw+2, vph+2, doWallCB, ptype);
510 if g_ol_nice then drawEdges();
511 if g_ol_fill_walls then drawFilledWalls();
512 end;
514 begin
515 if g_ol_rlayer_back then doWallsOld(gRenderBackgrounds, PANEL_BACK, 255, 127, 0);
516 if g_ol_rlayer_step then doWallsOld(gSteps, PANEL_STEP, 192, 192, 192);
517 if g_ol_rlayer_wall then doWallsOld(gWalls, PANEL_WALL, 255, 255, 255);
518 if g_ol_rlayer_door then doWallsOld(gWalls, PANEL_OPENDOOR or PANEL_CLOSEDOOR, 0, 255, 0);
519 if g_ol_rlayer_acid1 then doWallsOld(gAcid1, PANEL_ACID1, 255, 0, 0);
520 if g_ol_rlayer_acid2 then doWallsOld(gAcid2, PANEL_ACID2, 198, 198, 0);
521 if g_ol_rlayer_water then doWallsOld(gWater, PANEL_WATER, 0, 255, 255);
522 if g_ol_rlayer_fore then doWallsOld(gRenderForegrounds, PANEL_FORE, 210, 210, 210);
523 end;
526 procedure plrDebugDraw ();
528 procedure drawTileGrid ();
529 var
530 x, y: Integer;
531 begin
532 for y := 0 to (mapGrid.gridHeight div mapGrid.tileSize) do
533 begin
534 drawLine(mapGrid.gridX0, mapGrid.gridY0+y*mapGrid.tileSize, mapGrid.gridX0+mapGrid.gridWidth, mapGrid.gridY0+y*mapGrid.tileSize, 96, 96, 96, 255);
535 end;
537 for x := 0 to (mapGrid.gridWidth div mapGrid.tileSize) do
538 begin
539 drawLine(mapGrid.gridX0+x*mapGrid.tileSize, mapGrid.gridY0, mapGrid.gridX0+x*mapGrid.tileSize, mapGrid.gridY0+y*mapGrid.gridHeight, 96, 96, 96, 255);
540 end;
541 end;
543 procedure hilightCell (cx, cy: Integer);
544 begin
545 fillRect(cx, cy, monsGrid.tileSize, monsGrid.tileSize, 0, 128, 0, 64);
546 end;
548 procedure hilightCell1 (cx, cy: Integer);
549 begin
550 //e_WriteLog(Format('h1: (%d,%d)', [cx, cy]), MSG_NOTIFY);
551 fillRect(cx, cy, monsGrid.tileSize, monsGrid.tileSize, 255, 255, 0, 92);
552 end;
554 function hilightWallTrc (pan: TPanel; tag: Integer; x, y, prevx, prevy: Integer): Boolean;
555 begin
556 result := false; // don't stop
557 if (pan = nil) then exit; // cell completion, ignore
558 //e_WriteLog(Format('h1: (%d,%d)', [cx, cy]), MSG_NOTIFY);
559 fillRect(pan.X, pan.Y, pan.Width, pan.Height, 0, 128, 128, 64);
560 end;
562 function monsCollector (mon: TMonster; tag: Integer): Boolean;
563 var
564 ex, ey: Integer;
565 mx, my, mw, mh: Integer;
566 begin
567 result := false;
568 mon.getMapBox(mx, my, mw, mh);
569 e_DrawQuad(mx, my, mx+mw-1, my+mh-1, 255, 255, 0, 96);
570 if lineAABBIntersects(laserX0, laserY0, laserX1, laserY1, mx, my, mw, mh, ex, ey) then
571 begin
572 e_DrawPoint(8, ex, ey, 0, 255, 0);
573 end;
574 end;
576 procedure drawMonsterInfo (mon: TMonster);
577 var
578 mx, my, mw, mh: Integer;
580 procedure drawMonsterTargetLine ();
581 var
582 emx, emy, emw, emh: Integer;
583 enemy: TMonster;
584 eplr: TPlayer;
585 ex, ey: Integer;
586 begin
587 if (g_GetUIDType(mon.MonsterTargetUID) = UID_PLAYER) then
588 begin
589 eplr := g_Player_Get(mon.MonsterTargetUID);
590 if (eplr <> nil) then eplr.getMapBox(emx, emy, emw, emh) else exit;
591 end
592 else if (g_GetUIDType(mon.MonsterTargetUID) = UID_MONSTER) then
593 begin
594 enemy := g_Monsters_ByUID(mon.MonsterTargetUID);
595 if (enemy <> nil) then enemy.getMapBox(emx, emy, emw, emh) else exit;
596 end
597 else
598 begin
599 exit;
600 end;
601 mon.getMapBox(mx, my, mw, mh);
602 drawLine(mx+mw div 2, my+mh div 2, emx+emw div 2, emy+emh div 2, 255, 0, 0, 255);
603 if (g_Map_traceToNearestWall(mx+mw div 2, my+mh div 2, emx+emw div 2, emy+emh div 2, @ex, @ey) <> nil) then
604 begin
605 drawLine(mx+mw div 2, my+mh div 2, ex, ey, 0, 255, 0, 255);
606 end;
607 end;
609 procedure drawLOS2Plr ();
610 var
611 emx, emy, emw, emh: Integer;
612 eplr: TPlayer;
613 ex, ey: Integer;
614 begin
615 eplr := gPlayers[0];
616 if (eplr = nil) then exit;
617 eplr.getMapBox(emx, emy, emw, emh);
618 mon.getMapBox(mx, my, mw, mh);
619 drawLine(mx+mw div 2, my+mh div 2, emx+emw div 2, emy+emh div 2, 255, 0, 0, 255);
620 {$IF DEFINED(D2F_DEBUG)}
621 //mapGrid.dbgRayTraceTileHitCB := hilightCell1;
622 {$ENDIF}
623 if (g_Map_traceToNearestWall(mx+mw div 2, my+mh div 2, emx+emw div 2, emy+emh div 2, @ex, @ey) <> nil) then
624 //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
625 begin
626 drawLine(mx+mw div 2, my+mh div 2, ex, ey, 0, 255, 0, 255);
627 end;
628 {$IF DEFINED(D2F_DEBUG)}
629 //mapGrid.dbgRayTraceTileHitCB := nil;
630 {$ENDIF}
631 end;
633 begin
634 if (mon = nil) then exit;
635 mon.getMapBox(mx, my, mw, mh);
636 //mx += mw div 2;
638 monsGrid.forEachBodyCell(mon.proxyId, hilightCell);
640 if showMonsInfo then
641 begin
642 //fillRect(mx-4, my-7*8-6, 110, 7*8+6, 0, 0, 94, 250);
643 darkenRect(mx-4, my-7*8-6, 110, 7*8+6, 128);
644 my -= 8;
645 my -= 2;
647 // type
648 drawText6(mx, my, Format('%s(U:%u)', [monsTypeToString(mon.MonsterType), mon.UID]), 255, 127, 0); my -= 8;
649 // beh
650 drawText6(mx, my, Format('Beh: %s', [monsBehToString(mon.MonsterBehaviour)]), 255, 127, 0); my -= 8;
651 // state
652 drawText6(mx, my, Format('State:%s (%d)', [monsStateToString(mon.MonsterState), mon.MonsterSleep]), 255, 127, 0); my -= 8;
653 // health
654 drawText6(mx, my, Format('Health:%d', [mon.MonsterHealth]), 255, 127, 0); my -= 8;
655 // ammo
656 drawText6(mx, my, Format('Ammo:%d', [mon.MonsterAmmo]), 255, 127, 0); my -= 8;
657 // target
658 drawText6(mx, my, Format('TgtUID:%u', [mon.MonsterTargetUID]), 255, 127, 0); my -= 8;
659 drawText6(mx, my, Format('TgtTime:%d', [mon.MonsterTargetTime]), 255, 127, 0); my -= 8;
660 end;
662 drawMonsterTargetLine();
663 if showMonsLOS2Plr then drawLOS2Plr();
665 property MonsterRemoved: Boolean read FRemoved write FRemoved;
666 property MonsterPain: Integer read FPain write FPain;
667 property MonsterAnim: Byte read FCurAnim write FCurAnim;
669 end;
671 function highlightAllMonsterCells (mon: TMonster): Boolean;
672 begin
673 result := false; // don't stop
674 monsGrid.forEachBodyCell(mon.proxyId, hilightCell);
675 end;
677 var
678 mon: TMonster;
679 mx, my, mw, mh: Integer;
680 begin
681 if (gPlayer1 = nil) then exit;
683 glEnable(GL_SCISSOR_TEST);
684 glScissor(0, gWinSizeY-gPlayerScreenSize.Y-1, vpw, vph);
686 glPushMatrix();
687 glTranslatef(-vpx, -vpy, 0);
689 if (showGrid) then drawTileGrid();
690 drawOutlines();
692 if (laserSet) then g_Mons_AlongLine(laserX0, laserY0, laserX1, laserY1, monsCollector, true);
694 if (monMarkedUID <> -1) then
695 begin
696 mon := g_Monsters_ByUID(monMarkedUID);
697 if (mon <> nil) then
698 begin
699 mon.getMapBox(mx, my, mw, mh);
700 e_DrawQuad(mx, my, mx+mw-1, my+mh-1, 255, 0, 0, 30);
701 drawMonsterInfo(mon);
702 end;
703 end;
705 if showAllMonsCells then g_Mons_ForEach(highlightAllMonsterCells);
707 glPopMatrix();
709 glDisable(GL_SCISSOR_TEST);
711 if showMapCurPos then drawText8(4, gWinSizeY-10, Format('mappos:(%d,%d)', [pmsCurMapX, pmsCurMapY]), 255, 255, 0);
712 end;
715 // ////////////////////////////////////////////////////////////////////////// //
716 function g_Holmes_MouseEvent (var ev: THMouseEvent): Boolean;
717 begin
718 result := true;
719 msX := ev.x;
720 msY := ev.y;
721 msB := ev.bstate;
722 kbS := ev.kstate;
723 msB := msB;
724 if not uiMouseEvent(ev) then plrDebugMouse(ev);
725 end;
728 function g_Holmes_KeyEvent (var ev: THKeyEvent): Boolean;
729 var
730 mon: TMonster;
731 pan: TPanel;
732 x, y, w, h: Integer;
733 ex, ey: Integer;
734 dx, dy: Integer;
736 procedure dummyWallTrc (cx, cy: Integer);
737 begin
738 end;
740 begin
741 result := false;
742 msB := ev.bstate;
743 kbS := ev.kstate;
744 case ev.scan of
745 SDL_SCANCODE_LCTRL, SDL_SCANCODE_RCTRL,
746 SDL_SCANCODE_LALT, SDL_SCANCODE_RALT,
747 SDL_SCANCODE_LSHIFT, SDL_SCANCODE_RSHIFT:
748 result := true;
749 end;
750 if uiKeyEvent(ev) then begin result := true; exit; end;
751 // press
752 if (ev.kind = THKeyEvent.Press) then
753 begin
754 // M-M: one monster think step
755 if (ev.scan = SDL_SCANCODE_M) and ((ev.kstate and THKeyEvent.ModAlt) <> 0) then
756 begin
757 result := true;
758 gmon_debug_think := false;
759 gmon_debug_one_think_step := true; // do one step
760 exit;
761 end;
762 // M-I: toggle monster info
763 if (ev.scan = SDL_SCANCODE_I) and ((ev.kstate and THKeyEvent.ModAlt) <> 0) then
764 begin
765 result := true;
766 showMonsInfo := not showMonsInfo;
767 exit;
768 end;
769 // M-L: toggle monster LOS to player
770 if (ev.scan = SDL_SCANCODE_L) and ((ev.kstate and THKeyEvent.ModAlt) <> 0) then
771 begin
772 result := true;
773 showMonsLOS2Plr := not showMonsLOS2Plr;
774 exit;
775 end;
776 // M-G: toggle "show all cells occupied by monsters"
777 if (ev.scan = SDL_SCANCODE_G) and ((ev.kstate and THKeyEvent.ModAlt) <> 0) then
778 begin
779 result := true;
780 showAllMonsCells := not showAllMonsCells;
781 exit;
782 end;
783 // M-A: wake up monster
784 if (ev.scan = SDL_SCANCODE_A) and ((ev.kstate and THKeyEvent.ModAlt) <> 0) then
785 begin
786 result := true;
787 if (monMarkedUID <> -1) then
788 begin
789 mon := g_Monsters_ByUID(monMarkedUID);
790 if (mon <> nil) then mon.WakeUp();
791 end;
792 exit;
793 end;
794 // C-T: teleport player
795 if (ev.scan = SDL_SCANCODE_T) and ((ev.kstate and THKeyEvent.ModCtrl) <> 0) then
796 begin
797 result := true;
798 //e_WriteLog(Format('TELEPORT: (%d,%d)', [pmsCurMapX, pmsCurMapY]), MSG_NOTIFY);
799 if (gPlayers[0] <> nil) then
800 begin
801 gPlayers[0].getMapBox(x, y, w, h);
802 gPlayers[0].TeleportTo(pmsCurMapX-w div 2, pmsCurMapY-h div 2, true, 69); // 69: don't change dir
803 end;
804 exit;
805 end;
806 // C-P: show cursor position on the map
807 if (ev.scan = SDL_SCANCODE_P) and ((ev.kstate and THKeyEvent.ModCtrl) <> 0) then
808 begin
809 result := true;
810 showMapCurPos := not showMapCurPos;
811 exit;
812 end;
813 // C-G: toggle grid
814 if (ev.scan = SDL_SCANCODE_G) and ((ev.kstate and THKeyEvent.ModCtrl) <> 0) then
815 begin
816 result := true;
817 showGrid := not showGrid;
818 exit;
819 end;
820 // C-L: toggle layers window
821 if (ev.scan = SDL_SCANCODE_L) and ((ev.kstate and THKeyEvent.ModCtrl) <> 0) then
822 begin
823 result := true;
824 showLayersWindow := not showLayersWindow;
825 exit;
826 end;
827 // C-O: toggle outlines window
828 if (ev.scan = SDL_SCANCODE_O) and ((ev.kstate and THKeyEvent.ModCtrl) <> 0) then
829 begin
830 result := true;
831 showOutlineWindow := not showOutlineWindow;
832 exit;
833 end;
834 // F1: toggle options window
835 if (ev.scan = SDL_SCANCODE_F1) and (ev.kstate = 0) then
836 begin
837 result := true;
838 if (winOptions = nil) then createOptionsWindow();
839 if not uiVisibleWindow(winOptions) then uiAddWindow(winOptions) else uiRemoveWindow(winOptions);
840 exit;
841 end;
842 // C-UP, C-DOWN, C-LEFT, C-RIGHT: trace 10 pixels from cursor in the respective direction
843 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
844 ((ev.kstate and THKeyEvent.ModCtrl) <> 0) then
845 begin
846 result := true;
847 dx := pmsCurMapX;
848 dy := pmsCurMapY;
849 case ev.scan of
850 SDL_SCANCODE_UP: dy -= 120;
851 SDL_SCANCODE_DOWN: dy += 120;
852 SDL_SCANCODE_LEFT: dx -= 120;
853 SDL_SCANCODE_RIGHT: dx += 120;
854 end;
855 {$IF DEFINED(D2F_DEBUG)}
856 //mapGrid.dbgRayTraceTileHitCB := dummyWallTrc;
857 mapGrid.dbgShowTraceLog := true;
858 {$ENDIF}
859 pan := g_Map_traceToNearest(pmsCurMapX, pmsCurMapY, dx, dy, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey);
860 {$IF DEFINED(D2F_DEBUG)}
861 //mapGrid.dbgRayTraceTileHitCB := nil;
862 mapGrid.dbgShowTraceLog := false;
863 {$ENDIF}
864 e_LogWritefln('v-trace: (%d,%d)-(%d,%d); end=(%d,%d); hit=%d', [pmsCurMapX, pmsCurMapY, dx, dy, ex, ey, (pan <> nil)]);
865 exit;
866 end;
867 end;
868 end;
871 // ////////////////////////////////////////////////////////////////////////// //
872 procedure g_Holmes_Draw ();
873 begin
874 if (oldShowLayersWindow <> showLayersWindow) then
875 begin
876 oldShowLayersWindow := showLayersWindow;
877 if showLayersWindow then
878 begin
879 if (winLayers = nil) then createLayersWindow();
880 uiAddWindow(winLayers);
881 end
882 else
883 begin
884 uiRemoveWindow(winLayers);
885 end;
886 end
887 else
888 begin
889 showLayersWindow := uiVisibleWindow(winLayers);
890 oldShowLayersWindow := showLayersWindow;
891 end;
893 if (oldShowOutlineWindow <> showOutlineWindow) then
894 begin
895 oldShowOutlineWindow := showOutlineWindow;
896 if showOutlineWindow then
897 begin
898 if (winOutlines = nil) then createOutlinesWindow();
899 uiAddWindow(winOutlines);
900 end
901 else
902 begin
903 uiRemoveWindow(winOutlines);
904 end;
905 end
906 else
907 begin
908 showOutlineWindow := uiVisibleWindow(winOutlines);
909 oldShowOutlineWindow := showOutlineWindow;
910 end;
912 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // modify color buffer
913 glDisable(GL_STENCIL_TEST);
914 glDisable(GL_BLEND);
915 glDisable(GL_SCISSOR_TEST);
916 glDisable(GL_TEXTURE_2D);
918 if gGameOn then
919 begin
920 plrDebugDraw();
921 end;
923 laserSet := false;
924 end;
927 procedure g_Holmes_DrawUI ();
928 begin
929 uiDraw();
930 drawCursor();
931 end;
934 end.