/// <summary> /// Construction a conversation /// </summary> /// <param name="npc">NPC you will have a conversation with</param> /// <param name="state">The games current State</param> /// <param name="dataOvlRef">Data.OVL for reference</param> public Conversation(NonPlayerCharacterReference npc, GameState state, DataOvlReference dataOvlRef) { this.Npc = npc; script = npc.Script; this.gameStateRef = state; this.dataOvlRef = dataOvlRef; }
public TalkScript GetTalkScript(SmallMapReferences.SingleMapReference.SmallMapMasterFiles smallMapRef, int nNPC) { if (NonPlayerCharacterReference.IsSpecialDialogType((NonPlayerCharacterReference.NPCDialogTypeEnum)nNPC)) { return(null); } return(talkScriptRefs[smallMapRef][nNPC]); }
/// <summary> /// Begins the conversation with a particular NPC /// </summary> /// <param name="npc">the NPC to have a conversation with</param> /// <param name="enqueuedScriptItem">a handler to be called when script items are enqueued</param> /// <returns>A conversation object to be used to follow along with the conversation</returns> public Conversation CreateConversationAndBegin(NonPlayerCharacterReference npc, Conversation.EnqueuedScriptItem enqueuedScriptItem) { CurrentConversation = new Conversation(npc, State, DataOvlRef); CurrentConversation.EnqueuedScriptItemCallback += enqueuedScriptItem; PassTime(); return(CurrentConversation); }
public MapCharacterState(TileReferences tileReferences, NonPlayerCharacterReference npcRef, int nCharacterAnimationStateIndex, TimeOfDay timeOfDay) { NPCIndex = npcRef.DialogIndex; TileRef = tileReferences.GetTileReference(npcRef.NPCKeySprite); CharacterAnimationStateIndex = nCharacterAnimationStateIndex; // if you are adding by hand then we can assume that the character is active TheCharacterPosition = npcRef.Schedule.GetCharacterDefaultPositionByTime(timeOfDay); Active = true; }
public PlayerCharacterRecord GetCharacterRecordByNPC(NonPlayerCharacterReference npc) { foreach (PlayerCharacterRecord record in Records) { if (record.Name == npc.Name) { return(record); } } throw new Exception("Was unable to match CharacterRecord with NPC: " + npc.Name); }
/// <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); }
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); } }
public MapCharacter(NonPlayerCharacterReference npcRef, MapCharacterAnimationState mapCharacterAnimationState, MapCharacterState mapCharacterState, NonPlayerCharacterMovement nonPlayerCharacterMovement, TimeOfDay timeOfDay) { NPCRef = npcRef; AnimationState = mapCharacterAnimationState; CharacterState = mapCharacterState; Movement = nonPlayerCharacterMovement; CurrentCharacterPosition.Floor = CharacterState == null? 0: CharacterState.TheCharacterPosition.Floor; if (CharacterState == null) { if (npcRef != null) { MoveNPCToDefaultScheduledPosition(timeOfDay); } } else { CurrentCharacterPosition.XY = new Point2D(CharacterState.TheCharacterPosition.X, CharacterState.TheCharacterPosition.Y); } }
// 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); } } }
/// <summary> /// DEBUG FUNCTION /// </summary> /// <param name="npc"></param> public void SetNpcHasMetAvatar(NonPlayerCharacterReference npc, bool hasMet) { npcIsMetArray[npc.MapLocationID][npc.DialogIndex] = hasMet; }
/// <summary> /// Has the NPC met the avatar yet? /// </summary> /// <param name="npc"></param> /// <returns></returns> public bool NpcHasMetAvatar(NonPlayerCharacterReference npc) { return(npcIsMetArray[npc.MapLocationID][npc.DialogIndex]); }
/// <summary> /// Adds an NPC character to the party, and maps their CharacterRecord /// </summary> /// <param name="npc">the NPC to add</param> public void AddMemberToParty(NonPlayerCharacterReference npc) { PlayerCharacterRecord record = CharacterRecords.GetCharacterRecordByNPC(npc); record.PartyStatus = PlayerCharacterRecord.CharacterPartyStatus.InParty; }
/// <summary> /// Sets the flag to indicate the NPC is met /// </summary> /// <param name="npc"></param> public void SetMetNPC(NonPlayerCharacterReference npc) { npcIsMetArray[npc.MapLocationID][npc.DialogIndex] = true; }
/// <summary> /// Is NPC alive? /// </summary> /// <param name="npc">NPC object</param> /// <returns>true if NPC is alive</returns> public bool NpcIsAlive(NonPlayerCharacterReference npc) { // the array isDead becasue LB stores 0=alive, 1=dead // I think it's easier to evaluate if they are alive return(npcIsDeadArray[npc.MapLocationID][npc.DialogIndex] == false); }