Ejemplo n.º 1
0
    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();
    }
Ejemplo n.º 2
0
 public void RefreshMemory()
 {
     if (ProcessReader != null && ProcessReader.Read(memory, 0, memory.Length) == 0)
     {
         //unlink DOSBOX
         GetComponent <RoomLoader>().LinkToDosBox();
     }
 }
Ejemplo n.º 3
0
        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);
        }
Ejemplo n.º 4
0
        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);
        }
Ejemplo n.º 5
0
        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));
        }
Ejemplo n.º 6
0
        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);
                }
            }
        }
Ejemplo n.º 7
0
    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);
    }
Ejemplo n.º 8
0
        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);
            }
        }
Ejemplo n.º 9
0
        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);
            }
        }
Ejemplo n.º 10
0
        protected D2Unit GetPlayer()
        {
            if (player == null)
            {
                IntPtr playerAddress = reader.ReadAddress32(memory.Address.PlayerUnit, AddressingMode.Relative);
                player = reader.Read <D2Unit>(playerAddress);
            }

            return(player);
        }
Ejemplo n.º 11
0
        // 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);
        }
Ejemplo n.º 12
0
        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));
        }
Ejemplo n.º 13
0
        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()));
                }
            }
        }
Ejemplo n.º 14
0
    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);
    }
Ejemplo n.º 15
0
    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);
    }