public void SetCurrentMapType(SmallMapReferences.SingleMapReference singleMapReference, LargeMap.Maps largeMap, TimeOfDay timeOfDay, PlayerCharacterRecords playerCharacterRecords, bool bLoadFromDisk) { _currentMapType = largeMap; // I may need make an additional save of state before wiping these MapCharacters out Characters.Clear(); switch (largeMap) { case LargeMap.Maps.Small: LoadSmallMap(singleMapReference, timeOfDay, playerCharacterRecords, bLoadFromDisk); return; case LargeMap.Maps.Overworld: // we don't reload them because the over and underworld are only loaded at boot time break; case LargeMap.Maps.Underworld: break; } bool bIsLargeMap = largeMap != LargeMap.Maps.Small; if (bIsLargeMap) { for (int i = 0; i < MAX_MAP_CHARACTERS; i++) { MapCharacterAnimationState charAnimState = CurrentAnimationState.GetCharacterState(i); Characters.Add(new MapCharacter(null, charAnimState, null, null, timeOfDay, playerCharacterRecords)); } } }
/// <summary> /// Resets the current map to a default state - typically no monsters and NPCs in there default positions /// </summary> private List <NonPlayerCharacterReference> LoadSmallMap(SmallMapReferences.SingleMapReference singleMapReference, TimeOfDay timeOfDay, PlayerCharacterRecords playerCharacterRecords, bool bLoadFromDisk) { List <NonPlayerCharacterReference> npcCurrentMapRefs = null; npcCurrentMapRefs = NPCRefs.GetNonPlayerCharactersByLocation(singleMapReference.MapLocation); if (bLoadFromDisk) { Debug.WriteLine("Loading character positions from disk..."); _smallMapAnimationStates.Load(MapCharacterAnimationStates.MapCharacterAnimationStatesFiles.SAVED_GAM, bLoadFromDisk); } else { Debug.WriteLine("Loading default character positions..."); } for (int i = 0; i < MAX_MAP_CHARACTERS; i++) { if (i == 0) { Characters.Add(new MapCharacter()); continue; } NonPlayerCharacterReference npcRef = npcCurrentMapRefs[i]; MapCharacterState mapCharState; MapCharacterAnimationState charAnimState = null; NonPlayerCharacterMovement charMovement = Movements.GetMovement(i); if (!bLoadFromDisk) { // we keep the object because we may be required to save this to disk - but since we are leaving the map there is no need to save their movements charMovement.ClearMovements(); mapCharState = new MapCharacterState(_tileRefs, npcRef, i, timeOfDay); } else { // character states are only loaded when forced from disk and only on small maps mapCharState = _charStates.GetCharacterState(i); if (CurrentAnimationState.HasAnyAnimationStates()) { charAnimState = CurrentAnimationState.GetCharacterState(mapCharState.CharacterAnimationStateIndex); } } Characters.Add(new MapCharacter(npcRef, charAnimState, mapCharState, charMovement, timeOfDay, playerCharacterRecords)); } return(npcCurrentMapRefs); }
// left over structure /* [StructLayout(LayoutKind.Sequential, Pack = 1)] * private unsafe struct NPC_Info * { * NPC_Schedule schedule[32]; * fixed byte type[32]; // merchant, guard, etc. * fixed byte dialog_number[32]; * };*/ #endregion #region Initialization and Constructor routines /// <summary> /// Initialize NPCs from a particular small map master file set /// </summary> /// <param name="u5Directory">Directory with Ultima 5</param> /// <param name="mapMaster">The master map from which to load</param> /// <param name="smallMapRef">Small map reference to help link NPCs to a map</param> /// <param name="talkScriptsRef"></param> /// <param name="gameStateRef"></param> private void InitializeNPCs(string u5Directory, SmallMapReferences.SingleMapReference.SmallMapMasterFiles mapMaster, SmallMapReferences smallMapRef, TalkScripts talkScriptsRef, GameState gameStateRef) { // open the appropriate NPC data file string dataFilenameAndPath = Path.Combine(u5Directory, SmallMapReferences.SingleMapReference.GetNPCFilenameFromMasterFile(mapMaster)); // load the file into memory List <byte> npcData = Utils.GetFileAsByteList(dataFilenameAndPath); for (int nTown = 0; nTown < TOWNS_PER_NPCFILE; nTown++) { // fresh collections for each major loop to guarantee they are clean List <NonPlayerCharacterReference.NPCSchedule> schedules = new List <NonPlayerCharacterReference.NPCSchedule>(NPCS_PER_TOWN); List <byte> npcTypes = new List <byte>(NPCS_PER_TOWN); List <byte> npcDialogNumber = new List <byte>(NPCS_PER_TOWN); SmallMapReferences.SingleMapReference.Location location = smallMapRef.GetLocationByIndex(mapMaster, nTown); SmallMapReferences.SingleMapReference singleMapRef = smallMapRef.GetSingleMapByLocation(location, 0); //sing = SmallMapRef.GetSingleMapByLocation(SmallMapRef.GetLocationByIndex(mapMaster, nTown); int townOffset = (TownOffsetSize * nTown); // bajh: I know this could be done in a single loop, but it would be so damn ugly that I honestly don't even want to both // read through the schedules first int count = 0; // start at the town offset, incremenet by an NPC record each time, for 32 loops for (int offset = townOffset; count < NPCS_PER_TOWN; offset += ScheduleOffsetSize, count++) { NonPlayerCharacterReference.NPCSchedule schedule = (NonPlayerCharacterReference.NPCSchedule)Utils.ReadStruct(npcData, offset, typeof(NonPlayerCharacterReference.NPCSchedule)); schedules.Add(schedule); } // bajh: just shoot me if I ever have to write this again - why on earth did LB write all of his data in different formats! // these are single byte, so we can capture them just by jumping to their offsets count = 0; for (int offset = townOffset; count < NPCS_PER_TOWN; offset++, count++) { // add NPC type npcTypes.Add(npcData[offset + StartingNPCTypeTownOffset]); // add NPC dialog # npcDialogNumber.Add(npcData[offset + StartingNPCDialogTownOffset]); } List <byte> keySpriteList = gameStateRef.NonPlayerCharacterKeySprites.GetAsByteList(); // go over all of the NPCs, create them and add them to the collection for (int nNpc = 0; nNpc < NPCS_PER_TOWN; nNpc++) { NonPlayerCharacterReference npc = new NonPlayerCharacterReference(location, gameStateRef, schedules[nNpc], npcTypes[nNpc], npcDialogNumber[nNpc], nNpc, talkScriptsRef.GetTalkScript(mapMaster, npcDialogNumber[nNpc]), (int)(keySpriteList[nNpc] + 100)); _npcs.Add(npc); // we also create a quick lookup table by location but first need to check that there is an initialized list inside if (!_locationToNPCsDictionary.ContainsKey(singleMapRef.MapLocation)) { _locationToNPCsDictionary.Add(singleMapRef.MapLocation, new List <NonPlayerCharacterReference>()); } if (npc.Name != string.Empty && !npc.Name.StartsWith("...")) { // merchants do not have names recorded :( _npcByNameDictionary.Add(npc.Name, npc); } _locationToNPCsDictionary[singleMapRef.MapLocation].Add(npc); } } }