From 8cd6b5c965cd6cae75db5f554e61d0d150d08b46 Mon Sep 17 00:00:00 2001 From: Ketmar Dark Date: Tue, 5 Sep 2017 04:48:59 +0300 Subject: [PATCH] mplat fixes --- src/game/g_game.pas | 2 +- src/game/g_map.pas | 24 +++- src/game/g_panel.pas | 238 +++++++++++++++++++++++++++------------- src/game/g_triggers.pas | 1 + src/game/g_window.pas | 5 + src/mapdef/mapdef.txt | 5 + src/shared/MAPDEF.pas | 58 ++++++++++ src/shared/mapdef.inc | 61 ++++++---- src/shared/xdynrec.pas | 59 +++++++++- 9 files changed, 348 insertions(+), 105 deletions(-) diff --git a/src/game/g_game.pas b/src/game/g_game.pas index 58abd6e..c83fb8e 100644 --- a/src/game/g_game.pas +++ b/src/game/g_game.pas @@ -794,7 +794,7 @@ begin {$IF DEFINED(D2F_DEBUG)} if gPlayer1 <> nil then gPlayer1.NoTarget := True; - gAimLine := true; + gAimLine := g_dbg_aimline_on; {$ENDIF} end; diff --git a/src/game/g_map.pas b/src/game/g_map.pas index bbf39cb..101c3c5 100644 --- a/src/game/g_map.pas +++ b/src/game/g_map.pas @@ -1293,10 +1293,11 @@ begin end; end; -procedure CreateTrigger (amapIdx: Integer; Trigger: TDynRecord; atpanid, atrigpanid: Integer; fTexturePanel1Type, fTexturePanel2Type: Word); +function CreateTrigger (amapIdx: Integer; Trigger: TDynRecord; atpanid, atrigpanid: Integer; fTexturePanel1Type, fTexturePanel2Type: Word): Integer; var _trigger: TTrigger; begin + result := -1; if g_Game_IsClient and not (Trigger.TriggerType in [TRIGGER_SOUND, TRIGGER_MUSIC]) then Exit; with _trigger do @@ -1332,7 +1333,7 @@ begin end; end; - g_Triggers_Create(_trigger); + result := Integer(g_Triggers_Create(_trigger)); end; procedure CreateMonster(monster: TDynRecord); @@ -1577,6 +1578,8 @@ type PTRec = ^TTRec; TTRec = record //TexturePanel: Integer; + tnum: Integer; + id: Integer; texPanIdx: Integer; LiftPanelIdx: Integer; DoorPanelIdx: Integer; @@ -1613,6 +1616,7 @@ var stt: UInt64; moveSpeed{, moveStart, moveEnd}: TDFPoint; //moveActive: Boolean; + pan: TPanel; begin mapGrid.Free(); mapGrid := nil; @@ -2057,7 +2061,21 @@ begin else if (TriggersTable[trignum].MPlatPanelIdx <> -1) then tgpid := TriggersTable[trignum].MPlatPanelIdx else tgpid := -1; //e_LogWritefln('creating trigger #%s; texpantype=%s; shotpantype=%s (%d,%d)', [trignum, b, c, TriggersTable[trignum].texPanIdx, TriggersTable[trignum].ShotPanelIdx]); - CreateTrigger(trignum, rec, TriggersTable[trignum].texPanIdx, tgpid, Word(b), Word(c)); + TriggersTable[trignum].tnum := trignum; + TriggersTable[trignum].id := CreateTrigger(trignum, rec, TriggersTable[trignum].texPanIdx, tgpid, Word(b), Word(c)); + end; + end; + + //FIXME: use hashtable! + for pan in panByGUID do + begin + if (pan.endPosTrigId >= 0) and (pan.endPosTrigId < Length(TriggersTable)) then + begin + pan.endPosTrigId := TriggersTable[pan.endPosTrigId].id; + end; + if (pan.endSizeTrigId >= 0) and (pan.endSizeTrigId < Length(TriggersTable)) then + begin + pan.endSizeTrigId := TriggersTable[pan.endSizeTrigId].id; end; end; diff --git a/src/game/g_panel.pas b/src/game/g_panel.pas index 7ea056d..2f54116 100644 --- a/src/game/g_panel.pas +++ b/src/game/g_panel.pas @@ -49,6 +49,13 @@ type mMovingStart: TDFPoint; mMovingEnd: TDFPoint; mMovingActive: Boolean; + mMoveOnce: Boolean; + + mSizeSpeed: TDFSize; + mSizeEnd: TDFSize; + + mEndPosTrig: Integer; + mEndSizeTrig: Integer; private function getx1 (): Integer; inline; @@ -148,6 +155,7 @@ type property movingEndX: Integer read getMovingEndX write setMovingEndX; property movingEndY: Integer read getMovingEndY write setMovingEndY; property movingActive: Boolean read mMovingActive write mMovingActive; + property moveOnce: Boolean read mMoveOnce write mMoveOnce; property isGBack: Boolean read getIsGBack; property isGStep: Boolean read getIsGStep; @@ -163,6 +171,9 @@ type property movingSpeed: TDFPoint read mMovingSpeed write mMovingSpeed; property movingStart: TDFPoint read mMovingStart write mMovingStart; property movingEnd: TDFPoint read mMovingEnd write mMovingEnd; + + property endPosTrigId: Integer read mEndPosTrig write mEndPosTrig; + property endSizeTrigId: Integer read mEndSizeTrig write mEndSizeTrig; end; TPanelArray = Array of TPanel; @@ -175,7 +186,7 @@ var implementation uses - SysUtils, g_basic, g_map, g_game, g_gfx, e_graphics, g_weapons, + SysUtils, g_basic, g_map, g_game, g_gfx, e_graphics, g_weapons, g_triggers, g_console, g_language, g_monsters, g_player, g_grid, e_log, GL, utils; const @@ -208,6 +219,13 @@ begin mMovingStart := PanelRec.moveStart; mMovingEnd := PanelRec.moveEnd; mMovingActive := PanelRec['move_active'].varvalue; + mMoveOnce := PanelRec.moveOnce; + + mSizeSpeed := PanelRec.sizeSpeed; + mSizeEnd := PanelRec.sizeEnd; + + mEndPosTrig := PanelRec.endPosTrig; + mEndSizeTrig := PanelRec.endSizeTrig; // Òèï ïàíåëè: PanelType := PanelRec.PanelType; @@ -503,9 +521,17 @@ begin [arrIdx, mGUID, proxyId, px, py, pw, ph, x, y, width, height]); } g_Mark(px, py, pw, ph, MARK_WALL, false); - if (pw <> Width) or (ph <> Height) then mapGrid.moveResizeBody(proxyId, X, Y, Width, Height) - else mapGrid.moveBody(proxyId, X, Y); - g_Mark(X, Y, Width, Height, MARK_WALL); + if (Width < 1) or (Height < 1) then + begin + mapGrid.proxyEnabled[proxyId] := false; + end + else + begin + mapGrid.proxyEnabled[proxyId] := Enabled; + if (pw <> Width) or (ph <> Height) then mapGrid.moveResizeBody(proxyId, X, Y, Width, Height) + else mapGrid.moveBody(proxyId, X, Y); + g_Mark(X, Y, Width, Height, MARK_WALL); + end; end; end; end; @@ -530,6 +556,7 @@ var pdx, pdy: Integer; pan: TPanel; trtag: Integer; + hedge: Integer; begin squash := false; tex := px; @@ -546,10 +573,12 @@ var begin //e_LogWritefln('entity on the platform; tracing=(%s,%s); endpoint=(%s,%s); mustbe=(%s,%s)', [px, py, tex, tey, px+pdx, py+pdy]); // if we cannot move, only walls should squash the entity + { if ((tag and (GridTagWall or GridTagDoor)) <> 0) then begin if (tex = px) and (tey = py) then squash := true; end; + } end; end else @@ -563,7 +592,7 @@ var e_LogWritefln('entity is embedded: plr=(%s,%s)-(%s,%s); mpl=(%s,%s)-(%s,%s)', [px, py, px+pw-1, py+ph-1, ox, oy, ox+mpw-1, oy+mph-1]); end; } - if sweepAABB(ox, oy, mpw, mph, pdx, pdy, px, py, pw, ph, @u0, nil, @u1) then + if sweepAABB(ox, oy, mpw, mph, pdx, pdy, px, py, pw, ph, @u0, @hedge, @u1) then begin //e_LogWritefln('T: platsweep; u0=%s; u1=%s; hedge=%s; sweepAABB(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)', [u0, u1, hedge, ox, oy, mpw, mph, pdx, pdy, px-1, py-1, pw+2, ph+2]); // yes, platform hits the entity, push the entity in the direction of the platform @@ -580,26 +609,28 @@ var pan := mapGrid.traceBox(tex, tey, px, py, pw, ph, pdx, pdy, nil, trtag); //e_LogWritefln(' tracebox: te=(%s,%s)', [tex, tey]); // if we cannot move, only walls should squash the entity + { if ((tag and (GridTagWall or GridTagDoor)) <> 0) then begin if (pan <> nil) and (tex = px) and (tey = py) then squash := true; end; + } end; end else begin // no collistion, but may be embedded //e_LogWritefln('F: platsweep; u0=%s; u1=%s; sweepAABB(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)', [u0, u1, ox, oy, mpw, mph, pdx, pdy, px-1, py-1, pw+2, ph+2]); - squash := (u1 >= 0.0); + //squash := (u1 >= 0.0); end; end; dx := tex-px; dy := tey-py; result := (dx <> 0) or (dy <> 0); - if result and (not squash) and ((tag and (GridTagWall or GridTagDoor)) <> 0) then + if (not squash) and ((tag and (GridTagWall or GridTagDoor)) <> 0) then begin squash := g_Collide(tex, tey, pw, ph, nx, ny, mpw, mph); // still in platform? - if not squash then squash := g_Map_CollidePanel(tex, tey, pw, ph, (PANEL_WALL or PANEL_OPENDOOR or PANEL_CLOSEDOOR)); + //if not squash then squash := g_Map_CollidePanel(tex, tey, pw, ph, (PANEL_WALL or PANEL_OPENDOOR or PANEL_CLOSEDOOR)); end; end; @@ -622,6 +653,8 @@ var mon: TMonster; mpfrid: LongWord; ontop: Boolean; + actMoveTrig: Boolean; + actSizeTrig: Boolean; begin if (not Enabled) or (Width < 1) or (Height < 1) then exit; @@ -635,8 +668,14 @@ begin FCurFrameCount := FTextureIDs[FCurTexture].AnTex.CurrentCounter; end; + if not g_dbgpan_mplat_active then exit; + + if not mMovingActive then exit; + if mMovingSpeed.isZero and mSizeSpeed.isZero then exit; + + //TODO: write wall size change processing + // moving platform? - if mMovingActive and (not mMovingSpeed.isZero) and g_dbgpan_mplat_active then begin (* * collect all monsters and players (aka entities) along the possible platform path @@ -672,104 +711,149 @@ begin cw := cx1-cx0+1; ch := cy1-cy0+1; - // temporarily turn off this panel, so it won't interfere with collision checks - mapGrid.proxyEnabled[proxyId] := false; - - // process players - for f := 0 to High(gPlayers) do + // process "obstacle" panels + if ((tag and GridTagObstacle) <> 0) then begin - plr := gPlayers[f]; - if (plr = nil) or (not plr.alive) then continue; - plr.getMapBox(px, py, pw, ph); - if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue; - if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash) then + // temporarily turn off this panel, so it won't interfere with collision checks + mapGrid.proxyEnabled[proxyId] := false; + + // process players + for f := 0 to High(gPlayers) do begin - // set new position - plr.moveBy(pdx, pdy); // this will call `positionChanged()` for us + plr := gPlayers[f]; + if (plr = nil) or (not plr.alive) then continue; + plr.getMapBox(px, py, pw, ph); + if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue; + if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash) then + begin + // set new position + plr.moveBy(pdx, pdy); // this will call `positionChanged()` for us + end; // squash player, if necessary if squash then plr.Damage(15000, 0, 0, 0, HIT_TRAP); end; - end; - // process gibs - for f := 0 to High(gGibs) do - begin - gib := @gGibs[f]; - if not gib.alive then continue; - gib.getMapBox(px, py, pw, ph); - if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue; - if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then + // process gibs + for f := 0 to High(gGibs) do begin - // set new position - gib.moveBy(pdx, pdy); // this will call `positionChanged()` for us - { - if ontop then + gib := @gGibs[f]; + if not gib.alive then continue; + gib.getMapBox(px, py, pw, ph); + if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue; + if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then begin - gib.Obj.Vel.X += pdx; - gib.Obj.Vel.Y += pdy; + // set new position + gib.moveBy(pdx, pdy); // this will call `positionChanged()` for us + { + if ontop then + begin + gib.Obj.Vel.X += pdx; + gib.Obj.Vel.Y += pdy; + end; + } end; - } end; - end; - // move and push corpses - for f := 0 to High(gCorpses) do - begin - cor := gCorpses[f]; - if (cor = nil) then continue; - cor.getMapBox(px, py, pw, ph); - if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue; - if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then + // move and push corpses + for f := 0 to High(gCorpses) do begin - // set new position - cor.moveBy(pdx, pdy); // this will call `positionChanged()` for us - { - if ontop then + cor := gCorpses[f]; + if (cor = nil) then continue; + cor.getMapBox(px, py, pw, ph); + if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue; + if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then begin - cor.ObjPtr.Vel.X += pdx; - cor.ObjPtr.Vel.Y += pdy; + // set new position + cor.moveBy(pdx, pdy); // this will call `positionChanged()` for us + { + if ontop then + begin + cor.ObjPtr.Vel.X += pdx; + cor.ObjPtr.Vel.Y += pdy; + end; + } end; - } end; - end; - // collect monsters - monCheckListUsed := 0; - g_Mons_ForEachAt(cx0, cy0, cw, ch, monCollect); + // collect monsters + monCheckListUsed := 0; + g_Mons_ForEachAt(cx0, cy0, cw, ch, monCollect); - // process collected monsters - if (monCheckListUsed > 0) then - begin - mpfrid := g_Mons_getNewMPlatFrameId(); - for f := 0 to monCheckListUsed do + // process collected monsters + if (monCheckListUsed > 0) then begin - mon := monCheckList[f]; - if (mon = nil) or (not mon.alive) or (mon.mplatCheckFrameId = mpfrid) then continue; - mon.mplatCheckFrameId := mpfrid; - mon.getMapBox(px, py, pw, ph); - //if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue; - if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash) then + mpfrid := g_Mons_getNewMPlatFrameId(); + for f := 0 to monCheckListUsed do begin - // set new position - mon.moveBy(pdx, pdy); // this will call `positionChanged()` for us + mon := monCheckList[f]; + if (mon = nil) or (not mon.alive) or (mon.mplatCheckFrameId = mpfrid) then continue; + mon.mplatCheckFrameId := mpfrid; + mon.getMapBox(px, py, pw, ph); + //if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue; + if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash) then + begin + // set new position + mon.moveBy(pdx, pdy); // this will call `positionChanged()` for us + end; // squash player, if necessary if squash then mon.Damage(15000, 0, 0, 0, HIT_TRAP); end; end; + + // restore panel state + mapGrid.proxyEnabled[proxyId] := true; end; - // restore panel state - mapGrid.proxyEnabled[proxyId] := true; - // and really move it + // move panel X := nx; Y := ny; + FWidth += mSizeSpeed.w; + FHeight += mSizeSpeed.h; positionChanged(); + actMoveTrig := false; + actSizeTrig := false; + + { + if not mSizeSpeed.isZero then + begin + e_LogWritefln('ss: size_speed=(%s,%s); size=(%s,%s); move_speed=(%s,%s); oy=%s; ny=%s; etp:%s; ets:%s', [mSizeSpeed.w, mSizeSpeed.h, FWidth, FHeight, mMovingSpeed.X, mMovingSpeed.Y, oy, ny, mEndPosTrig, mEndSizeTrig]); + end; + } + // reverse moving direction, if necessary - if (mMovingSpeed.X < 0) and (nx <= mMovingStart.X) then mMovingSpeed.X := -mMovingSpeed.X - else if (mMovingSpeed.X > 0) and (nx >= mMovingEnd.X) then mMovingSpeed.X := -mMovingSpeed.X; - if (mMovingSpeed.Y < 0) and (ny <= mMovingStart.Y) then mMovingSpeed.Y := -mMovingSpeed.Y - else if (mMovingSpeed.Y > 0) and (ny >= mMovingEnd.Y) then mMovingSpeed.Y := -mMovingSpeed.Y; + if ((mMovingSpeed.X < 0) and (nx <= mMovingStart.X)) or ((mMovingSpeed.X > 0) and (nx >= mMovingEnd.X)) then + begin + if mMoveOnce then mMovingActive := false else mMovingSpeed.X := -mMovingSpeed.X; + actMoveTrig := true; + end; + + if ((mMovingSpeed.Y < 0) and (ny <= mMovingStart.Y)) or ((mMovingSpeed.Y > 0) and (ny >= mMovingEnd.Y)) then + begin + if mMoveOnce then mMovingActive := false else mMovingSpeed.Y := -mMovingSpeed.Y; + actMoveTrig := true; + end; + + // check "size stop" + if not mSizeSpeed.isZero and (Width = mSizeEnd.w) and (Height = mSizeEnd.h) then + begin + mSizeSpeed.w := 0; + mSizeSpeed.h := 0; + actSizeTrig := true; + if (Width < 1) or (Height < 1) then mMovingActive := false; //HACK! + //e_LogWritefln('FUUUUUUUUUUUUUU', []); + end; + + + if actMoveTrig then + begin + g_Triggers_Press(mEndPosTrig, ACTIVATE_CUSTOM); + end; + + if actSizeTrig then + begin + g_Triggers_Press(mEndSizeTrig, ACTIVATE_CUSTOM); + end; end; end; diff --git a/src/game/g_triggers.pas b/src/game/g_triggers.pas index 2da3a1e..97648af 100644 --- a/src/game/g_triggers.pas +++ b/src/game/g_triggers.pas @@ -2608,6 +2608,7 @@ end; procedure g_Triggers_Press(ID: DWORD; ActivateType: Byte; ActivateUID: Word = 0); begin + if (ID >= Length(gTriggers)) then exit; gTriggers[ID].ActivateUID := ActivateUID; ActivateTrigger(gTriggers[ID], ActivateType); end; diff --git a/src/game/g_window.pas b/src/game/g_window.pas index e77934c..0cf15d6 100644 --- a/src/game/g_window.pas +++ b/src/game/g_window.pas @@ -40,6 +40,7 @@ var gwin_dump_extensions: Boolean = false; gwin_has_stencil: Boolean = false; gwin_k8_enable_light_experiments: Boolean = false; + g_dbg_aimline_on: Boolean = false; implementation @@ -872,6 +873,10 @@ begin if arg = '--no-particle-phys' then gpart_dbg_phys_enabled := false; if arg = '--no-particle-physics' then gpart_dbg_phys_enabled := false; + {$IF DEFINED(D2F_DEBUG)} + if arg = '--aimline' then g_dbg_aimline_on := false; + {$ENDIF} + if arg = '--holmes' then begin g_holmes_enabled := true; g_Game_SetDebugMode(); end; if (arg = '--holmes-ui-scale') or (arg = '-holmes-ui-scale') then begin diff --git a/src/mapdef/mapdef.txt b/src/mapdef/mapdef.txt index 4a27ccf..591eadb 100644 --- a/src/mapdef/mapdef.txt +++ b/src/mapdef/mapdef.txt @@ -54,9 +54,14 @@ TPanelRec_1 is "panel" size 18 bytes binblock 2 { Flags is "flags" type ubyte offset 17 bitset PanelFlag default PANEL_FLAG_NONE omitdefault; // moving platform options, not in binary MoveSpeed is "move_speed" type point default (0 0) omitdefault; + SizeSpeed is "size_speed" type point default (0 0) omitdefault; // alas, `size` cannot be negative MoveStart is "move_start" type point default (0 0) omitdefault; MoveEnd is "move_end" type point default (0 0) omitdefault; + SizeEnd is "size_end" type size default (0 0) omitdefault; MoveActive is "move_active" type bool default false omitdefault; + MoveOnce is "move_once" type bool default false omitdefault; + EndPosTrigger is "end_pos_trigger" type int trigger default null omitdefault; + EndSizeTrigger is "end_size_trigger" type int trigger default null omitdefault; // not in binary //Id is "id" type string default "" omitdefault; // internals diff --git a/src/shared/MAPDEF.pas b/src/shared/MAPDEF.pas index ad16025..2e7ec96 100644 --- a/src/shared/MAPDEF.pas +++ b/src/shared/MAPDEF.pas @@ -44,6 +44,17 @@ type function isZero (): Boolean; inline; end; + TDFSize = packed record + public + w, h: LongInt; + + public + constructor Create (aw, ah: LongInt); + + function isZero (): Boolean; inline; + function isValid (): Boolean; inline; + end; + Char16 = packed array[0..15] of Char; Char32 = packed array[0..31] of Char; Char64 = packed array[0..63] of Char; @@ -70,6 +81,7 @@ type function getPanelIndex (pan: TDynRecord): Integer; function getPointField (const aname: AnsiString): TDFPoint; inline; + function getSizeField (const aname: AnsiString): TDFSize; inline; public function panelCount (): Integer; inline; @@ -96,6 +108,14 @@ type function moveStart (): TDFPoint; inline; function moveEnd (): TDFPoint; inline; + function moveOnce (): Boolean; inline; + + function sizeSpeed (): TDFSize; inline; + function sizeEnd (): TDFSize; inline; + + function endPosTrig (): Integer; inline; + function endSizeTrig (): Integer; inline; + // texture function Resource (): AnsiString; inline; function Anim (): Boolean; inline; @@ -155,6 +175,11 @@ constructor TDFPoint.Create (ax, ay: LongInt); begin X := ax; Y := ay; end; function TDFPoint.isZero (): Boolean; inline; begin result := (X = 0) and (Y = 0); end; +constructor TDFSize.Create (aw, ah: LongInt); begin w := aw; h := ah; end; +function TDFSize.isZero (): Boolean; inline; begin result := (w = 0) and (h = 0); end; +function TDFSize.isValid (): Boolean; inline; begin result := (w > 0) and (h > 0); end; + + // ////////////////////////////////////////////////////////////////////////// // function TDynRecordHelper.getUserPanelId (): Integer; inline; var @@ -193,6 +218,28 @@ function TDynRecordHelper.moveSpeed (): TDFPoint; inline; begin result := getPoi function TDynRecordHelper.moveStart (): TDFPoint; inline; begin result := getPointField('move_start'); end; function TDynRecordHelper.moveEnd (): TDFPoint; inline; begin result := getPointField('move_end'); end; +function TDynRecordHelper.sizeSpeed (): TDFSize; inline; begin result := getSizeField('size_speed'); end; +function TDynRecordHelper.sizeEnd (): TDFSize; inline; begin result := getSizeField('size_end'); end; + +function TDynRecordHelper.moveOnce (): Boolean; inline; begin result := (getFieldWithType('move_once', TDynField.TType.TBool).ival <> 0); end; + + +function TDynRecordHelper.endPosTrig (): Integer; inline; +var + fld: TDynField; +begin + fld := getFieldWithType('end_pos_trigger', TDynField.TType.TInt); + result := fld.recrefIndex; +end; + +function TDynRecordHelper.endSizeTrig (): Integer; inline; +var + fld: TDynField; +begin + fld := getFieldWithType('end_size_trigger', TDynField.TType.TInt); + result := fld.recrefIndex; +end; + // ////////////////////////////////////////////////////////////////////////// // function TDynRecordHelper.getFieldWithType (const aname: AnsiString; atype: TDynField.TType): TDynField; inline; @@ -214,6 +261,17 @@ begin end; +function TDynRecordHelper.getSizeField (const aname: AnsiString): TDFSize; inline; +var + fld: TDynField; +begin + fld := field[aname]; + if (fld = nil) then raise Exception.Create(Format('field ''%s'' not found in record ''%s'' of type ''%s''', [aname, name, id])); + if (fld.baseType <> TSize) and (fld.baseType <> TPoint) then raise Exception.Create(Format('field ''%s'' in record ''%s'' of type ''%s'' has invalid data type', [aname, name, id])); + result := TDFSize.Create(fld.ival, fld.ival2); +end; + + function TDynRecordHelper.getPanelByIdx (idx: Integer): TDynRecord; inline; var fld: TDynField; diff --git a/src/shared/mapdef.inc b/src/shared/mapdef.inc index b74ebfc..c4ab984 100644 --- a/src/shared/mapdef.inc +++ b/src/shared/mapdef.inc @@ -379,28 +379,47 @@ const defaultMapDef: AnsiString = ''+ #10#32#32#77#111#118#101#83#112#101#101#100#32#105#115#32#34#109#111#118#101+ #95#115#112#101#101#100#34#32#116#121#112#101#32#112#111#105#110#116#32#100+ #101#102#97#117#108#116#32#40#48#32#48#41#32#111#109#105#116#100#101#102#97+ - #117#108#116#59#10#32#32#77#111#118#101#83#116#97#114#116#32#105#115#32#34+ - #109#111#118#101#95#115#116#97#114#116#34#32#116#121#112#101#32#112#111#105+ + #117#108#116#59#10#32#32#83#105#122#101#83#112#101#101#100#32#105#115#32#34+ + #115#105#122#101#95#115#112#101#101#100#34#32#116#121#112#101#32#112#111#105+ #110#116#32#100#101#102#97#117#108#116#32#40#48#32#48#41#32#111#109#105#116+ - #100#101#102#97#117#108#116#59#10#32#32#77#111#118#101#69#110#100#32#105#115+ - #32#34#109#111#118#101#95#101#110#100#34#32#116#121#112#101#32#112#111#105+ - #110#116#32#100#101#102#97#117#108#116#32#40#48#32#48#41#32#111#109#105#116+ - #100#101#102#97#117#108#116#59#10#32#32#77#111#118#101#65#99#116#105#118#101+ - #32#105#115#32#34#109#111#118#101#95#97#99#116#105#118#101#34#32#116#121#112+ - #101#32#98#111#111#108#32#100#101#102#97#117#108#116#32#102#97#108#115#101+ - #32#111#109#105#116#100#101#102#97#117#108#116#59#10#32#32#47#47#32#110#111+ - #116#32#105#110#32#98#105#110#97#114#121#10#32#32#47#47#73#100#32#105#115#32+ - #34#105#100#34#32#116#121#112#101#32#115#116#114#105#110#103#32#100#101#102+ - #97#117#108#116#32#34#34#32#111#109#105#116#100#101#102#97#117#108#116#59#10+ - #32#32#47#47#32#105#110#116#101#114#110#97#108#115#10#32#32#80#97#110#73#100+ - #120#32#105#115#32#34#112#97#110#105#100#120#34#32#116#121#112#101#32#117+ - #105#110#116#32#105#110#116#101#114#110#97#108#59#10#125#10#10#84#73#116#101+ - #109#82#101#99#95#49#32#105#115#32#34#105#116#101#109#34#32#115#105#122#101+ - #32#49#48#32#98#121#116#101#115#32#98#105#110#98#108#111#99#107#32#51#32#123+ - #10#32#32#47#47#88#32#105#115#32#34#120#34#32#116#121#112#101#32#105#110#116+ - #32#111#102#102#115#101#116#32#48#59#10#32#32#47#47#89#32#105#115#32#34#121+ - #34#32#116#121#112#101#32#105#110#116#32#111#102#102#115#101#116#32#52#59#10+ - #32#32#80#111#115#32#105#115#32#34#112#111#115#105#116#105#111#110#34#32#116+ + #100#101#102#97#117#108#116#59#32#47#47#32#97#108#97#115#44#32#96#115#105+ + #122#101#96#32#99#97#110#110#111#116#32#98#101#32#110#101#103#97#116#105#118+ + #101#10#32#32#77#111#118#101#83#116#97#114#116#32#105#115#32#34#109#111#118+ + #101#95#115#116#97#114#116#34#32#116#121#112#101#32#112#111#105#110#116#32+ + #100#101#102#97#117#108#116#32#40#48#32#48#41#32#111#109#105#116#100#101#102+ + #97#117#108#116#59#10#32#32#77#111#118#101#69#110#100#32#105#115#32#34#109+ + #111#118#101#95#101#110#100#34#32#116#121#112#101#32#112#111#105#110#116#32+ + #100#101#102#97#117#108#116#32#40#48#32#48#41#32#111#109#105#116#100#101#102+ + #97#117#108#116#59#10#32#32#83#105#122#101#69#110#100#32#105#115#32#34#115+ + #105#122#101#95#101#110#100#34#32#116#121#112#101#32#115#105#122#101#32#100+ + #101#102#97#117#108#116#32#40#48#32#48#41#32#111#109#105#116#100#101#102#97+ + #117#108#116#59#10#32#32#77#111#118#101#65#99#116#105#118#101#32#105#115#32+ + #34#109#111#118#101#95#97#99#116#105#118#101#34#32#116#121#112#101#32#98#111+ + #111#108#32#100#101#102#97#117#108#116#32#102#97#108#115#101#32#111#109#105+ + #116#100#101#102#97#117#108#116#59#10#32#32#77#111#118#101#79#110#99#101#32+ + #105#115#32#34#109#111#118#101#95#111#110#99#101#34#32#116#121#112#101#32#98+ + #111#111#108#32#100#101#102#97#117#108#116#32#102#97#108#115#101#32#111#109+ + #105#116#100#101#102#97#117#108#116#59#10#32#32#69#110#100#80#111#115#84#114+ + #105#103#103#101#114#32#105#115#32#34#101#110#100#95#112#111#115#95#116#114+ + #105#103#103#101#114#34#32#116#121#112#101#32#105#110#116#32#116#114#105#103+ + #103#101#114#32#100#101#102#97#117#108#116#32#110#117#108#108#32#111#109#105+ + #116#100#101#102#97#117#108#116#59#10#32#32#69#110#100#83#105#122#101#84#114+ + #105#103#103#101#114#32#105#115#32#34#101#110#100#95#115#105#122#101#95#116+ + #114#105#103#103#101#114#34#32#116#121#112#101#32#105#110#116#32#116#114#105+ + #103#103#101#114#32#100#101#102#97#117#108#116#32#110#117#108#108#32#111#109+ + #105#116#100#101#102#97#117#108#116#59#10#32#32#47#47#32#110#111#116#32#105+ + #110#32#98#105#110#97#114#121#10#32#32#47#47#73#100#32#105#115#32#34#105#100+ + #34#32#116#121#112#101#32#115#116#114#105#110#103#32#100#101#102#97#117#108+ + #116#32#34#34#32#111#109#105#116#100#101#102#97#117#108#116#59#10#32#32#47+ + #47#32#105#110#116#101#114#110#97#108#115#10#32#32#80#97#110#73#100#120#32+ + #105#115#32#34#112#97#110#105#100#120#34#32#116#121#112#101#32#117#105#110+ + #116#32#105#110#116#101#114#110#97#108#59#10#125#10#10#84#73#116#101#109#82+ + #101#99#95#49#32#105#115#32#34#105#116#101#109#34#32#115#105#122#101#32#49+ + #48#32#98#121#116#101#115#32#98#105#110#98#108#111#99#107#32#51#32#123#10#32+ + #32#47#47#88#32#105#115#32#34#120#34#32#116#121#112#101#32#105#110#116#32+ + #111#102#102#115#101#116#32#48#59#10#32#32#47#47#89#32#105#115#32#34#121#34+ + #32#116#121#112#101#32#105#110#116#32#111#102#102#115#101#116#32#52#59#10#32+ + #32#80#111#115#32#105#115#32#34#112#111#115#105#116#105#111#110#34#32#116+ #121#112#101#32#112#111#105#110#116#32#111#102#102#115#101#116#32#48#32#97+ #115#32#120#121#59#10#32#32#73#116#101#109#84#121#112#101#32#105#115#32#34+ #116#121#112#101#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102#102+ diff --git a/src/shared/xdynrec.pas b/src/shared/xdynrec.pas index d82867e..15040f8 100644 --- a/src/shared/xdynrec.pas +++ b/src/shared/xdynrec.pas @@ -1647,9 +1647,17 @@ begin else begin rec := mOwner.findRecordByTypeId(mEBSTypeName, pr.tokStr); - if (rec = nil) then raise Exception.Create(Format('record ''%s'' (%s) value for field ''%s'' not found', [pr.tokStr, mEBSTypeName, mName])); + if (rec = nil) then + begin + //raise Exception.Create(Format('record ''%s'' (%s) value for field ''%s'' not found', [pr.tokStr, mEBSTypeName, mName])); + mRecRefId := pr.tokStr; + end + else + begin + mRecRef := rec; + mRecRefId := ''; + end; pr.expectId(); - mRecRef := rec; end; mDefined := true; pr.expectTT(pr.TTSemi); @@ -2634,6 +2642,40 @@ var {$IF DEFINED(D2D_DYNREC_PROFILER)} stt, stall: UInt64; {$ENDIF} + + procedure linkNames (rec: TDynRecord); + var + fld: TDynField; + rt: TDynRecord; + begin + //writeln('*** rec: ', rec.mName, '.', rec.mId, ' (', rec.mFields.count, ')'); + for fld in rec.mFields do + begin + if (fld.mType = TDynField.TType.TTrigData) then + begin + if (fld.mRecRef <> nil) then linkNames(fld.mRecRef); + continue; + end; + if (Length(fld.mRecRefId) = 0) then continue; + assert(fld.mEBSType <> nil); + rt := findRecordByTypeId(fld.mEBSTypeName, fld.mRecRefId); + if (rt = nil) then + begin + e_LogWritefln('record of type ''%s'' with id ''%s'' links to inexistant record of type ''%s'' with id ''%s''', [rec.mName, rec.mId, fld.mEBSTypeName, fld.mRecRefId], MSG_WARNING); + //raise Exception.Create(Format('record of type ''%s'' with id ''%s'' links to inexistant record of type ''%s'' with id ''%s''', [rec.mName, rec.mId, fld.mEBSTypeName, fld.mRecRefId])); + end; + //writeln(' ', rec.mName, '.', rec.mId, ':', fld.mName, ' -> ', rt.mName, '.', rt.mId, ' (', fld.mEBSTypeName, '.', fld.mRecRefId, ')'); + fld.mRecRefId := ''; + fld.mRecRef := rt; + fld.mDefined := true; + end; + for fld in rec.mFields do + begin + //writeln(' ', fld.mName); + fld.fixDefaultValue(); // just in case + end; + end; + begin if (mOwner = nil) then raise Exception.Create(Format('can''t parse record ''%s'' value without owner', [mName])); @@ -2724,6 +2766,17 @@ begin raise Exception.Create(Format('unknown field ''%s'' in record ''%s''', [pr.tokStr, mName])); end; pr.expectTT(pr.TTEnd); + + if mHeader then + begin + // link fields + for fld in mFields do + begin + if (fld.mType <> TDynField.TType.TList) then continue; + for rec in fld.mRVal do linkNames(rec); + end; + end; + // fix field defaults {$IF DEFINED(D2D_DYNREC_PROFILER)}stt := curTimeMicro();{$ENDIF} for fld in mFields do fld.fixDefaultValue(); @@ -3115,7 +3168,7 @@ begin result := res; res := nil; finally - res.Free(); + //TMP:segfaults! res.Free(); end; end; -- 2.29.2