-+-+-+-+-+-+-+-+ START OF PART 13 -+-+-+-+-+-+-+-+ X If GrabTable('Memory option? ', MemOptTable, S, Opt) Then Begin X Read_Record(FILE_MEMORY, Entity.MemoryId, IAddress(Memory)); X Case Opt Of X M_Bexp : Memory.BaseExp := GrabNumberI('Base experience? ', S); X M_Bgold : Memory.BaseGold := GrabNumberI('Base gold? ', S); X M_Saying : EditSaying; X M_Ap : EditActionPoints; X End; X Update_Record(FILE_MEMORY, Entity.MemoryId, IAddress(Memory)); X End; X End Else PutLine(Entity.Name+' do not have memory. '); X End Else PutLine('No such person here. '); XEnd; X X X(* Npc driver routines *) X XConst X MaxRoomNpc = 100; (* should be more than enough.. *) X MaxGlobNpc = 5; (* this should be adjusted very carefully *) X XType X RoomNpclistType = Record X Top : Integer; X Point : Integer; X Ids : Array`5B1..MaxRoomNpc`5D Of $UWord; X Items : Array`5B1..MaxRoomNpc`5D Of EntityType; X End; X X GlobNpcListType = Record X Next : Integer; X Point : Integer; X Ids : Array`5B1..MaxGlobNpc`5D Of $UWord; X Items : Array`5B1..MaxGlobNpc`5D Of EntityType; X End; X XVar X RoomNpc : RoomNpcListType; X MyEnemies : GlobNpcListType; X X`5BGlobal`5D XProcedure InitEnemyList; XBegin X MyEnemies.Next := 1; X MyEnemies.Point := 0; X MyEnemies.Items := Zero; X MyEnemies.Ids := Zero; XEnd; X X`5BGlobal`5D XProcedure UpdateEnemyList(Id : $UWord; X Var Npc : EntityType); XVar Found : Boolean := False; X I : Integer; XBegin X For I := 1 To MaxGlobNpc Do X If (MyEnemies.Ids`5BI`5D = Id) Then X Found := True; X If Not Found Then With MyEnemies Do Begin X Next := Next + 1; X If (Point > MaxGlobNpc) Then X Next := 1; X Items`5BNext`5D := Npc; X Ids`5BNext`5D := Id; X End; XEnd; X X`5BGlobal`5D XProcedure LoadRoomNpc(Location : $UWord); XVar Map : ItemMapType; X NodeIn, Entity, Npc : EntityType; X PersonBlk, NpcPersonBlk : BlockType; X I : Integer; X Done : Boolean := False; XBegin X RoomNpc := Zero; X RoomNpc.Point := 1; X ReadEntity(MyEntityId, Entity); X ReadBlock(Entity.PersonId, PersonBlk); X ReadEntity(Location, NodeIn); X Read_Record(FILE_ITEMMAP, NodeIn.RoomMapId, IAddress(Map)); X While Not Done Do Begin X For I := 1 To ItemMapSize Do X If (Map.Ids`5BI`5D > 0) And (Map.Ids`5BI`5D <> MyEntityId) And (Map.Po Vs`5BI`5D > 0) X Then Begin X ReadEntity(Map.Ids`5BI`5D, Npc); X If (Npc.EntityKind = ENTITY_PERSON) And (Npc.Driver = 0) Then Begin X RoomNpc.Top := RoomNpc.Top + 1; X RoomNpc.Items`5BRoomNpc.Top`5D := Npc; X RoomNpc.Ids`5BRoomNpc.Top`5D := Map.Ids`5BI`5D; X ReadBlock(Npc.PersonId, NpcPersonBlk); X If (PersonBlk.Person.Group <> NpcPersonBlk.Person.Group) Then X UpdateEnemyList(Map.Ids`5BI`5D, Npc); X End; X End; X If (Map.Next > 0) Then X Read_Record(FILE_ITEMMAP, Map.Next, IAddress(Map)) X Else Done := True; X End; XEnd; X X`5BGlobal`5D XProcedure LogNpcEvent(Var AnEvent : Event_Type; Where : $UWord); XVar I : Integer; X TempList : RoomNpcListType; XBegin X If (Where <> MyLocation) Then Begin X TempList := RoomNpc; X LoadRoomNpc(Where); X End; X For I := 1 To RoomNpc.Top Do X HandleEvent(AnEvent, RoomNpc.Ids`5BI`5D, Where); X If (Where <> MyLocation) Then X RoomNpc := TempList; XEnd; X X`5BGlobal`5D XProcedure UpdateRoomNpc(IsLeaving : Boolean; Id : $UWord); XVar I : Integer; XBegin X If IsLeaving And (RoomNpc.Top > 0) Then Begin X For I := 1 To RoomNpc.Top Do X If (RoomNpc.Ids`5BI`5D = Id) Then Begin X RoomNpc.Ids`5BI`5D := 0; X RoomNpc.Items`5BI`5D := Zero; X End; X End Else If Not IsLeaving Then Begin X RoomNpc.Top := RoomNpc.Top + 1; X RoomNpc.Ids`5BRoomNpc.Top`5D := Id; X ReadEntity(Id, RoomNpc.Items`5BRoomNpc.Top`5D); X End; XEnd; X X`5BHidden`5D XProcedure DriveEnemy(NpcId : $UWord; X Var Npc : EntityType); XVar Index : $UWord; X PersonBlk : BlockType; X Memory : MemoryType; X MyEntity, DriverEntity, NodeIn : EntityType; X LowHealth : Boolean; X Where, Pos : $UWord; X X Procedure SearchMemory; X Var I : Integer := 0; X Begin X Index := 0; X While (Index = 0) And (I < MaxActPoints) Do Begin X I := I + 1; X If Memory.ActPoints`5BI`5D.Where = Where Then X Index := I; X End; X End; X X Procedure ActRunAway; X Var Dir : Integer; X RoomBlk : BlockType; X Begin X ReadBlock(NodeIn.RoomId, RoomBlk); X If (MyLocation = Where) And (Rnd(100) < 50) Then Begin X ReadEntity(MyEntityId, MyEntity); X AttackPerson(Npc, MyEntity, NodeIn, PersonBlk, NpcId, MyEntityId,`20 X Where, FALSE); X End Else Begin X If (Index > 0) Then Begin X Case Memory.Actpoints`5BIndex`5D.RunAct Of X NPC_ACT_GO_S : Dir := South; X NPC_ACT_GO_N : Dir := North; X NPC_ACT_GO_W : Dir := West; X NPC_ACT_GO_E : Dir := East; X NPC_ACT_GO_D : Dir := Down; X NPC_ACT_GO_U : Dir := Up; X Otherwise Dir := (Memory.Actpoints`5BIndex`5D.OutDir + Rnd(4)) Mod V 6 + 1; X End; X End Else Dir := Rnd(5) + 1; X MovePerson(Npc, NodeIn, PersonBlk, RoomBlk, Where, NpcId, Dir, FALSE); X End; X End; X X Procedure ActAttack; X Begin X ReadEntity(MyEntityId, MyEntity); X AttackPerson(Npc, MyEntity, NodeIn, PersonBlk, NpcId, MyEntityId,`20 X Where, FALSE); X End; X X Procedure ActChase; X Var Dir : Integer; X RoomBlk : BlockType; X Begin X ReadBlock(NodeIn.RoomId, RoomBlk); X If (Index > 0) Then Begin X Case Memory.Actpoints`5BIndex`5D.Action Of X NPC_ACT_GO_S : Dir := South; X NPC_ACT_GO_N : Dir := North; X NPC_ACT_GO_W : Dir := West; X NPC_ACT_GO_E : Dir := East; X NPC_ACT_GO_D : Dir := Down; X NPC_ACT_GO_U : Dir := Up; X Otherwise Dir := (Memory.Actpoints`5BIndex`5D.OutDir + Rnd(4)) Mod 6 V + 1; X End; X End Else Dir := Rnd(5) + 1; X MovePerson(Npc, NodeIn, PersonBlk, RoomBlk, Where, NpcId, Dir, FALSE); X End; X XBegin X GetLocation(NpcId, Where, Pos); X Get_Record(FILE_BLOCK, Npc.PersonId, IAddress(PersonBlk)); X If (PersonBlk.Person.Health > 0) Then Begin X if CanAct(PersonBlk) Then Begin X PersonBlk.Person.ActionDelay := 0; X PersonBlk.Person.LastAct := GetRealTime; X Update_Record(FILE_BLOCK, Npc.PersonId, IAddress(PersonBlk)); X LowHealth := ((PersonBlk.Person.Health*2) < (PersonBlk.Person.Maxhealt Vh)); X If (Npc.MemoryId > 0) Then Begin X Read_Record(FILE_MEMORY, Npc.MemoryId, IAddress(Memory)); X SearchMemory; (* set index *) X End; X ReadEntity(Where, NodeIn); X If LowHealth Then X ActRunAway X Else If (Where <> MyLocation) Then X ActChase X Else ActAttack; X End Else Begin`20 X Free_Record(FILE_BLOCK); X TimeHeal(NpcId, Where); X End; X End Else Begin X Free_Record(FILE_BLOCK); X Resurrect(Npc, PersonBlk, NpcId, Where, FALSE); X End; XEnd; X X`5BGlobal`5D `20 XProcedure DriveEnemyList; XVar OldPoint : Integer; XBegin X OldPoint := MyEnemies.Point; X If (OldPoint = 0) Then X OldPoint := MaxGlobNpc; X With MyEnemies Do Repeat X Point := Point + 1; X If Point > MAxGlobNpc Then X Point := 1; X If Ids`5BPoint`5D > 0 Then X DriveEnemy(Ids`5BPoint`5D, Items`5BPoint`5D); X Until (Ids`5BPoint`5D > 0) Or (Point = OldPoint); XEnd; X XEnd. $ CALL UNPACK M9_2.PAS;1 1718748889 $ create 'f' X`5BInherit('Sys$Library:Starlet', 'Sys$Library:Pascal$Lib_Routines', X 'M1','M2','M3','M4','M5','M6','M7','M7_2', X 'M7_3', 'M9','M9_2','M10')`5D X XProgram Mon; X XConst X C_Play = 1; C_Quit = 2; C_Rebuild = 3; C_Root = 4; C_Force = 5; X MaxCmds = 5; X XType X ItemType = Record X Blen : $UWord; X Code : $UWord; X Baddr : Unsigned; X Raddr : Unsigned; X End; X XVar X CmdTable : `5BReadOnly`5D Array`5B1..MaxCmds`5D Of Short_String_Type := X ('Play', 'Quit', 'Rebuild', 'Root', 'Force'); X S : String_Type; Cmd : $UWord; Done : Boolean := False; X X`5BExternal, Hidden`5D XProcedure InitEnemyList; External; X XProcedure SetupDump; XVar ItemList : Packed Array`5B1..2`5D Of ItemType; X DumpFn : String_Type; XBegin X DumpFn := Root+'Dump.Mon'; X ItemList`5B1`5D.Blen := DumpFn.Length; X ItemList`5B1`5D.Code := Lnm$_String; X ItemList`5B1`5D.Baddr := IAddress(DumpFn); X ItemList`5B2`5D := Zero; X SysCall( $CreLnm(, 'LNM$PROCESS_TABLE', 'SYS$ERROR',,ItemList) ); XEnd; X XProcedure SetupMisc; XBegin X InitSmg; X InitTimer; X SetupError; X SetUpDump; XEnd; X XProcedure SetupFiles; XBegin X SetupAlloc; X SetupNpcSay; X SetupUser; X SetupLine; X SetupEntity; X SetupItemMap; X SetupBlock; X SetupExit; X SetupEvent; X SetupEffect; X SetUpMemory; XEnd; X XFunction WelcomeBack: Boolean; XVar User : user_Type;`20 X NodeIn, Entity : EntityType; X MyPersonBlk : BlockType; XBegin X If (Not IsPlaying(MyUserLog)) Then Begin X Welcomeback := True; X Get_Record(FILE_USER, MyUserLog, IAddress(User)); X MyEntityId := User.EntityLog; (* entity *) X SysCall( Lib$GetJpi(JPI$_PID,,,User.ProcessId) ); (* process *) X User.IsPlaying := True; X Update_Record(FILE_USER, MyUserLog, IAddress(User)); X Get_Record(FILE_ENTITY, MyEntityId, IAddress(Entity)); X Entity.Driver := MyUserLog; X Update_Record(FILE_ENTITY, MyEntityId, IAddress(Entity)); X GetLocation(MyEntityId, MyLocation, MyPosition); X ReadEntity(MyLocation, NodeIn); X ChangeMapPos(MyEntityId, MyLocation, NodeIn.RoomMapId, MyPosition); X ReadBlock(Entity.PersonId, MyPersonBlk); X ImDead := (MypersonBlk.Person.Health = 0); X PutLine('Welcome back! ', 1); X InitEnemyList; X SetMyEvent; X DescRoomIn(NodeIn, MyEntityId); X LogGlobEvent(0, 0, EV_INFORM, '('+Entity.Name+' once again roams the lan Vd)'); X End Else Begin X Welcomeback := False; X LogErr('You are already in the game. '); X End; XEnd; X XFunction MakeNewPlayer: Boolean; XVar User : User_Type; X NodeIn : EntityType; X S : String_Type := ''; XBegin X While (S.Length = 0) Do X GrabLine('What is your name? ', S); X S := Short(S); X If CreateUser(MyUserLog) Then Begin X If CreatePerson(S, MyEntityId, MyUserLog, MyUserLog, The_Great_Beginning V,`20 X POS_IN_ROOM) Then Begin X MakeNewPlayer := True; X Get_Record(FILE_USER, MyUserLog, IAddress(User)); X User.EntityLog := MyEntityId; X User.IsPlaying := True; X Update_Record(FILE_USER, MyUserLog, IAddress(User)); X MyLocation := The_Great_Beginning; X MyPosition := POS_IN_ROOM; X ImDead := False; X PutLine('Welcome! ', 1); X InitEnemyList; X SetMyEvent; X ReadEntity(MyLocation, NodeIn); X DescRoomIn(NodeIn, MyEntityId); X LogGlobEvent(0, 0, EV_INFORM, '('+S+' is born)'); X End Else Begin X MakeNewPlayer := False; X DeleteUser(MyUserLog); X LogErr('Create player failed, notify monster manager. ') X End; X End Else Begin X MakeNewPlayer := False; X PutLine('The universe is full, notify monster manager. '); X End; XEnd; X XProcedure ExitPlaying; XVar NodeIn, Entity : EntityType; User : User_Type; XBegin X ReadEntity(MyLocation, NodeIn); X ChangeMapPos(MyEntityId, MyLocation, NodeIn.RoomMapId, 0); (* tricky! *) X UpdateLocation(MyEntityId, MyLocation, MyPosition); (* *) X Get_Record(FILE_ENTITY, MyEntityId, IAddress(Entity)); X Entity.Driver := 0; X Update_Record(FILE_ENTITY, MyEntityId, IAddress(Entity)); (* entity *) X Get_Record(FILE_USER, MyUserLog, IAddress(User)); X User.ProcessId := 0; X User.IsPlaying := False; X Update_Record(FILE_USER, MyUserLog, IAddress(User)); (* user *) X PutLine('You vanished in a brilliant burst of multicolor light. '); X LogGlobEvent(0, 0, EV_INFORM, '('+Entity.Name+' returns to sleep)'); XEnd; X XProcedure Do_Play; XBegin X SetupFiles; X If FAST_MODE Then Begin X PutLine('Running in fast mode..'); X PutLine('Load entity..'); X LoadEntitys; X PutLine('Load block..'); X LoadBlocks; X PutLine('Load exit..'); X LoadExits; X End; X If LookupUsername(MyUserId, MyUserLog) Then Begin X If WelcomeBack Then Begin X ParseCmd; X ExitPlaying; X End; X End Else If MakeNewPlayer Then Begin X ParseCmd; X ExitPlaying; X End; X SetupFiles; XEnd; X XProcedure Do_Rebuild; XVar S : String_Type; X EntityLog : $UWord; XBegin X Setupfiles; X PutLine('Initialize say file.. '); X InitSayFile(10); X PutLine('Initialize user file.. '); X InitUserFile(10); X PutLine('Initialize line file.. '); X InitLineFile(10); X PutLine('Initialize entity file.. '); X InitEntityFile(10); X PutLine('Initialize map file.. '); X InitItemMapFile(10); X PutLine('Initialize block file.. '); X InitBlockFile(10); X PutLine('Initialize exit file.. '); X InitExitFile(10); X PutLine('Initialize event file.. '); X InitEventFile; X PutLine('Initialize effect file.. '); X InitEffectFile(10); X PutLine('Initialize memory file.. '); X InitMemoryFile(10); X PutLine('Create the great beginning..'); X CreateRoom('The great beginning', EntityLog); X PutLine('Create human..'); X CreateClass('Human', EntityLog); X Setupfiles; XEnd; X XProcedure Do_Root(Var S : String_Type); XBegin X While (S.Length = 0) Do`20 X GrabLine('New path? ', S); X Root := S; X S := ''; X PutLine('Done. '); XEnd; X XProcedure Do_Force(Var S : String_Type); XBegin X While (S.Length = 0) Do`20 X GrabLine('New username? ', S); X MyUserId := S; X S := ''; X PutLine('You are now '+MyUserId+'.'); XEnd; X XBegin X SetupMisc; X MyUserId := GetUserId; X PutLine('Welcome to UB monster version 1.0! ', 1); X While Not Done Do Begin X If GrabTable('Start> ', CmdTable, S, Cmd) Then X Case Cmd Of`20 X C_Quit : Done := True; X C_PLay : Do_Play; X C_Rebuild : If IsWindy Then Do_Rebuild; X C_Root : If IsWindy Then Do_Root(S); X C_Force : If IsWindy Then Do_Force(S); X End X Else PutLine('Type ? for a list of command. '); X End; +-+-+-+-+-+-+-+- END OF PART 13 +-+-+-+-+-+-+-+-