-
Notifications
You must be signed in to change notification settings - Fork 1
/
Engine3D_NPC.p
729 lines (581 loc) · 16.1 KB
/
Engine3D_NPC.p
1
unit Engine3D_NPC;interfaceuses types, quickdraw, Dream3Display_Tipi, Dream3Display_Tools, Engine3D_Globals, Engine3D_PlaySequence; var firstTimeCheck : boolean; function InMap ( ThePoint : DoublePoint; var TheResult : integer; IsNPC : boolean) : boolean;procedure DisposeAllNPCS;procedure Engine3D_AddObject ( TheObjectId : integer; ThePos : point);procedure Engine3D_AssignSequenceToNPC ( ThePlaySequence : PlaySequenceHandle; TheNPCPtr : NPCPtr); procedure Engine3D_DisposeNPC ( TheNPC : NPCPtr; UpdateDList : boolean);procedure Engine3D_DisposeNPCById ( Id : integer);procedure Engine3D_LoadAllNPC ( NpcListId : integer);procedure Engine3D_NewNPC ( Id : integer);procedure Engine3D_NPCInit;procedure Engine3D_PlayOneStep ( ThePlaySequence : PlaySequenceHandle);procedure Engine3D_SetNPCViewPoint (TheNPC : NPCPtr; ViewPoint : integer); function Engine3D_ClickObject ( Where : point) : integer;function Engine3D_GetDistanceFromNPC ( TheNPC : NPCPtr) : longint;function Engine3D_GetDistanceFromTwoNPCs ( TheNPC1Id, TheNPC2Id : integer) : longint;function Engine3D_MeetSomeOne : integer;function Engine3D_MoveNPC ( TheNPC : NPCPtr; TheDirection : integer; var ThePosition : point) : integer;function Engine3D_SetNPCPoint ( TheNPC : NPCPtr; var ThePoint : DoublePoint; Engine : boolean) : integer;procedure MoveAllNPC;implementation{$R-}uses fixmath, toolutils, windows, qdoffscreen, resources, icons, palettes, AppleEvents, AERegistry, segload, memory, binio, cilindro, dreamTypes, lowlevel, game, { objects4dream2,} Engine3D_DrawProc, Engine3D_CIconArray, Engine3D_Rotate, Engine3D_Roofs, Engine3D_Boxes, Engine3D_DrawXLine;const NPCListResType = 'NPCL'; DeadNPCListId = 1; type NPCRList = record R1 : integer; ListN : integer; NpcId : array [0..255] of integer; end; NPCRListPtr = ^NPCRList; NPCRListHandle = ^NPCRListPtr; var OldPoint : point; OldXplore : boolean; {$S Engine3D_Utils}procedure Engine3D_NPCInit;begin setpt (OldPoint, -1, -1);end; {$S Engine3D_PlaySequenceTools}procedure Engine3D_AssignSequenceToNPC ( ThePlaySequence : PlaySequenceHandle; TheNPCPtr : NPCPtr); var ThePlay : PlaySequencePtr; begin hlock (handle (ThePlaySequence)); ThePlay := ThePlaySequence^; with ThePlay^ do begin TheNPC := TheNPCPtr; end; hunlock (handle (ThePlaySequence));end;{$S Engine3D}procedure Engine3D_PlayOneStep ( ThePlaySequence : PlaySequenceHandle);var ThePlay : PlaySequencePtr; TheStep : longint; IgnoreMe : integer; APoint : point; begin hlock (handle (ThePlaySequence)); ThePlay := ThePlaySequence^; with ThePlay^ do begin if thePlay^.StepN > -1 then if TheTick >= LastTick + StepTicks then begin LastTick := TheTick; CurrentStep := CurrentStep + 1; if CurrentStep = StepN + 1 then CurrentStep := 0; TheStep := Step [CurrentStep]; if band (TheStep, KeyBackward) <> 0 then IgnoreMe := Engine3D_MoveNPC (TheNPC, 2, APoint); if band (TheStep, KeyLeftward) <> 0 then IgnoreMe := Engine3D_MoveNPC (TheNPC, 4, APoint); if band (TheStep, KeyRightward) <> 0 then IgnoreMe := Engine3D_MoveNPC (TheNPC, 6, APoint); if band (TheStep, KeyTurnLeft) <> 0 then IgnoreMe := Engine3D_MoveNPC (TheNPC, 7, APoint); if band (TheStep, KeyForward) <> 0 then IgnoreMe := Engine3D_MoveNPC (TheNPC, 8, APoint); if band (TheStep, KeyTurnRight) <> 0 then IgnoreMe := Engine3D_MoveNPC (TheNPC, 9, APoint); end; end; hunlock (handle (ThePlaySequence));end;{$S Engine3D_Utils}procedure Engine3D_LoadAllNPC ( NpcListId : integer);var I: integer; TheListH : NPCRListHandle; TheList : NPCRListPtr; TheDListH : NPCRListHandle; TheDList : NPCRListPtr; tmp : integer; function IsNPCDead (var Id : integer) : boolean;var J : integer;begin for J := 0 to TheDList^.ListN do if TheDList^.NpcId [J] = Id then begin IsNPCDead := true; exit (IsNPCDead); end; IsNPCDead := false;end;begin NPCN := 0; TheListH := NPCRListHandle (mygetresource (NPCListResType, NpcListId, false, true)); if TheListH <> nil then begin hlock (handle (TheListH)); TheList := TheListH^; TheDListH := NPCRListHandle (mygetresource (NPCListResType, DeadNPCListId, false, false)); if TheDListH <> nil then begin hlock (handle (TheDListH)); TheDList := TheDListH^; for I := 0 to TheList^.ListN do begin tmp := TheList^.NpcId [I]; if not IsNPCDead (tmp) then Engine3D_NewNPC (TheList^.NpcId [I]); end; releaseresource (handle (TheDListH)); end else for I := 0 to TheList^.ListN do Engine3D_NewNPC (TheList^.NpcId [I]); releaseresource (handle (TheListH)); end; firstTimeCheck := true;end;{$S Engine3D}function InMap ( ThePoint : DoublePoint; var TheResult : integer; IsNPC : boolean) : boolean;var ElNum : integer; TheDim : integer; The2Dim : integer; SinglePoint : point; TheDir : char; TheVeryPoint : DoublePoint; bstialResult : TExplorationResult; function NoBoxes : boolean;var I : longint; LocalBoxList : TBoxListPtr; begin LocalBoxList := BoxList; for I := BoxN downto 1 do with LocalBoxList^ [I]^ do begin if (not (Passable)) and (TheVeryPoint.h > MapRect.left) and (TheVeryPoint.h < MapRect.right) and (TheVeryPoint.v < MapRect.top) and (TheVeryPoint.v > MapRect.bottom) then begin NoBoxes := false; exit (NoBoxes); end; end; NoBoxes := true;end;function Dentro : boolean;var Tmp : boolean; begin Tmp := true; if (ThePoint.h < 1) or (ThePoint.h > Environment.MapHor) or (ThePoint.v < 1) or (ThePoint.v > Environment.MapVer) then Tmp := false; Dentro := Tmp;end;begin TheVeryPoint := ThePoint; TheDim := Environment.PlaceDim; The2Dim := bsl (TheDim, 1); ThePoint.h := (ThePoint.h + TheDim) div The2Dim + 1; ThePoint.v := (ThePoint.v - TheDim) div The2Dim + 1; with Environment do if Dentro then begin hlock (handle (SquareMap)); ElNum := SquareMap^^ [ThePoint.h, MapVer - ThePoint.v + 1]; hunlock (handle (SquareMap)); with SinglePoint do begin h := ThePoint.h; v := ThePoint.v; end; if ElNum <> 0 then begin if (not (GetSqElementInList (ElNum).Passable)) then begin InMap := false; TheResult := -11; exit (InMap); end; end; TheResult := 0; InMap := true; if firstTimeCheck then begin oldPoint := singlePoint; firstTimeCheck := false; oldXplore := true; end; if not IsNpc then if NoBoxes then begin if ((SinglePoint.h <> OldPoint.h) or (SinglePoint.v <> OldPoint.v)) then begin TheDir := '8'; bstialResult := mayiexplorethere (ThePoint.h, MapVer - ThePoint.v + 1, TheDir); case bstialResult of yesYouMayExplore : oldXplore := true; noYouCant : oldXplore := false; yesButStopInThere : begin oldXplore := true; theResult := -12; end; otherwise; end; OldPoint := SinglePoint; InMap := oldXplore; end else InMap := OldXplore; end else InMap := false; exit (InMap); end else begin InMap := false; if ThePoint.h > MapHor then TheResult := 6; if ThePoint.h < 1 then TheResult := 4; if ThePoint.v > MapVer then TheResult := 8; if ThePoint.v < 1 then TheResult := 2; end;end;{$S Engine3D_Utils}procedure Engine3D_DisposeNPC ( TheNPC : NPCPtr; UpdateDList : boolean);var I, J : integer; procedure UpdateDeadList ( Id : integer);var TheNListH, TheDListH : NPCRListHandle;begin TheDListH := NPCRListHandle (mygetresource (NPCListResType, DeadNPCListId, false, false)); if TheDListH <> nil then begin hlock (handle (TheDListH)); TheNListH := NPCRListHandle (newhandle (gethandlesize (handle (TheDListH)) + 2)); if theNListH = nil then deathalert (erroutofmemory, memerror); hlock (handle (TheNlistH)); blockmovedata (TheDListH^, TheNListH^, gethandlesize (handle (TheDListH))); releaseresource (handle (TheDListH)); end else begin TheNListH := NPCRListHandle (newhandle (8)); if theNListH = nil then deathalert (erroutofmemory, memerror); hlock (handle (TheNListH)); theNListH^^.ListN := -1; end; with TheNListH^^ do begin ListN := ListN + 1; NpcId [ListN] := Id; end; writeres (currentsavegamefile, DeadNPCListId, NPCListResType, '', handle (TheNListH)); releaseresource (handle (TheNListH));end;begin for i := 1 to NPCN do if NPCList^ [i] = theNPC then NPCList^ [i] := NPCList^ [NPCN]; NPCN := NPCN - 1; with TheNPC^ do begin releaseresource (NPCList^ [NPCN]^.PathPtr); for I := 1 to ObjectSides do for J := 0 to MoveFrames do begin DisposePICTOnPtr (MovePICT [I, J]); DisposePICTOnPtr (MoveMask [I, J]); end; for J := 0 to ActionFrames do begin DisposePICTOnPtr (ActionPICT [J]); DisposePICTOnPtr (ActionMask [J]); end; end; if UpdateDList then UpdateDeadList (TheNPC^.Id); Engine3D_DisposeSequence (playSequenceHandle (theNPC^.pathPtr)); disposeptr (ptr (TheNPC));end;{$S Engine3D_Utils}procedure Engine3D_DisposeNPCById ( Id : integer);label 100; var I, J : integer; begin for I := 1 to NPCN do if NPCList^ [I]^.Id = Id then begin Engine3D_DisposeNPC (NPCList^ [I], true); goto 100; end; exit (Engine3D_DisposeNPCById);100: for J := I to NPCN - 1 do NPCList^ [J] := NPCList^ [J + 1]; NPCN := NPCN - 1;end;{$S Engine3D_Utils}procedure Engine3D_NewNPC ( Id : integer);begin NPCN := NPCN + 1; NPCList^ [NPCN] := GetNPC (Id); if NPCList^ [NPCN]^.RelatedPath <> 0 then begin NPCList^ [NPCN]^.PathPtr := handle (GetPlaySequence (NPCList^ [NPCN]^.RelatedPath)); Engine3D_AssignSequenceToNPC (PlaySequenceHandle (NPCList^ [NPCN]^.PathPtr), NPCList^ [NPCN]); end;end;{$S Engine3D_Utils}procedure DisposeAllNPCS;var I : integer; begin for I := 1 to NPCN do Engine3D_DisposeNPC (NPCList^ [I], false); NPCN := 0;end;{$S Engine3D}function Engine3D_SetNPCPoint ( TheNPC : NPCPtr; var ThePoint : DoublePoint; Engine : boolean) : integer;var Dh, Dv : integer; TheResult : integer; ThisPosition : DoublePoint; begin if not Engine then with ThePoint do begin h := h * 20; v := v * 20; end; ThisPosition := TheNPC^.Position; with TheNPC^ do begin if not Engine then begin Position := ThePoint; exit (Engine3D_SetNPCPoint); end; if ThePoint.h > ThisPosition.h then Dh := 1 else if ThePoint.h < ThisPosition.h then Dh := -1 else Dh := 0; if ThePoint.v > ThisPosition.v then Dv := 1 else if ThePoint.v < ThisPosition.v then Dv := -1 else Dv := 0; TheResult := 0; if Dh <> 0 then begin repeat ThisPosition.h := ThisPosition.h + Dh; until (ThisPosition.h = ThePoint.h) or (not (InMap (ThisPosition, TheResult, true))); if not (InMap (ThisPosition, TheResult, true)) then ThisPosition.h := ThisPosition.h - Dh; end; if Dv <> 0 then begin repeat ThisPosition.v := ThisPosition.v + Dv; until (ThisPosition.v = ThePoint.v) or (not (InMap (ThisPosition, TheResult, true))); if not (InMap (ThisPosition, TheResult, true)) then ThisPosition.v := ThisPosition.v - Dv; end; end; TheNPC^.Position := ThisPosition; Engine3D_SetNPCPoint := TheResult;end;{$S Engine3D}function Engine3D_MoveNPC ( TheNPC : NPCPtr; TheDirection : integer; var ThePosition : point) : integer;var I, J : integer; TheResult : integer; ThisPosition : DoublePoint; ThisDirection : integer; TheSpeed : integer; begin TheResult := 0; ThisPosition := TheNPC^.Position; ThisDirection := TheNPC^.Direction; TheSpeed := TheNPC^.Speed; with TheNPC^ do begin for I := 1 to TheSpeed do begin case TheDirection of 2 : begin ThisPosition.v := ThisPosition.v - round (TheSpeed * DiscreteCos [ThisDirection] / Coefficient40); ThisPosition.h := ThisPosition.h + round (TheSpeed * DiscreteSin [ThisDirection] / Coefficient40); end; 4 : begin ThisPosition.v := ThisPosition.v - round (TheSpeed * DiscreteSin [ThisDirection] / Coefficient40); ThisPosition.h := ThisPosition.h - round (TheSpeed * DiscreteCos [ThisDirection] / Coefficient40); end; 6 : begin ThisPosition.v := ThisPosition.v + round (TheSpeed * DiscreteSin [ThisDirection] / Coefficient40); ThisPosition.h := ThisPosition.h + round (TheSpeed * DiscreteCos [ThisDirection] / Coefficient40); end; 7 : begin for J := 1 to ElAngles4Step do begin ThisDirection := ThisDirection + 1; if ThisDirection = NAngles then ThisDirection := 0; end; end; 8 : begin ThisPosition.v := ThisPosition.v + round (TheSpeed * DiscreteCos [ThisDirection] / Coefficient40); ThisPosition.h := ThisPosition.h - round (TheSpeed * DiscreteSin [ThisDirection] / Coefficient40); end; 9 : begin for J := 1 to ElAngles4Step do begin ThisDirection := ThisDirection - 1; if ThisDirection = -1 then ThisDirection := NAngles - 1; end; end; otherwise; end; end; TheNPC^.Direction := ThisDirection; if TheDirection in [2, 4, 6, 8] then begin MoveFrame := MoveFrame + 1; if MoveFrame >= MoveFrames then MoveFrame := 0; TheResult := Engine3D_SetNPCPoint (TheNPC, ThisPosition, true); end; Engine3D_MoveNPC := TheResult; if Engine3D_GetDistanceFromNPC (TheNPC) < TheNPC^.CDistance then Engine3D_MoveNPC := 1; end; ThePosition := MapPoint (TheNPC^.Position.h, TheNPC^.Position.v);end;{$S Engine3D_Utils}procedure Engine3D_AddObject ( TheObjectId : integer; ThePos : point);var TheObject : DisplayObjectHandle; begin TheObject := GetObject (TheObjectId); hlock (handle (TheObject)); ObjectN := ObjectN + 1; TheObject^^.Id := ObjectN; ObjectList^ [ObjectN] := TheObject^^; releaseresource (handle (TheObject)); AddObjectInBase (ObjectList^ [ObjectN], ThePos); if ObjectList^ [ObjectN].LightSource then AddLightSource (ThePos);end;{$S Engine3D_Utils}function Engine3D_ClickObject ( Where : point) : integer;const MaxDist = 600; var I : integer; ThePoly : Poly3D; begin where.h := where.h - Environment.CommonRect.left - WindowXCenter; where.v := where.v - Environment.CommonRect.top - WindowYCenter; for I := PolyNTr downto 1 do begin ThePoly := PolysTr^ [I]; if ThePoly.MiddleZ > MaxDist then begin Engine3D_ClickObject := 0; exit (Engine3D_ClickObject); end; if (Where.h in [ThePoly.ProjCorner0.X..ThePoly.ProjCorner1.X]) and (Where.v in [ThePoly.YStart0..ThePoly.YEnd0]) then begin Engine3D_ClickObject := Base^ [ThePoly.BaseRef].Cicon; exit (Engine3D_ClickObject); end; end;end;{$S Engine3D}procedure Engine3D_SetNPCViewPoint (TheNPC : NPCPtr; ViewPoint : integer); begin TheNPC^.Direction := ViewPoint;end;{$S Engine3D}function Engine3D_GetDistanceFromNPC ( TheNPC : NPCPtr) : longint;var MyPos, HisPos : DoublePoint; begin MyPos := Environment.ViewPoint; HisPos := TheNPC^.Position; Engine3D_GetDistanceFromNPC := trunc (sqrt (sqr (MyPos.h - HisPos.h) + sqr (MyPos.v - HisPos.v)));end;{$S Engine3D}function Engine3D_GetDistanceFromTwoNPCs ( TheNPC1Id, TheNPC2Id : integer) : longint;var MyPos, HisPos : DoublePoint; begin MyPos := NPCList^ [TheNPC1Id]^.Position; HisPos := NPCList^ [TheNPC2Id]^.Position; Engine3D_GetDistanceFromTwoNPCs := trunc (sqrt (sqr (MyPos.h - HisPos.h) + sqr (MyPos.v - HisPos.v)));end;{$S Engine3D}procedure MoveAllNPC;var I : integer;begin for I := 1 to NPCN do if NPCList^ [I]^.RelatedPath <> 0 then Engine3D_PlayOneStep (PlaySequenceHandle (NPCList^ [I]^.PathPtr));end;{$S Engine3D}function Engine3D_MeetSomeOne : integer;var I : integer; LocalNPCList : NPCListPtr; begin LocalNPCList := NPCList; for I := 1 to NPCN do if (not (LocalNPCList^ [I]^.TalkOccurred)) and (Engine3D_GetDistanceFromNPC (LocalNPCList^ [I]) <= LocalNPCLIst^ [I]^.CDistance) then begin LocalNPCList^ [I]^.TalkOccurred := true; Engine3D_MeetSomeOne := LocalNPCList^ [I]^.RelatedTalk; exit (Engine3D_MeetSomeOne); end; Engine3D_MeetSomeOne := 0;end;end.