void Update() { ProcessMemoryReader processReader = GetComponent <DosBox>().ProcessReader; if (processReader != null) { if (!pauseVarsTracking) { if (varsMemoryAddress != -1) { processReader.Read(memory, varsMemoryAddress, 207 * 2); CheckDifferences(memory, vars, varsMemoryAddress); } if (cvarsMemoryAddress != -1) { processReader.Read(memory, cvarsMemoryAddress, 44 * 2); CheckDifferences(memory, cvars, cvarsMemoryAddress); } ignoreDifferences = false; } } //hide table if (Input.GetMouseButtonDown(1)) { this.enabled = false; } UpdateCellSize(); }
public void RefreshMemory() { if (ProcessReader != null && ProcessReader.Read(memory, 0, memory.Length) == 0) { //unlink DOSBOX GetComponent <RoomLoader>().LinkToDosBox(); } }
public D2Unit GetPlayer() { if (player == null && (long)memory.Address.PlayerUnit > 0) { IntPtr playerAddress = reader.ReadAddress32(memory.Address.PlayerUnit, AddressingMode.Relative); player = reader.Read <D2Unit>(playerAddress); } return(player); }
public SkillReader(ProcessMemoryReader reader, GameMemoryTable memory) { this.reader = reader; globals = reader.Read <D2GlobalData>(reader.ReadAddress32(memory.Address.GlobalData, AddressingMode.Relative)); stringReader = new StringLookupTable(reader, memory.Address); }
public D2Inventory GetPlayerInventory() { var playerAddress = processReader.ReadAddress32(memory.Address.PlayerUnit, AddressingMode.Relative); if (playerAddress == IntPtr.Zero) { return(null); } var playerUnit = processReader.Read <D2Unit>(playerAddress); if (playerUnit == null) { return(null); } return(processReader.Read <D2Inventory>(playerUnit.pInventory.Address)); }
public ItemReader(ProcessMemoryReader reader, D2MemoryTable memory) : base(reader, memory) { cachedItemData = new Dictionary <IntPtr, D2ItemData>(); cachedDescriptions = new Dictionary <int, D2ItemDescription>(); globals = reader.Read <D2GlobalData>(reader.ReadAddress32(memory.Address.GlobalData, AddressingMode.Relative)); lowQualityTable = reader.Read <D2SafeArray>(memory.Address.LowQualityItems, AddressingMode.Relative); descriptionTable = reader.Read <D2SafeArray>(memory.Address.ItemDescriptions, AddressingMode.Relative); magicModifiers = reader.Read <ModifierTable>(memory.Address.MagicModifierTable, AddressingMode.Relative); rareModifiers = reader.Read <ModifierTable>(memory.Address.RareModifierTable, AddressingMode.Relative); if (globals != null) { opNestings = reader.ReadArray <ushort>(globals.OpStatNesting, (int)globals.OpStatNestingCount); if (ItemStatCost == null && !globals.ItemStatCost.IsNull) { ItemStatCost = reader.ReadArray <D2ItemStatCost>(globals.ItemStatCost, (int)globals.ItemStatCostCount); } } }
public bool LinkToDosBOX(int floor, int room, int detectedGame) { //search player position in DOSBOX processes int patternIndex = detectedGame - 1; int processId = Shared.ProcessId; if (processId == -1) { long memoryAddress; if (!SearchForBytePattern(patternIndex, out processId, out memoryAddress)) { return(false); } Shared.ProcessId = processId; Shared.ActorsMemoryAdress = memoryAddress; ProcessReader = new ProcessMemoryReader(processId); //vars if (patternIndex == 0) //AITD1 only { Shared.ObjectMemoryAddress = ProcessReader.SearchForBytePattern(objectMemoryPattern); if (Shared.ObjectMemoryAddress != -1) { Shared.ObjectMemoryAddress -= 4 + 52; //adjust actor offset (needed if player has been swapped) ProcessReader.Read(memory, Shared.ObjectMemoryAddress + 52, 2); int playerSlotID = memory.ReadShort(0); Shared.ActorsMemoryAdress += (1 - playerSlotID) * 160; } } } else { ProcessReader = new ProcessMemoryReader(processId); } //force reload linkfloor = floor; linkroom = room; dosBoxPattern = patternIndex; //check if CDROM/floppy version (AITD1 only) byte[] cdPattern = ASCIIEncoding.ASCII.GetBytes("CD Not Found"); IsCDROMVersion = detectedGame == 1 && ProcessReader.SearchForBytePattern(cdPattern) != -1; RightText.text = string.Empty; return(true); }
public IEnumerable <D2Unit> EnumerateInventoryBackward(D2Unit unit) { if (unit.pInventory.IsNull) { yield break; } var inventory = processReader.Read <D2Inventory>(unit.pInventory); if (inventory.pLastItem.IsNull) { yield break; } var item = GetUnit(inventory.pLastItem); for (; item != null; item = GetPreviousItem(item)) { yield return(item); } }
public IEnumerable <D2Skill> EnumerateSkills(D2Unit unit) { // first skill comes first var skill = reader.Read <D2Skill>(unit.pSkills.Address); if (skill == null) { yield break; } // seems like the first item that is found in that address is not an actual skill // yield return skill; // all other skills follow while (!skill.pNextSkill.IsNull) { skill = reader.Read <D2Skill>(skill.pNextSkill); if (skill == null) { yield break; } yield return(skill); } }
protected D2Unit GetPlayer() { if (player == null) { IntPtr playerAddress = reader.ReadAddress32(memory.Address.PlayerUnit, AddressingMode.Relative); player = reader.Read <D2Unit>(playerAddress); } return(player); }
// StatCostClassId => looks like statcost is in high bits and class is in low bits // example: // 00AC0000 // 00AC => statcost idx // 0000 => class id public static int GetArrayIndexByStatCostClassId(ProcessMemoryReader r, IntPtr addr, int StatCostClassId) { D2StatArray statArray = r.Read <D2StatArray>(addr); ushort statArrayLen = statArray.Length; if (statArrayLen < 1) { return(-1); } for (int i = statArrayLen - 1; i >= 0; i--) { // read the itemstatcost // int value = r.ReadInt32(statArray.Address.Address + i * 8); if (value == StatCostClassId) { return(i); } } return(-1); }
private string LookupStringTable(ushort identifier) { StringTable strTable = GetStringTableByIdentifier(identifier); identifier -= strTable.identifierOffset; IntPtr indexerTable = reader.ReadAddress32(strTable.indexTable, AddressingMode.Relative); if (indexerTable == IntPtr.Zero) { return(null); } IntPtr addressTable = reader.ReadAddress32(strTable.addressTable, AddressingMode.Relative); if (addressTable == IntPtr.Zero) { return(null); } /* * Info by [qhris]. * * Unicode strings are stored contiguous in a big buffer. To access this buffer * the address table is used. The address table maps an address index to a string * in the contiguous buffer. * * Note that all strings end with a null terminator and string length does not seem to * be stored anywhere. * * To get the address index, the string identifier (unsigned short) is looked up in the * item info table, along with a few checks to validate. */ var tableInfo = reader.Read <D2StringTableInfo>(indexerTable); // We use the identifier 0x1F4 for invalid identifiers. // because this is also what happens in D2Lang.dll if (identifier >= tableInfo.IdentifierCount) { identifier = 0x01F4; } // Right after the string info table (in memory) lies the identifier -> address index // mapping array. IntPtr stringDataRegion = indexerTable + Marshal.SizeOf <D2StringTableInfo>(); Func <ushort, IntPtr> GetAddressIndexLocation = (index) => stringDataRegion + index * sizeof(ushort); // Read address index; must be in valid range. ushort addressTableIndex = reader.ReadUInt16(GetAddressIndexLocation(identifier)); if (addressTableIndex >= tableInfo.AddressTableSize) { return(null); } // Get the address containing string information. IntPtr stringInfoBlock = GetAddressIndexLocation(tableInfo.IdentifierCount); IntPtr stringInfoAddress = stringInfoBlock + addressTableIndex * Marshal.SizeOf <D2StringInfo>(); // Make sure it's in range. IntPtr endTest = indexerTable + tableInfo.DataBlockSize; if ((long)stringInfoAddress >= (long)endTest) { return(null); } // Check if the string has been loaded into the address table. D2StringInfo stringInfo = reader.Read <D2StringInfo>(stringInfoAddress); if (!stringInfo.IsLoadedUnicode) { return(null); } // If we get a null string address, just ignore it. IntPtr stringAddress = reader.ReadAddress32(addressTable + addressTableIndex * sizeof(uint)); if (stringAddress == IntPtr.Zero) { return(null); } // A maximum of 0x4000 sized buffer **should** be enough to read all strings, bump if too low. return(reader.GetNullTerminatedString(stringAddress, 0x100, 0x4000, Encoding.Unicode, AddressingMode.Absolute)); }
public void UpdateItemStats(ProcessMemoryReader r, D2MemoryTable memory, D2Unit pl) { InventoryReader inventoryReader = new InventoryReader(r, memory); UnitReader unitReader = new UnitReader(r, memory); // Build filter to get only equipped items. Func <D2ItemData, bool> filter = data => data.BodyLoc != BodyLocation.None; foreach (D2Unit item in inventoryReader.EnumerateInventory(filter)) { List <D2Stat> itemStats = unitReader.GetStats(item); if (itemStats == null) { continue; } StringBuilder statBuilder = new StringBuilder(); statBuilder.Append(inventoryReader.ItemReader.GetFullItemName(item)); statBuilder.Append("\n"); List <string> magicalStrings = inventoryReader.ItemReader.GetMagicalStrings(item); foreach (string str in magicalStrings) { statBuilder.Append(" "); statBuilder.Append(str); statBuilder.Append("\n"); } Control c = null; D2ItemData itemData = r.Read <D2ItemData>(item.UnitData); switch (itemData.BodyLoc) { case BodyLocation.Head: c = tabPageHead; break; case BodyLocation.Amulet: c = tabPageAmulet; break; case BodyLocation.BodyArmor: c = tabPageBody; break; case BodyLocation.PrimaryRight: c = tabPageWeaponRight; break; case BodyLocation.PrimaryLeft: c = tabPageWeaponLeft; break; case BodyLocation.RingRight: c = tabPageRingRight; break; case BodyLocation.RingLeft: c = tabPageRingLeft; break; //case BodyLocation.SecondaryLeft: c = tabPageRingRight; break; //case BodyLocation.SecondaryRight: c = tabPageRingLeft; break; case BodyLocation.Belt: c = tabPageBelt; break; case BodyLocation.Boots: c = tabPageFeet; break; case BodyLocation.Gloves: c = tabPageHand; break; } if (c != null) { if (c.Controls.Count == 0) { c.Invoke(new Action(delegate() { c.Controls.Add(new RichTextBox()); c.Controls[0].Dock = DockStyle.Fill; })); } c.Controls[0].Invoke(new Action(() => c.Controls[0].Text = statBuilder.ToString())); } } }
public void UpdateAllActors() { Player = null; if (ProcessReader != null) { if (ProcessReader.Read(memory, Shared.ActorsMemoryAdress, memory.Length) > 0) { //read actors info int i = 0; foreach (Box box in Boxes) { int k = i * actorStructSize[dosBoxPattern]; box.ID = memory.ReadShort(k + 0); if (box.ID != -1) { int trackModeOffset = trackModeOffsets[dosBoxPattern]; box.Body = memory.ReadShort(k + 2); box.Flags = memory.ReadShort(k + 4); box.ColFlags = memory.ReadShort(k + 6); memory.ReadBoundingBox(k + 8, out box.BoundingLower, out box.BoundingUpper); FixBoundingWrap(ref box.BoundingLower.x, ref box.BoundingUpper.x); FixBoundingWrap(ref box.BoundingLower.z, ref box.BoundingUpper.z); memory.ReadBoundingBox(k + 20, out box.Box2DLower, out box.Box2DUpper); box.LocalPosition = memory.ReadVector(k + 28); box.WorldPosition = memory.ReadVector(k + 34); box.Angles = memory.ReadVector(k + 40); box.Floor = memory.ReadShort(k + 46); box.Room = memory.ReadShort(k + 48); box.LifeMode = memory.ReadShort(k + 50); box.Life = memory.ReadShort(k + 52); box.Chrono = memory.ReadUnsignedInt(k + 54); box.RoomChrono = memory.ReadUnsignedInt(k + 58); box.Anim = memory.ReadShort(k + 62); box.AnimType = memory.ReadShort(k + 64); box.NextAnim = memory.ReadShort(k + 66); box.Keyframe = memory.ReadShort(k + 74); box.TotalFrames = memory.ReadShort(k + 76); box.EndFrame = memory.ReadShort(k + 78); box.EndAnim = memory.ReadShort(k + 80); box.TrackMode = memory.ReadShort(k + trackModeOffset); box.TrackNumber = memory.ReadShort(k + 84); box.PositionInTrack = memory.ReadShort(k + 88); if (dosBoxPattern == 0) //AITD1 only { box.Mod = memory.ReadVector(k + 90); } else { box.Mod = Vector3.zero; } box.OldAngle = memory.ReadShort(k + 106); box.NewAngle = memory.ReadShort(k + 108); box.RotateTime = memory.ReadShort(k + 110); box.Speed = memory.ReadShort(k + 116); box.Col = memory.ReadVector(k + 126); box.ColBy = memory.ReadShort(k + 132); box.HardTrigger = memory.ReadShort(k + 134); box.HardCol = memory.ReadShort(k + 136); box.Hit = memory.ReadShort(k + 138); box.HitBy = memory.ReadShort(k + 140); box.ActionType = memory.ReadShort(k + 142); box.HotBoxSize = memory.ReadShort(k + 148); box.HitForce = memory.ReadShort(k + 150); box.HotPosition = memory.ReadVector(k + 154); } i++; } //find player + switch floor if necessary foreach (Box box in Boxes) { bool isActive = box.ID != -1; if (isActive) { //player if (box.TrackMode == 1 || box.ID == lastValidPlayerIndex) { //update player index lastValidPlayerIndex = box.ID; //automatically switch room and floor (has to be done before setting other actors positions) if (linkfloor != box.Floor || linkroom != box.Room) { linkfloor = box.Floor; linkroom = box.Room; GetComponent <RoomLoader>().RefreshRooms(linkfloor, linkroom); } } } } //update all boxes foreach (Box box in Boxes) { if (box.ID != -1) { Transform roomObject = GetComponent <RoomLoader>().GetRoom(box.Floor, box.Room); if (roomObject != null) { //local to global position Vector3 boxPosition = box.BoundingPos / 1000.0f; boxPosition = new Vector3(boxPosition.x, -boxPosition.y, boxPosition.z) + roomObject.localPosition; if (box.transform.position != boxPosition) { Vector3 offset = 1000.0f * (box.transform.position - boxPosition); float distance = new Vector3(Mathf.Round(offset.x), 0.0f, Mathf.Round(offset.z)).magnitude; box.LastOffset = Mathf.RoundToInt(distance); box.LastDistance += distance; box.transform.position = boxPosition; } //make actors appears slightly bigger than they are to be not covered by colliders Vector3 delta = Vector3.one; box.transform.localScale = (box.BoundingSize + delta) / 1000.0f; //make sure very small actors are visible box.transform.localScale = Vector3.Max(box.transform.localScale, Vector3.one * 0.1f); bool isAITD1 = dosBoxPattern == 0; if (isAITD1) { UpdateHotPointBox(box, roomObject.localPosition); } if (ShowAITD1Vars) { if (box.PreviousAnim != box.Anim || box.PreviousKeyFrame != box.Keyframe || box.EndFrame == 1 || box.EndAnim == 1) { box.PreviousAnim = box.Anim; box.PreviousKeyFrame = box.Keyframe; box.lastKeyFrameChange.Reset(); } if (saveTimerFlag) { box.lastKeyFrameChange.Stop(); } else { box.lastKeyFrameChange.Start(); } } //player bool isPlayer = box.ID == lastValidPlayerIndex; if (isPlayer) { //check if player has moved if (box.transform.position != lastPlayerPosition) { //center camera to player position GetComponent <RoomLoader>().CenterCamera(new Vector2(box.transform.position.x, box.transform.position.z)); lastPlayerPosition = box.transform.position; } //follow player Arrow.transform.position = box.transform.position + new Vector3(0.0f, box.transform.localScale.y / 2.0f + 0.001f, 0.0f); //face camera float angle = box.Angles.y * 360.0f / 1024.0f; Arrow.transform.rotation = Quaternion.AngleAxis(90.0f, -Vector3.left); Arrow.transform.rotation *= Quaternion.AngleAxis((angle + 180.0f) % 360.0f, Vector3.forward); float minBoxScale = Mathf.Min(box.transform.localScale.x, box.transform.localScale.z); Arrow.transform.localScale = new Vector3( minBoxScale * 0.9f, minBoxScale * 0.9f, 1.0f); //player is white box.Color = new Color32(255, 255, 255, 255); Arrow.AlwaysOnTop = Camera.main.orthographic; Player = box; } else { if (box.Slot == 0) { box.Color = new Color32(255, 255, 255, 255); } else { //other actors are green box.Color = new Color32(0, 128, 0, 255); } } if (isAITD1) { UpdateWorldPosBox(box, roomObject.localPosition, isPlayer); } box.AlwaysOnTop = Camera.main.orthographic; box.gameObject.SetActive(true); } else { box.gameObject.SetActive(false); } } else { box.gameObject.SetActive(false); } } if (ShowAITD1Vars) { //internal timer ProcessReader.Read(memory, Shared.ActorsMemoryAdress - 0x83B6 - 6, 4); InternalTimer1 = memory.ReadUnsignedInt(0); //internal timer 2 ProcessReader.Read(memory, Shared.ActorsMemoryAdress - 0x83B6 - 6 + 0xA5CE, 2); internalTimer2 = memory.ReadUnsignedShort(0); //inventory ProcessReader.Read(memory, Shared.ActorsMemoryAdress - 0x83B6 - 6 - 0x1A4, 2); allowInventory = memory.ReadShort(0) == 1; //inhand ProcessReader.Read(memory, Shared.ActorsMemoryAdress - 0x83B6 + 0xA33C, 2); inHand = memory.ReadShort(0); //set by AITD when long running code is started (eg: loading ressource) ProcessReader.Read(memory, Shared.ActorsMemoryAdress - 0x83B6 - 6 + 0x13EA, 4); saveTimerFlag = memory[0] == 1; } } else { //unlink DOSBOX GetComponent <RoomLoader>().ProcessKey(KeyCode.L); } } //arrow is only active if actors are active and player is active Arrow.gameObject.SetActive(Actors.activeSelf && Player != null && Player.gameObject.activeSelf && Player.transform.localScale.magnitude > 0.01f); }
public void Update() { GameObject player = null; if (ProcessReader != null) { if (ProcessReader.Read(memory, memoryAddress, memory.Length) > 0) { //read actors info int i = 0; foreach (Box box in Actors.GetComponentsInChildren <Box>(true)) { int k = i * ActorStructSize[dosBoxPattern]; int floorNumber = Utils.ReadShort(memory, k + 46); int roomNumber = Utils.ReadShort(memory, k + 48); int objectid = Utils.ReadShort(memory, k + 0); int body = Utils.ReadShort(memory, k + 2); int trackModeOffset = TrackModeOffsets[dosBoxPattern]; int trackMode = Utils.ReadShort(memory, k + trackModeOffset); bool isActive = objectid != -1; if (isActive) { //player if (trackMode == 1 || objectid == lastValidPlayerIndex) { //update player index lastValidPlayerIndex = objectid; //automatically switch room and floor (has to be done before setting other actors positions) if (linkfloor != floorNumber || linkroom != roomNumber) { linkfloor = floorNumber; linkroom = roomNumber; GetComponent <RoomLoader>().RefreshRooms(linkfloor, linkroom); } } Transform roomObject = GetComponent <RoomLoader>().GetRoom(floorNumber, roomNumber); if (roomObject != null) { //local position int boundingX1 = Utils.ReadShort(memory, k + 8); int boundingX2 = Utils.ReadShort(memory, k + 10); int boundingY1 = Utils.ReadShort(memory, k + 12); int boundingY2 = Utils.ReadShort(memory, k + 14); int boundingZ1 = Utils.ReadShort(memory, k + 16); int boundingZ2 = Utils.ReadShort(memory, k + 18); FixBoundingWrap(ref boundingX1, ref boundingX2); FixBoundingWrap(ref boundingY1, ref boundingY2); FixBoundingWrap(ref boundingZ1, ref boundingZ2); box.BoundingLower = new Vector3(boundingX1, boundingY1, boundingZ1); box.BoundingUpper = new Vector3(boundingX2, boundingY2, boundingZ2); //local to global position Vector3 boxPosition = box.BoundingPos / 1000.0f + roomObject.localPosition; box.transform.position = new Vector3(boxPosition.x, -boxPosition.y, boxPosition.z); //make actors appears slightly bigger than they are to be not covered by colliders Vector3 delta = Vector3.one; box.transform.localScale = (box.BoundingSize + delta) / 1000.0f; //make sure very small actors are visible box.transform.localScale = new Vector3( Mathf.Max(box.transform.localScale.x, 0.1f), Mathf.Max(box.transform.localScale.y, 0.1f), Mathf.Max(box.transform.localScale.z, 0.1f)); box.ID = objectid; box.Body = body; box.Room = roomNumber; box.Floor = floorNumber; box.Flags = Utils.ReadShort(memory, k + 4); box.ColFlags = Utils.ReadShort(memory, k + 6); box.LifeMode = Utils.ReadShort(memory, k + 50); box.Life = Utils.ReadShort(memory, k + 52); box.Chrono = Utils.ReadUnsignedInt(memory, k + 54); box.RoomChrono = Utils.ReadUnsignedInt(memory, k + 58); box.TotalFrames = Utils.ReadShort(memory, k + 76); box.TrackNumber = Utils.ReadShort(memory, k + 84); box.PositionInTrack = Utils.ReadShort(memory, k + 88); box.TrackMode = trackMode; box.Speed = Utils.ReadShort(memory, k + 116); box.Slot = i; box.Angles.x = Utils.ReadShort(memory, k + 40); box.Angles.y = Utils.ReadShort(memory, k + 42); box.Angles.z = Utils.ReadShort(memory, k + 44); box.Mod.x = Utils.ReadShort(memory, k + 90); box.Mod.y = Utils.ReadShort(memory, k + 92); box.Mod.z = Utils.ReadShort(memory, k + 94); box.LocalPosition.x = Utils.ReadShort(memory, k + 28) + box.Mod.x; box.LocalPosition.y = Utils.ReadShort(memory, k + 30) + box.Mod.y; box.LocalPosition.z = Utils.ReadShort(memory, k + 32) + box.Mod.z; box.WorldPosition.x = Utils.ReadShort(memory, k + 34) + box.Mod.x; box.WorldPosition.y = Utils.ReadShort(memory, k + 36) + box.Mod.y; box.WorldPosition.z = Utils.ReadShort(memory, k + 38) + box.Mod.z; box.ShowAdditionalInfo = ShowAdditionalInfo; UpdateBoxAnimAndKeyFrame(box, k); //player if (objectid == lastValidPlayerIndex) { float angle = box.Angles.y * 360.0f / 1024.0f; float sideAngle = (angle + 45.0f) % 90.0f - 45.0f; playerInfo = new StringBuilder(); playerInfo.AppendFormat("Position: {0} {1} {2}\n", box.LocalPosition.x, box.LocalPosition.y, box.LocalPosition.z); playerInfo.AppendFormat("Angle: {0:N1} {1:N1}", angle, sideAngle); //check if player has moved if (box.transform.position != lastPlayerPosition) { //center camera to player position GetComponent <RoomLoader>().CenterCamera(new Vector2(box.transform.position.x, box.transform.position.z)); lastPlayerPosition = box.transform.position; } //follow player Arrow.transform.position = box.transform.position + new Vector3(0.0f, box.transform.localScale.y / 2.0f + 0.001f, 0.0f); //face camera Arrow.transform.rotation = Quaternion.AngleAxis(90.0f, -Vector3.left); Arrow.transform.rotation *= Quaternion.AngleAxis((angle + 180.0f) % 360.0f, Vector3.forward); float minBoxScale = Mathf.Min(box.transform.localScale.x, box.transform.localScale.z); Arrow.transform.localScale = new Vector3( minBoxScale * 0.9f, minBoxScale * 0.9f, 1.0f); //player is white box.Color = new Color32(255, 255, 255, 255); box.AlwaysOnTop = Camera.main.orthographic; Arrow.AlwaysOnTop = Camera.main.orthographic; player = box.gameObject; } else { //other actors are green box.Color = new Color32(0, 128, 0, 255); } box.gameObject.SetActive(true); } else { box.gameObject.SetActive(false); } } else { box.gameObject.SetActive(false); } i++; } if (ShowAdditionalInfo) { Vector3 mousePosition = GetMousePosition(linkroom, linkfloor); fpsInfo = new StringBuilder(); fpsInfo.AppendFormat("Timer: {0}\n", TimeSpan.FromSeconds(InternalTimer / 60)); fpsInfo.AppendFormat("Fps: {0}\n", calculatedFps); fpsInfo.AppendFormat("Delay: {0} ms\n", lastDelayFpsCounter * 1000 / 200); fpsInfo.AppendFormat("Allow inventory: {0}\n", allowInventory ? "Yes" : "No"); fpsInfo.AppendFormat("Cursor position: {0} {1} {2}\n", (int)(mousePosition.x), (int)(mousePosition.y), (int)(mousePosition.z)); fpsInfo.AppendFormat("Last player offset: {0}\n", lastPlayerOffset); fpsInfo.AppendFormat("Last player mod: {0}\n", lastPlayerMod); fpsInfo.AppendFormat("In hand: {0}\n", inHand); } else { fpsInfo = null; } if (playerInfo != null) { RightText.text = playerInfo.ToString(); } if (fpsInfo != null) { RightText.text += "\n\n" + fpsInfo.ToString(); } } else { //unlink DOSBOX GetComponent <RoomLoader>().ProcessKey(KeyCode.L); } } if (ProcessReader != null) { if (ShowAdditionalInfo) { //inventory ProcessReader.Read(memory, memoryAddress - 0x83B6 - 6 - 0x1A4, 2); allowInventory = Utils.ReadShort(memory, 0) == 1; //inhand ProcessReader.Read(memory, memoryAddress - 0x83B6 + 0xA33C, 2); inHand = Utils.ReadShort(memory, 0); } } //arrow is only active if actors are active and player is active Arrow.gameObject.SetActive(Actors.activeSelf && player != null && player.activeSelf && player.transform.localScale.magnitude > 0.01f); }