DEADSOFTWARE

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