/// <summary> /// Creates a small map object using a pre-defined map reference /// </summary> /// <param name="u5Directory"></param> /// <param name="mapRef"></param> public SmallMap(string u5Directory, SmallMapReferences.SingleMapReference mapRef, TileReferences spriteTileReferences) : base(u5Directory) { MapRef = mapRef; // load the map into memory TheMap = LoadSmallMapFile(Path.Combine(u5Directory, mapRef.MapFilename), mapRef.FileOffset); InitializeAStarMap(spriteTileReferences); }
/// <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, bool bLoadFromDisk) { List <NonPlayerCharacterReference> npcCurrentMapRefs = null; npcCurrentMapRefs = npcRefs.GetNonPlayerCharactersByLocation(singleMapReference.MapLocation); if (bLoadFromDisk) { smallMapAnimationStates.Load(MapCharacterAnimationStates.MapCharacterAnimationStatesFiles.SAVED_GAM, bLoadFromDisk); } else { } 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; 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)); } return(npcCurrentMapRefs); }
/// <summary> /// Loads a small map based on the provided reference /// </summary> /// <param name="singleMapReference"></param> public void LoadSmallMap(SmallMapReferences.SingleMapReference singleMapReference, bool bLoadFromDisk) { CurrentSingleMapReference = singleMapReference; CurrentSmallMap = smallMaps.GetSmallMap(singleMapReference.MapLocation, singleMapReference.Floor); overrideMap = Utils.Init2DArray <int>(CurrentSmallMap.TheMap[0].Length, CurrentSmallMap.TheMap.Length); IsLargeMap = false; LargeMapOverUnder = (LargeMap.Maps)(-1); TheMapCharacters.SetCurrentMapType(singleMapReference, LargeMap.Maps.Small, timeOfDay, bLoadFromDisk); //TheMapCharacters = new MapCharacters(tileReferences, npcRefs, singleMapReference, LargeMap.Maps.Small, // state.CharacterAnimationStatesDataChunk,state.OverworldOverlayDataChunks, state.UnderworldOverlayDataChunks, state.CharacterStatesDataChunk, // state.NonPlayerCharacterMovementLists, state.NonPlayerCharacterMovementOffsets); }
public void SetCurrentMapType(SmallMapReferences.SingleMapReference singleMapReference, LargeMap.Maps largeMap, TimeOfDay timeOfDay, bool bLoadFromDisk) { List <NonPlayerCharacterReference> npcCurrentMapRefs = null; 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, 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++) { // the animations are out of order - so we use this reference to track it down NonPlayerCharacterReference npcRef = bIsLargeMap ? null : npcCurrentMapRefs[i]; MapCharacterState mapCharState; MapCharacterAnimationState charAnimState = null; NonPlayerCharacterMovement charMovement; mapCharState = null; charMovement = null; charAnimState = CurrentAnimationState.GetCharacterState(i); Characters.Add(new MapCharacter(npcRef, charAnimState, mapCharState, charMovement, timeOfDay)); } //Debug.Assert(charAnimState.X == mapCharState.X); //Debug.Assert(charAnimState.Y == mapCharState.Y); //Debug.Assert(charAnimState.Floor == mapCharState.Floor); } }
// 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> 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.NPC_Schedule> schedules = new List <NonPlayerCharacterReference.NPC_Schedule>(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 = (TOWN_OFFSET_SIZE * 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 += SCHEDULE_OFFSET_SIZE, count++) { NonPlayerCharacterReference.NPC_Schedule sched = (NonPlayerCharacterReference.NPC_Schedule)Utils.ReadStruct(npcData, offset, typeof(NonPlayerCharacterReference.NPC_Schedule)); schedules.Add(sched); } // 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 + STARTING_NPC_TYPE_TOWN_OFFSET]); // add NPC dialog # npcDialogNumber.Add(npcData[offset + STARTING_NPC_DIALOG_TOWN_OFFSET]); } 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>()); } locationToNPCsDictionary[singleMapRef.MapLocation].Add(npc); } } }