DEADSOFTWARE

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