view mm7_3.cpp @ 1957:3d0c57c4fa83

pActorBuffs[13] to pActorBuffs[ACTOR_BUFF_DAY_OF_PROTECTION]
author Grumpy7
date Fri, 25 Oct 2013 11:18:10 -0700
parents 524fe0810f32
children c1c74df0a33e
line wrap: on
line source

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif

#include "Weather.h"
#include "Texture.h"
#include "mm7_data.h"
#include "Sprites.h"
#include "BSPModel.h"
#include "LightmapBuilder.h"
#include "DecalBuilder.h"
#include "ParticleEngine.h"
#include "Mouse.h"
#include "Keyboard.h"
#include "stru6.h"
#include "FactionTable.h"
#include "MapInfo.h"
#include "Game.h"
#include "GUIWindow.h"
#include "GUIFont.h"
#include "GUIProgressBar.h"
#include "Party.h"
#include "AudioPlayer.h"
#include "Outdoor.h"
#include "Outdoor_stuff.h"
#include "Overlays.h"
#include "LOD.h"
#include "Actor.h"
#include "Events.h"
#include "Viewport.h"
#include "Math.h"
#include "SpriteObject.h"
#include "ObjectList.h"
#include "PaletteManager.h"
#include "DecorationList.h"
#include "stru123.h"
#include "Time.h"
#include "IconFrameTable.h"
#include "TurnEngine.h"
#include "Events2D.h"
#include "stru176.h"
#include "stru298.h"
#include "texts.h"
#include "Log.h"
#include "Lights.h"
#include "Level/Decoration.h"

#include "MM7.h"

//----- (0046E44E) --------------------------------------------------------
int  _46E44E_collide_against_faces_and_portals(unsigned int b1)
{
  BLVSector *pSector; // edi@1
  signed int v2; // ebx@1
  BLVFace *pFace; // esi@2
  __int16 pNextSector; // si@10
  int pArrayNum; // ecx@12
  unsigned __int8 v6; // sf@12
  unsigned __int8 v7; // of@12
  int result; // eax@14
  //BLVSector *v9; // ebx@15
  int v10; // ecx@15
  int pFloor; // eax@16
  //BLVFace *v12; // ebp@16
  int v13; // eax@24
  int v14; // esi@24
  int v15; // eax@24
  int v16; // edx@25
  int v17; // eax@29
  unsigned int v18; // eax@33
  int v19; // eax@35
  int v20; // edx@35
  int v21; // eax@35
  int v22; // ecx@36
  int v23; // eax@40
  unsigned int v24; // eax@44
  int a3; // [sp+10h] [bp-48h]@28
  int v26; // [sp+14h] [bp-44h]@15
  int i; // [sp+18h] [bp-40h]@1
  int a10; // [sp+1Ch] [bp-3Ch]@1
  int v29; // [sp+20h] [bp-38h]@14
  int v30; // [sp+24h] [bp-34h]@35
  int v31; // [sp+28h] [bp-30h]@24
  int v32; // [sp+2Ch] [bp-2Ch]@15
  int pSectorsArray[10]; // [sp+30h] [bp-28h]@1

  pSector = &pIndoor->pSectors[stru_721530.uSectorID];
  v2 = 0;
  a10 = b1;
  pSectorsArray[0] = stru_721530.uSectorID;
  for ( i = 1; v2 < pSector->uNumPortals; ++v2 )
  {
    pFace = &pIndoor->pFaces[pSector->pPortals[v2]];
    if ( stru_721530.sMaxX <= pFace->pBounding.x2
      && stru_721530.sMinX >= pFace->pBounding.x1
      && stru_721530.sMaxY <= pFace->pBounding.y2
      && stru_721530.sMinY >= pFace->pBounding.y1
      && stru_721530.sMaxZ <= pFace->pBounding.z2
      && stru_721530.sMinZ >= pFace->pBounding.z1
      && abs((pFace->pFacePlane_old.dist
            + stru_721530.normal.x * pFace->pFacePlane_old.vNormal.x
            + stru_721530.normal.y * pFace->pFacePlane_old.vNormal.y
            + stru_721530.normal.z * pFace->pFacePlane_old.vNormal.z) >> 16) <= stru_721530.field_6C + 16 )
    {
      pNextSector = pFace->uSectorID == stru_721530.uSectorID ? pFace->uBackSectorID : pFace->uSectorID;//FrontSectorID
      pArrayNum = i++;
      v7 = i < 10;
      v6 = i - 10 < 0;
      pSectorsArray[pArrayNum] = pNextSector;
      if ( !(v6 ^ v7) )
        break;
    }
  }
  result = 0;
  v29 = 0;
  if ( i > 0 )
  {
    while ( 1 )
    {
      pSector = &pIndoor->pSectors[pSectorsArray[result]];
      v10 = 0;
      v32 = pSector->uNumFloors + pSector->uNumWalls + pSector->uNumCeilings;
      v26 = 0;
      if ( v32 > 0 )
        break;
LABEL_46:
      result = v29++ + 1;
      if ( v29 >= i )
        return result;
    }
    while ( 1 )
    {
      pFloor = pSector->pFloors[v10];
      pFace = &pIndoor->pFaces[pFloor];
      if ( pFace->Portal()
        || stru_721530.sMaxX > pFace->pBounding.x2
        || stru_721530.sMinX < pFace->pBounding.x1
        || stru_721530.sMaxY > pFace->pBounding.y2
        || stru_721530.sMinY < pFace->pBounding.y1
        || stru_721530.sMaxZ > pFace->pBounding.z2
        || stru_721530.sMinZ < pFace->pBounding.z1
        || pFloor == stru_721530.field_84 )
        goto LABEL_45;
      v13 = pFace->pFacePlane_old.vNormal.y;
      v14 = pFace->pFacePlane_old.dist;
      v31 = v13;
      v15 = (stru_721530.normal.x * pFace->pFacePlane_old.vNormal.x + v14 + stru_721530.normal.y * v13
           + stru_721530.normal.z * pFace->pFacePlane_old.vNormal.z) >> 16;
      if ( v15 > 0 )
      {
        v16 = (stru_721530.normal2.y * v31 + pFace->pFacePlane_old.dist + stru_721530.normal2.z * pFace->pFacePlane_old.vNormal.z
             + stru_721530.normal2.x * pFace->pFacePlane_old.vNormal.x) >> 16;
        if ( v15 <= stru_721530.prolly_normal_d || v16 <= stru_721530.prolly_normal_d )
        {
          if ( v16 <= v15 )
          {
            a3 = stru_721530.field_6C;
            if ( sub_47531C(stru_721530.prolly_normal_d, &a3, stru_721530.normal.x, stru_721530.normal.y, stru_721530.normal.z,
                   stru_721530.direction.x, stru_721530.direction.y, stru_721530.direction.z, pFace, a10) )
            {
              v17 = a3;
            }
            else
            {
              a3 = stru_721530.field_6C + stru_721530.prolly_normal_d;
              if ( !sub_475D85(&stru_721530.normal, &stru_721530.direction, &a3, pFace) )
                goto LABEL_34;
              v17 = a3 - stru_721530.prolly_normal_d;
              a3 -= stru_721530.prolly_normal_d;
            }
            if ( v17 < stru_721530.field_7C )
            {
              stru_721530.field_7C = v17;
              v18 = 8 * pSector->pFloors[v26];
              LOBYTE(v18) = v18 | 6;
              stru_721530.uFaceID = v18;
            }
          }
        }
      }
LABEL_34:
      if ( !(stru_721530.field_0 & 1)
        || (v19 = pFace->pFacePlane_old.vNormal.x,
            v20 = pFace->pFacePlane_old.vNormal.y,
            v30 = v19,
            v21 = (stru_721530.position.x * v19 + pFace->pFacePlane_old.dist + stru_721530.position.y * v20
                 + stru_721530.position.z * pFace->pFacePlane_old.vNormal.z) >> 16,
            v21 <= 0)
        || (v22 = (stru_721530.field_4C * v30 + pFace->pFacePlane_old.dist + stru_721530.field_50 * v20
                 + stru_721530.field_54 * pFace->pFacePlane_old.vNormal.z) >> 16,
            v21 > stru_721530.prolly_normal_d)
        && v22 > stru_721530.prolly_normal_d
        || v22 > v21 )
        goto LABEL_45;
      a3 = stru_721530.field_6C;
      if ( sub_47531C(stru_721530.field_8_radius, &a3, stru_721530.position.x, stru_721530.position.y, stru_721530.position.z,
             stru_721530.direction.x, stru_721530.direction.y, stru_721530.direction.z, pFace, a10) )
      {
        v23 = a3;
        goto LABEL_43;
      }
      a3 = stru_721530.field_6C + stru_721530.field_8_radius;
      if ( sub_475D85(&stru_721530.position, &stru_721530.direction, &a3, pFace) )
      {
        v23 = a3 - stru_721530.prolly_normal_d;
        a3 -= stru_721530.prolly_normal_d;
LABEL_43:
        if ( v23 < stru_721530.field_7C )
        {
          stru_721530.field_7C = v23;
          v24 = 8 * pSector->pFloors[v26];
          LOBYTE(v24) = v24 | 6;
          stru_721530.uFaceID = v24;
        }
      }
LABEL_45:
      v10 = v26++ + 1;
      if ( v26 >= v32 )
        goto LABEL_46;
    }
  }
  return result;
}
// 46E44E: using guessed type int var_28[10];

//----- (0046E889) --------------------------------------------------------
int __fastcall _46E889_collide_against_bmodels(unsigned int ecx0)
{
  int result; // eax@1
  BSPModel *v2; // ecx@3
  int v3; // ebx@9
  ODMFace *v4; // eax@11
  int v5; // edi@17
  int v6; // esi@17
  unsigned int v7; // ecx@17
  int v8; // eax@19
  int v9; // ecx@20
  int v10; // eax@24
  int v11; // ST18_4@25
  int v12; // ST1C_4@25
  int v13; // ST0C_4@25
  unsigned int v14; // eax@28
  int v15; // eax@30
  int v16; // ecx@31
  unsigned int v17; // eax@36
  int v18; // ST18_4@41
  int v19; // ST1C_4@41
  int v20; // ST0C_4@41
  int v21; // eax@42
  unsigned int v22; // eax@43
  //BLVFace f; // [sp+Ch] [bp-7Ch]@1
  int v24; // [sp+6Ch] [bp-1Ch]@9
  int a11; // [sp+70h] [bp-18h]@1
  unsigned int v26; // [sp+74h] [bp-14h]@2
  unsigned int v27; // [sp+78h] [bp-10h]@10
  BSPModel *v28; // [sp+7Ch] [bp-Ch]@3
  int a10; // [sp+80h] [bp-8h]@1
  int a2; // [sp+84h] [bp-4h]@23

  a11 = ecx0;

  BLVFace f; // [sp+Ch] [bp-7Ch]@1
  //BLVFace::BLVFace(&f);

  result = 0;
  a10 = 0;
  if ( (signed int)pOutdoor->uNumBModels > 0 )
  {
    v26 = 0;
    while ( 1 )
    {
      v2 = &pOutdoor->pBModels[v26 / 0xBC];
      v28 = &pOutdoor->pBModels[v26 / 0xBC];
      if ( stru_721530.sMaxX <= pOutdoor->pBModels[v26 / 0xBC].sMaxX )
      {
        if ( stru_721530.sMinX >= v2->sMinX )
        {
          if ( stru_721530.sMaxY <= v2->sMaxY )
          {
            if ( stru_721530.sMinY >= v2->sMinY )
            {
              if ( stru_721530.sMaxZ <= v2->sMaxZ )
              {
                if ( stru_721530.sMinZ >= v2->sMinZ )
                {
                  v3 = 0;
                  v24 = v2->uNumFaces;
                  if ( v24 > 0 )
                    break;
                }
              }
            }
          }
        }
      }
LABEL_39:
      ++a10;
      v26 += 188;
      result = a10;
      if ( a10 >= (signed int)pOutdoor->uNumBModels )
        return result;
    }
    v27 = 0;
    while ( 1 )
    {
      v4 = &v2->pFaces[v27 / 0x134];
      if ( stru_721530.sMaxX > v4->pBoundingBox.x2
        || stru_721530.sMinX < v4->pBoundingBox.x1
        || stru_721530.sMaxY > v4->pBoundingBox.y2
        || stru_721530.sMinY < v4->pBoundingBox.y1
        || stru_721530.sMaxZ > v4->pBoundingBox.z2
        || stru_721530.sMinZ < v4->pBoundingBox.z1 )
        goto LABEL_38;
      f.pFacePlane_old.vNormal.x = v4->pFacePlane.vNormal.x;
      f.pFacePlane_old.vNormal.y = v4->pFacePlane.vNormal.y;
      v5 = v4->pFacePlane.vNormal.z;
      f.pFacePlane_old.vNormal.z = v4->pFacePlane.vNormal.z;
      v6 = v4->pFacePlane.dist;
      f.pFacePlane_old.dist = v4->pFacePlane.dist;
      v7 = v4->uAttributes;
      f.uAttributes = v7;
      f.pBounding.x1 = v4->pBoundingBox.x1;
      f.pBounding.y1 = v4->pBoundingBox.y1;
      f.pBounding.z1 = v4->pBoundingBox.z1;
      f.pBounding.x2 = v4->pBoundingBox.x2;
      f.pBounding.y2 = v4->pBoundingBox.y2;
      f.pBounding.z2 = v4->pBoundingBox.z2;
      f.zCalc1 = v4->zCalc1;
      f.zCalc2 = v4->zCalc2;
      f.zCalc3 = v4->zCalc3;
      f.pXInterceptDisplacements = v4->pXInterceptDisplacements;
      f.pYInterceptDisplacements = v4->pYInterceptDisplacements;
      f.pZInterceptDisplacements = v4->pZInterceptDisplacements;
      f.uPolygonType = (PolygonType)v4->uPolygonType;
      f.uNumVertices = v4->uNumVertices;
      f.uBitmapID = v4->uTextureID;
      f.pVertexIDs = v4->pVertexIDs;
      if ( !(v7 & 0x20000000) )
      {
        if ( !(v7 & 1) )
          break;
      }
LABEL_37:
      v2 = v28;
LABEL_38:
      v27 += 308;
      ++v3;
      if ( v3 >= v24 )
        goto LABEL_39;
    }
    v8 = (v5 * stru_721530.normal.z
        + v6
        + f.pFacePlane_old.vNormal.y * stru_721530.normal.y
        + f.pFacePlane_old.vNormal.x * stru_721530.normal.x) >> 16;
    if ( v8 > 0 )
    {
      v9 = (v5 * stru_721530.normal2.z
          + v6
          + f.pFacePlane_old.vNormal.y * stru_721530.normal2.y
          + f.pFacePlane_old.vNormal.x * stru_721530.normal2.x) >> 16;
      if ( v8 <= stru_721530.prolly_normal_d || v9 <= stru_721530.prolly_normal_d )
      {
        if ( v9 <= v8 )
        {
          a2 = stru_721530.field_6C;
          if ( sub_4754BF(
                 stru_721530.prolly_normal_d,
                 &a2,
                 stru_721530.normal.x,
                 stru_721530.normal.y,
                 stru_721530.normal.z,
                 stru_721530.direction.x,
                 stru_721530.direction.y,
                 stru_721530.direction.z,
                 &f,
                 a10,
                 a11) )
          {
            v10 = a2;
          }
          else
          {
            v11 = stru_721530.direction.y;
            v12 = stru_721530.direction.z;
            v13 = stru_721530.normal.y;
            a2 = stru_721530.prolly_normal_d + stru_721530.field_6C;
            if ( !sub_475F30(
                    &a2,
                    &f,
                    stru_721530.normal.x,
                    v13,
                    stru_721530.normal.z,
                    stru_721530.direction.x,
                    v11,
                    v12,
                    a10) )
              goto LABEL_29;
            v10 = a2 - stru_721530.prolly_normal_d;
            a2 -= stru_721530.prolly_normal_d;
          }
          if ( v10 < stru_721530.field_7C )
          {
            stru_721530.field_7C = v10;
            v14 = 8 * (v3 | (a10 << 6));
            LOBYTE(v14) = v14 | 6;
            stru_721530.uFaceID = v14;
          }
        }
      }
    }
LABEL_29:
    if ( stru_721530.field_0 & 1 )
    {
      v15 = (f.pFacePlane_old.vNormal.z * stru_721530.position.z
           + f.pFacePlane_old.dist
           + f.pFacePlane_old.vNormal.y * stru_721530.position.y
           + f.pFacePlane_old.vNormal.x * stru_721530.position.x) >> 16;
      if ( v15 > 0 )
      {
        v16 = (f.pFacePlane_old.vNormal.z * stru_721530.field_54
             + f.pFacePlane_old.dist
             + f.pFacePlane_old.vNormal.y * stru_721530.field_50
             + f.pFacePlane_old.vNormal.x * stru_721530.field_4C) >> 16;
        if ( v15 <= stru_721530.prolly_normal_d || v16 <= stru_721530.prolly_normal_d )
        {
          if ( v16 <= v15 )
          {
            a2 = stru_721530.field_6C;
            if ( sub_4754BF(stru_721530.field_8_radius,
                   &a2,
                   stru_721530.position.x,
                   stru_721530.position.y,
                   stru_721530.position.z,
                   stru_721530.direction.x,
                   stru_721530.direction.y,
                   stru_721530.direction.z,
                   &f,
                   a10,
                   a11) )
            {
              if ( a2 < stru_721530.field_7C )
              {
                stru_721530.field_7C = a2;
                v17 = 8 * (v3 | (a10 << 6));
                LOBYTE(v17) = v17 | 6;
                stru_721530.uFaceID = v17;
              }
            }
            else
            {
              v18 = stru_721530.direction.y;
              v19 = stru_721530.direction.z;
              v20 = stru_721530.position.y;
              a2 = stru_721530.field_6C + stru_721530.field_8_radius;
              if ( sub_475F30(&a2,
                     &f,
                     stru_721530.position.x,
                     v20,
                     stru_721530.position.z,
                     stru_721530.direction.x,
                     v18,
                     v19,
                     a10) )
              {
                v2 = v28;
                v21 = a2 - stru_721530.prolly_normal_d;
                a2 -= stru_721530.prolly_normal_d;
                if ( a2 < stru_721530.field_7C )
                {
                  stru_721530.field_7C = v21;
                  v22 = 8 * (v3 | (a10 << 6));
                  LOBYTE(v22) = v22 | 6;
                  stru_721530.uFaceID = v22;
                }
                goto LABEL_38;
              }
            }
          }
        }
      }
    }
    goto LABEL_37;
  }
  return result;
}

//----- (0046ED1B) --------------------------------------------------------
int collide_against_floor(int x, int y, int z, unsigned int *pSectorID, unsigned int *pFaceID)
{
  uint uFaceID = -1;
  int floor_level = BLV_GetFloorLevel(x, y, z, *pSectorID, &uFaceID);

  if (floor_level != -30000 && floor_level <= z + 50)
  {
    *pFaceID = uFaceID;
    return floor_level;
  }

  uint uSectorID = pIndoor->GetSector(x, y, z);
  *pSectorID = uSectorID;

  floor_level = BLV_GetFloorLevel(x, y, z, uSectorID, &uFaceID);
  if (uSectorID && floor_level != -30000)
    *pFaceID = uFaceID;
  else return -30000;
  return floor_level;
}

//----- (0046ED8A) --------------------------------------------------------
void __fastcall _46ED8A_collide_against_sprite_objects(unsigned int _this)
{
  int v1; // ebx@2
  ObjectDesc *v2; // edx@4
  int v3; // esi@5
  int v4; // ecx@5
  int v5; // eax@7
  int v6; // edi@9
  int v7; // edx@9
  int v8; // edi@11
  int v9; // ebx@11
  int v10; // ecx@12
  int v11; // esi@13
  signed int v12; // [sp+0h] [bp-14h]@1
  int v13; // [sp+4h] [bp-10h]@9
  char *v14; // [sp+8h] [bp-Ch]@2
  unsigned int v15; // [sp+10h] [bp-4h]@1

  v15 = 0;
  v12 = _this;
  if ( (signed int)uNumSpriteObjects > 0 )
  {
    v1 = (int)&pSpriteObjects[0].uObjectDescID;
    v14 = (char *)&pSpriteObjects[0].uObjectDescID;
    do
    {
      if ( *(short *)v1 )
      {
        v2 = &pObjectList->pObjects[*(short *)v1];
        if ( !(v2->uFlags & 2) )
        {
          v3 = v2->uRadius;
          v4 = *(int *)(v1 + 2);
          if ( stru_721530.sMaxX <= v4 + v3 )
          {
            if ( stru_721530.sMinX >= v4 - v3 )
            {
              v5 = *(int *)(v1 + 6);
              if ( stru_721530.sMaxY <= v5 + v3 )
              {
                if ( stru_721530.sMinY >= v5 - v3 )
                {
                  v6 = v2->uHeight;
                  v7 = *(int *)(v1 + 10);
                  v13 = v6;
                  if ( stru_721530.sMaxZ <= v7 + v6 )
                  {
                    if ( stru_721530.sMinZ >= v7 )
                    {
                      v8 = v4 - stru_721530.normal.x;
                      v9 = v5 - stru_721530.normal.y;
                      if ( abs(((v4 - stru_721530.normal.x) * stru_721530.direction.y
                              - (v5 - stru_721530.normal.y) * stru_721530.direction.x) >> 16) <= v3
                                                                                              + stru_721530.prolly_normal_d )
                      {
                        v10 = (v8 * stru_721530.direction.x + v9 * stru_721530.direction.y) >> 16;
                        if ( v10 > 0 )
                        {
                          v11 = stru_721530.normal.z
                              + ((unsigned __int64)(stru_721530.direction.z * (signed __int64)v10) >> 16);
                          if ( v11 >= *(int *)(v14 + 10) - stru_721530.prolly_normal_d )
                          {
                            if ( v11 <= v13 + stru_721530.prolly_normal_d + *(int *)(v14 + 10) )
                            {
                              if ( v10 < stru_721530.field_7C )
                                sub_46DEF2(v12, v15);
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
      ++v15;
      v1 = (int)(v14 + 112);
      v14 += 112;
    }
    while ( (signed int)v15 < (signed int)uNumSpriteObjects );
  }
}

//----- (0046EF01) --------------------------------------------------------
int _46EF01_collision_chech_player(int a1)
{
  int v1; // edx@1
  int result; // eax@1
  int v3; // ebx@7
  int v4; // esi@7
  int v5; // edi@8
  int v6; // ecx@9
  int v7; // edi@12
  int v8; // [sp+Ch] [bp-10h]@1
  unsigned int v9; // [sp+10h] [bp-Ch]@1
  int v10; // [sp+14h] [bp-8h]@7
  int v11; // [sp+18h] [bp-4h]@7

  v8 = a1;
  v1 = 2 * pParty->field_14_radius;
  result = pParty->vPosition.x;
  v9 = pParty->uPartyHeight;
  if ( stru_721530.sMaxX <= pParty->vPosition.x + 2 * pParty->field_14_radius )
  {
    if ( stru_721530.sMinX >= pParty->vPosition.x - v1 )
    {
      if ( stru_721530.sMaxY <= pParty->vPosition.y + v1 )
      {
        if ( stru_721530.sMinY >= pParty->vPosition.y - v1 )
        {
          if ( stru_721530.sMaxZ <= (signed int)(pParty->vPosition.z + pParty->uPartyHeight) )
          {
            if ( stru_721530.sMinZ >= pParty->vPosition.z )
            {
              v3 = stru_721530.prolly_normal_d + v1;
              v11 = pParty->vPosition.x - stru_721530.normal.x;
              v4 = ((pParty->vPosition.x - stru_721530.normal.x) * stru_721530.direction.y
                  - (pParty->vPosition.y - stru_721530.normal.y) * stru_721530.direction.x) >> 16;
              v10 = pParty->vPosition.y - stru_721530.normal.y;
              result = abs(((pParty->vPosition.x - stru_721530.normal.x) * stru_721530.direction.y
                          - (pParty->vPosition.y - stru_721530.normal.y) * stru_721530.direction.x) >> 16);
              if ( result <= v3 )
              {
                result = v10 * stru_721530.direction.y;
                v5 = (v10 * stru_721530.direction.y + v11 * stru_721530.direction.x) >> 16;
                if ( v5 > 0 )
                {
                  v6 = ((unsigned __int64)(stru_721530.direction.z * (signed __int64)v5) >> 16) + stru_721530.normal.z;
                  result = pParty->vPosition.z;
                  if ( v6 >= pParty->vPosition.z )
                  {
                    result = v9 + pParty->vPosition.z;
                    if ( v6 <= (signed int)(v9 + pParty->vPosition.z) || v8 )
                    {
                      result = integer_sqrt(v3 * v3 - v4 * v4);
                      v7 = v5 - result;
                      if ( v7 < 0 )
                        v7 = 0;
                      if ( v7 < stru_721530.field_7C )
                      {
                        stru_721530.field_7C = v7;
                        stru_721530.uFaceID = 4;
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  return result;
}

//----- (0046F04E) --------------------------------------------------------
int _46F04E_collide_against_portals()
{
  BLVSector *v0; // ecx@1
  unsigned int v1; // eax@1
  int v2; // eax@2
  BLVFace *v3; // eax@3
  int v4; // ecx@9
  int v5; // edx@9
  signed int result; // eax@21
  BLVFace *v7; // eax@22
  signed int v8; // [sp+0h] [bp-14h]@1
  BLVSector *v9; // [sp+4h] [bp-10h]@1
  unsigned int v10; // [sp+8h] [bp-Ch]@1
  int a3; // [sp+Ch] [bp-8h]@13
  int v12; // [sp+10h] [bp-4h]@15

  v8 = 0;
  v0 = &pIndoor->pSectors[stru_721530.uSectorID];
  v1 = 0xFFFFFFu;
  v10 = 0xFFFFFFu;
  v9 = v0;
  if ( v0->uNumPortals > 0 )
  {
    do
    {
      v2 = v0->pPortals[v8];
      if ( v2 != stru_721530.field_80 )
      {
        v3 = &pIndoor->pFaces[v2];
        if ( stru_721530.sMaxX <= v3->pBounding.x2 )
        {
          if ( stru_721530.sMinX >= v3->pBounding.x1
            && stru_721530.sMaxY <= v3->pBounding.y2
            && stru_721530.sMinY >= v3->pBounding.y1
            && stru_721530.sMaxZ <= v3->pBounding.z2
            && stru_721530.sMinZ >= v3->pBounding.z1 )
          {
            v4 = (stru_721530.normal.x * v3->pFacePlane_old.vNormal.x + v3->pFacePlane_old.dist
                + stru_721530.normal.y * v3->pFacePlane_old.vNormal.y
                + stru_721530.normal.z * v3->pFacePlane_old.vNormal.z) >> 16;
            v5 = (stru_721530.normal2.z * v3->pFacePlane_old.vNormal.z + v3->pFacePlane_old.dist
                + stru_721530.normal2.x * v3->pFacePlane_old.vNormal.x
                + stru_721530.normal2.y * v3->pFacePlane_old.vNormal.y) >> 16;
            if ( (v4 < stru_721530.prolly_normal_d || v5 < stru_721530.prolly_normal_d)
              && (v4 > -stru_721530.prolly_normal_d || v5 > -stru_721530.prolly_normal_d)
              && (a3 = stru_721530.field_6C, sub_475D85(&stru_721530.normal, &stru_721530.direction, &a3, v3))
              && a3 < (signed int)v10 )
            {
              v0 = v9;
              v10 = a3;
              v12 = v9->pPortals[v8];
            }
            else
            {
              v0 = v9;
            }
          }
        }
      }
      ++v8;
    }
    while ( v8 < v0->uNumPortals );
    v1 = v10;
  }
  if ( stru_721530.field_7C >= (signed int)v1 && (signed int)v1 <= stru_721530.field_6C )
  {
    stru_721530.field_80 = v12;
    v7 = &pIndoor->pFaces[v12];
    if ( v7->uSectorID == stru_721530.uSectorID )
      stru_721530.uSectorID = v7->uBackSectorID;
    else
      stru_721530.uSectorID = v7->uSectorID;
    stru_721530.field_7C = 268435455;
    result = 0;
  }
  else
  {
    result = 1;
  }
  return result;
}

//----- (0047050A) --------------------------------------------------------
int stru141_actor_collision_object::_47050A(int dt)
{
  //stru141_actor_collision_object *v2; // esi@1
  //signed int v3; // eax@1
  //int v4; // ecx@1
  //int v5; // edx@1
  //int v6; // edx@1
  int v7; // eax@1
  //int v8; // eax@3
  signed int result; // eax@4
  //int v10; // eax@5
  //int v11; // eax@5
  //int v12; // ebx@5
  //int v13; // edx@5
  //int v14; // edi@5
  //int v15; // ecx@5
  //int v16; // eax@5
  int v17; // eax@5
  int v18; // eax@7
  //int v19; // edx@9
  //int v20; // edi@9
  int v21; // eax@9
  int v22; // eax@11
  //int v23; // edx@13
  //int v24; // eax@13
  //int v25; // eax@14
  //int v26; // eax@16
  //int v27; // eax@17
  //int v28; // [sp+14h] [bp+8h]@5

  //v2 = this;
  int speed = 1 | integer_sqrt(this->velocity.z * this->velocity.z + this->velocity.y * this->velocity.y + this->velocity.x * this->velocity.x);

  this->direction.x = 65536 / speed * this->velocity.x;
  this->direction.y = 65536 / speed * this->velocity.y;
  this->direction.z = 65536 / speed * this->velocity.z;

  this->speed = speed;
  this->inv_speed = 65536 / speed;

  if (dt)
    v7 = dt;
  else
    v7 = pEventTimer->dt_in_some_format;

  //v8 = fixpoint_mul(v7, speed) - this->field_70; // speed * dt - something
  this->field_6C = fixpoint_mul(v7, speed) - this->field_70;
  if ( this->field_6C > 0 )
  {
    //v10 = fixpoint_mul(v8, this->direction.x) + this->normal.x;
    this->field_4C = fixpoint_mul(this->field_6C, this->direction.x) + this->normal.x;
    this->normal2.x = fixpoint_mul(this->field_6C, this->direction.x) + this->normal.x;
    //v11 = fixpoint_mul(this->field_6C, this->direction.y) + this->normal.y;
    this->field_50 = fixpoint_mul(this->field_6C, this->direction.y) + this->normal.y;
    this->normal2.y = fixpoint_mul(this->field_6C, this->direction.y) + this->normal.y;
    this->normal2.z = fixpoint_mul(this->field_6C, this->direction.z) + this->normal.z;
    //v12 = this->position.z;
    //v13 = this->normal.x;
    //v14 = this->normal2.x;
    //v15 = this->prolly_normal_d;
    //v16 = this->position.z + fixpoint_mul(this->field_6C, this->direction.z);
    //v28 = this->position.z + fixpoint_mul(this->field_6C, this->direction.z);
    this->field_54 = this->position.z + fixpoint_mul(this->field_6C, this->direction.z);
    v17 = this->normal.x;
    if ( v17 >= this->normal2.x )
      v17 = this->normal2.x;
    this->sMaxX = v17 - this->prolly_normal_d;
    v18 = this->prolly_normal_d + this->normal.x;
    if ( this->normal.x <= this->normal2.x )
      v18 = this->prolly_normal_d + this->normal2.x;
    //v19 = this->normal.y;
    //v20 = this->normal2.y;
    this->sMinX = v18;
    v21 = this->normal.y;
    if ( v21 >= this->normal2.y )
      v21 = this->normal2.y;
    this->sMaxY = v21 - this->prolly_normal_d;
    v22 = this->prolly_normal_d + this->normal.y;
    if ( this->normal.y <= this->normal2.y )
      v22 = this->normal2.y + this->prolly_normal_d;
    //v23 = this->normal2.z;
    this->sMinY = v22;
    //v24 = this->normal.z;
    if ( this->normal.z >= this->normal2.z )
      this->sMaxZ = this->normal2.z - this->prolly_normal_d;
    else
      this->sMaxZ = this->normal.z - this->prolly_normal_d;
    //this->sMaxZ = v25;
    //v26 = this->field_8_radius;
    if ( this->position.z <= this->position.z + fixpoint_mul(this->field_6C, this->direction.z) )
      this->sMinZ = (this->position.z + fixpoint_mul(this->field_6C, this->direction.z)) + this->field_8_radius;
    else
      this->sMinZ = this->position.z + this->field_8_radius;
    this->uFaceID = 0;
    this->field_80 = -1;
    this->field_88 = -1;
    //this->sMinZ = v27;
    this->field_7C = 0xFFFFFFu;
    result = 0;
  }
  else
  {
    result = 1;
  }
  return result;
}

//----- (004706C6) --------------------------------------------------------
void UpdateActors_ODM()
{
  Actor *v0; // esi@2
  AIState uAIState; // ax@2
  //unsigned int v2; // ecx@6
  int v3; // ebx@6
  //int v4; // eax@8
  int v5; // eax@10
  int v6; // ecx@10
  //signed int v7; // ebx@10
  signed int v8; // ebx@17
  //unsigned __int8 v9; // zf@17
  unsigned __int8 v10; // sf@17
  unsigned __int16 v11; // ax@21
  //int v12; // eax@29
  //unsigned __int64 v13; // qax@29
  //int v14; // eax@30
  //unsigned __int64 v15; // qax@30
  int v16; // eax@33
  //int v17; // edi@34
  //int v18; // edx@42
  //int v19; // ecx@42
  __int16 v20; // ax@42
  //int v21; // ebx@42
  //int v22; // edi@42
  //int v23; // ecx@42
  //__int16 v24; // ax@42
  int v25; // eax@45
  signed int v26; // ecx@50
  //int v27; // eax@52
  int v28; // eax@54
  signed int v29; // ebx@57
  signed int v30; // eax@57
  int v31; // edi@57
  signed int i; // ebx@57
  unsigned int v33; // ecx@58
  //int v34; // ebx@64
  int v35; // edi@64
  int v36; // eax@64
  //unsigned __int16 v37; // cx@66
  signed int v38; // edx@71
  unsigned int v39; // edi@71
  BSPModel *v40; // eax@75
  ODMFace *v41; // edi@75
  int v42; // ebx@76
  int v43; // ecx@77
  int v44; // edx@77
  __int16 v45; // dx@82
  int v46; // ecx@82
  signed int v47; // ebx@85
  int v48; // edi@85
  int v49; // edi@85
  //int v50; // eax@85
  //unsigned __int64 v51; // qax@85
  //unsigned __int8 v52; // zf@87
  //unsigned __int8 v53; // sf@87
 // unsigned __int8 v54; // of@104
  int v55; // eax@107
  unsigned int v56; // edi@107
  int v57; // ST10_4@107
  unsigned int v58; // edi@107
  unsigned int v59; // ebx@107
  signed int v60; // eax@107
  int v61; // eax@124
  Vec3_int_ v62; // [sp+Ch] [bp-44h]@42
  int v63; // [sp+18h] [bp-38h]@64
  int v64; // [sp+1Ch] [bp-34h]@64
  int v65; // [sp+20h] [bp-30h]@2
  int v66; // [sp+24h] [bp-2Ch]@2
  bool v67; // [sp+28h] [bp-28h]@10
  //unsigned int v68; // [sp+2Ch] [bp-24h]@10
  unsigned int v69; // [sp+30h] [bp-20h]@6
  unsigned int v70; // [sp+34h] [bp-1Ch]@10
  int v71; // [sp+38h] [bp-18h]@62
  int uIsAboveFloor; // [sp+3Ch] [bp-14h]@10
  int v72b;
  //int v73; // [sp+40h] [bp-10h]@17
  int uIsFlying; // [sp+44h] [bp-Ch]@8
  unsigned int v75; // [sp+48h] [bp-8h]@1
  int uIsOnWater; // [sp+4Ch] [bp-4h]@10

  for (v75 = 0; v75 < uNumActors; ++v75)
  {
    v0 = &pActors[v75];
    v66 = v0->vPosition.x;
    v65 = v0->vPosition.y;
    uAIState = v0->uAIState;
    if ( uAIState == Removed || uAIState == Disabled || uAIState == Summoned || !v0->uMovementSpeed )
	{
		continue;
	}
    v3 = 0;
    v69 = 0;
    if ( MonsterStats::BelongsToSupertype(v0->pMonsterInfo.uID, MONSTER_SUPERTYPE_WATER_ELEMENTAL) )
      v3 = 1;
    v0->uSectorID = 0;
    uIsFlying = v0->pMonsterInfo.uFlying;
    if ( !v0->CanAct() )
      uIsFlying = 0;
    v70 = IsTerrainSlopeTooHigh(v0->vPosition.x, v0->vPosition.y);
    v5 = ODM_GetFloorLevel(
           v0->vPosition.x,
           v0->vPosition.y,
           v0->vPosition.z,
           v0->uActorHeight,
           &uIsOnWater,
           (int *)&v69,
           v3);
    v6 = v0->vPosition.z;
    uIsAboveFloor = 0;
    v67 = v69 == 0;
    if ( v6 > v5 + 1 )
      uIsAboveFloor = 1;
    if ( uAIState == Dead && uIsOnWater && !uIsAboveFloor )
    {
      v0->uAIState = Removed;
	  continue;
    }
    if ( v0->uCurrentActionAnimation == ANIM_Walking )
    {
      v8 = v0->uMovementSpeed;
      if ( (signed __int64)v0->pActorBuffs[ACTOR_BUFF_SLOWED].uExpireTime > 0 )
      {
        v8 = (signed __int64)((double)v8 * 0.5);
      }
      if ( uAIState == Fleeing || uAIState == Pursuing )
      {
        v8 *= 2;
      }
      if ( pParty->bTurnBasedModeOn == 1 && pTurnEngine->turn_stage == 1 )
        v8 *= flt_6BE3AC_debug_recmod1_x_1_6;
      if ( v8 > 1000 )
        v8 = 1000;

      v0->vVelocity.x = fixpoint_mul(stru_5C6E00->Cos(v0->uYawAngle), v8);
      v0->vVelocity.y = fixpoint_mul(stru_5C6E00->Sin(v0->uYawAngle), v8);
      if ( uIsFlying )
      {
        v0->vVelocity.z = fixpoint_mul(stru_5C6E00->Sin(v0->uPitchAngle), v8);
      }
      //v7 = v68;
    }
    else
    {
      v0->vVelocity.x = fixpoint_mul(55000, v0->vVelocity.x);
      v0->vVelocity.y = fixpoint_mul(55000, v0->vVelocity.y);
      if ( uIsFlying )
      {
        v0->vVelocity.z = fixpoint_mul(55000, v0->vVelocity.z);
      }
    }
    if ( v0->vPosition.z < v5 )
    {
      v16 = uIsFlying;
      v0->vPosition.z = v5;
      v0->vVelocity.z = v16 != 0 ? 0x14 : 0;
    }
    //v17 = 0;
    if ( !uIsAboveFloor || uIsFlying )
    {
      if ( v70 && !uIsAboveFloor && v67 )
      {
        v0->vPosition.z = v5;
        ODM_GetTerrainNormalAt(v0->vPosition.x, v0->vPosition.y, &v62);
        v20 = GetGravityStrength();
        //v21 = v62.y;
        //v22 = v62.z;
        //v23 = v62.y * v0->vVelocity.y;
        v0->vVelocity.z += -8 * LOWORD(pEventTimer->uTimeElapsed) * v20;
        int v73 = abs(v62.x * v0->vVelocity.x + v62.z * v0->vVelocity.z + v62.y * v0->vVelocity.y) >> 16;
        //v72b = v21;
        v0->vVelocity.x += fixpoint_mul(v73, v62.x);
        v0->vVelocity.y += fixpoint_mul(v73, v62.y);
        v0->vVelocity.z += fixpoint_mul(v73, v62.z);
        //v17 = 0;
      }
    }
    else
    {
      v0->vVelocity.z -= LOWORD(pEventTimer->uTimeElapsed) * GetGravityStrength();
    }
    if ( pParty->armageddon_timer != 0 && v0->CanAct() )
    {
      v0->vVelocity.x += rand() % 100 - 50;
      v0->vVelocity.y += rand() % 100 - 50;
      v0->vVelocity.z += rand() % 100 - 20;
      v25 = rand();
      v0->uAIState = Stunned;
      v0->uYawAngle += v25 % 32 - 16;
      v0->UpdateAnimation();
    }
    if ( v0->vVelocity.x * v0->vVelocity.x + v0->vVelocity.y * v0->vVelocity.y < 400 && v70 == 0 )
    {
      v0->vVelocity.y = 0;
      v0->vVelocity.x = 0;
    }
    stru_721530.field_0 = 1;
    if ( !uIsFlying )
      v26 = 40;
    else
      v26 = v0->uActorRadius;

    stru_721530.field_84 = -1;
    stru_721530.field_8_radius = v26;
    stru_721530.prolly_normal_d = v26;
    stru_721530.height = v0->uActorHeight;
    stru_721530.field_70 = 0;
    v69 = 0;
    while ( 1 )
    {
      stru_721530.position.x = v0->vPosition.x;
      stru_721530.normal.x = stru_721530.position.x;
      stru_721530.position.y = v0->vPosition.y;
      stru_721530.normal.y = stru_721530.position.y;
      v28 = v0->vPosition.z;
      stru_721530.normal.z = v28 + v26 + 1;
      stru_721530.position.z = v28 - v26 + stru_721530.height - 1;
      if ( stru_721530.position.z < stru_721530.normal.z )
        stru_721530.position.z = v28 + v26 + 1;
      stru_721530.velocity.x = v0->vVelocity.x;
      stru_721530.uSectorID = 0;
      stru_721530.velocity.y = v0->vVelocity.y;
      stru_721530.velocity.z = v0->vVelocity.z;
      if ( stru_721530._47050A(0) )
        break;
      _46E889_collide_against_bmodels(1u);
      v29 = WorldPosToGridCellZ(v0->vPosition.y);
      v30 = WorldPosToGridCellX(v0->vPosition.x);
      _46E26D_collide_against_sprites(v30, v29);
      _46EF01_collision_chech_player(0);
      _46ED8A_collide_against_sprite_objects(PID(OBJECT_Actor,v75));
      v31 = 0;
      for ( i = 0; v31 < ai_arrays_size; ++v31 )
      {
        v33 = ai_near_actors_ids[v31];
        if ( v33 != v75 && Actor::_46DF1A_collide_against_actor(v33, 40) )
          ++i;
      }
      v71 = i > 1;
      if ( stru_721530.field_7C < stru_721530.field_6C )
        v70 = fixpoint_mul(stru_721530.field_7C, stru_721530.direction.z);
      //v34 = 0;
      v35 = stru_721530.normal2.z - stru_721530.prolly_normal_d - 1;
      v36 = ODM_GetFloorLevel(stru_721530.normal2.x,
              stru_721530.normal2.y,
              stru_721530.normal2.z - stru_721530.prolly_normal_d - 1,
              v0->uActorHeight,
              (int *)&v63,
              &v64,
              0);
      if ( uIsOnWater )
      {
        if ( v35 < v36 + 60 )
        {
          if ( uAIState == Dead || uAIState == Dying || uAIState == Removed || uAIState == Disabled )
          {
            if ( v64 )
              v61 = v36 + 30;
            else
              v61 = v5 + 60;
            sub_42F960_create_object(v0->vPosition.x, v0->vPosition.y, v61);
            v0->uAIState = Removed;
            return;
          }
        }
      }
      if ( stru_721530.field_7C >= stru_721530.field_6C )
      {
        v0->vPosition.x = LOWORD(stru_721530.normal2.x);
        v0->vPosition.y = LOWORD(stru_721530.normal2.y);
        v0->vPosition.z = LOWORD(stru_721530.normal2.z) - LOWORD(stru_721530.prolly_normal_d) - 1;
        break;
      }
      //v72b = fixpoint_mul(stru_721530.field_7C, stru_721530.field_58.x);
      v0->vPosition.x += fixpoint_mul(stru_721530.field_7C, stru_721530.direction.x);
      //v72b = (unsigned __int64)(stru_721530.field_7C * (signed __int64)stru_721530.field_58.y) >> 16;
      v0->vPosition.y += fixpoint_mul(stru_721530.field_7C, stru_721530.direction.y);
      //v72b = (unsigned __int64)(stru_721530.field_7C * (signed __int64)stru_721530.field_58.z) >> 16;
      v0->vPosition.z += fixpoint_mul(stru_721530.field_7C, stru_721530.direction.z);
      v38 = stru_721530.uFaceID;
      stru_721530.field_70 += stru_721530.field_7C;
	  v39 = PID_ID(v38);
      switch ( PID_TYPE(v38) )
      {
        case OBJECT_Actor:
          if ( pTurnEngine->turn_stage != 2 && pTurnEngine->turn_stage != 3 || pParty->bTurnBasedModeOn != 1 )
          {
			//if(pParty->bTurnBasedModeOn == 1)
				//v34 = 0;
            if ( v0->pMonsterInfo.uHostilityType )
            {
              if ( v71 == 0 )
			  {
				  Actor::AI_Flee(v75, v38, 0, (AIDirection *)0);
			  }
			  else
			  {
				  Actor::AI_StandOrBored(v75, 4, 0, (AIDirection *)0);
			  }
            }
            else if ( v71 )
			{
              Actor::AI_StandOrBored(v75, 4, 0, (AIDirection *)0);
			}
			else if ( pActors[v39].pMonsterInfo.uHostilityType == MonsterInfo::Hostility_Friendly )
            {
              Actor::AI_Flee(v75, v38, 0, (AIDirection *)0);
            }
			else
			{
				Actor::AI_FaceObject(v75, v38, 0, (AIDirection *)0);
			}
          }
          break;
        case OBJECT_Player:
          if ( !v0->GetActorsRelation(0) )
          {
            v38 = stru_721530.uFaceID;
            Actor::AI_FaceObject(v75, v38, 0, (AIDirection *)0);
            break;
          }
          //v52 = HIDWORD(pParty->pPartyBuffs[PARTY_BUFF_INVISIBILITY].uExpireTime) == 0;
          //v53 = SHIDWORD(pParty->pPartyBuffs[PARTY_BUFF_INVISIBILITY].uExpireTime) < 0;
          v0->vVelocity.y = 0;
          v0->vVelocity.x = 0;
          //if ( !v53 && (!(v53 | v52) || LODWORD(pParty->pPartyBuffs[PARTY_BUFF_INVISIBILITY].uExpireTime) > 0) )
		  if ( (signed __int64)pParty->pPartyBuffs[PARTY_BUFF_INVISIBILITY].uExpireTime < 0)
            pParty->pPartyBuffs[PARTY_BUFF_INVISIBILITY].Reset();
          viewparams->bRedrawGameUI = 1;
          break;
        case OBJECT_Decoration:
          v47 = integer_sqrt(v0->vVelocity.x * v0->vVelocity.x + v0->vVelocity.y * v0->vVelocity.y);
          v48 = stru_5C6E00->Atan2(
                  v0->vPosition.x - pLevelDecorations[v39].vPosition.x,
                  v0->vPosition.y - pLevelDecorations[v39].vPosition.y);
          v49 = v48;
          v0->vVelocity.x = fixpoint_mul(stru_5C6E00->Cos(v48), v47);
          v0->vVelocity.y = fixpoint_mul(stru_5C6E00->Sin(v48), v47);
          break;
        case OBJECT_BModel:
          v40 = &pOutdoor->pBModels[v38 >> 9];
          v41 = &v40->pFaces[v39 & 0x3F];
          if ( !(v41->uAttributes & 0x20000000) )
          {
            v42 = v41->uPolygonType;
            if ( v42 == 3 )
            {
              v43 = v0->vVelocity.y;
              v44 = v0->vVelocity.x;
              v0->vVelocity.z = 0;
              v0->vPosition.z = LOWORD(v40->pVertices.pVertices[v41->pVertexIDs[0]].z) + 1;
              if ( v44 * v44 + v43 * v43 < 400 )
              {
                v0->vVelocity.y = 0;
                v0->vVelocity.x = 0;
              }
            }
            else
            {
              v72b = abs(v41->pFacePlane.vNormal.y * v0->vVelocity.y + v41->pFacePlane.vNormal.z * v0->vVelocity.z
                                                                    + v41->pFacePlane.vNormal.x * v0->vVelocity.x) >> 16;
              if ( (stru_721530.speed >> 3) > v72b )
                v72b = stru_721530.speed >> 3;

              v0->vVelocity.x += fixpoint_mul(v72b, v41->pFacePlane.vNormal.x);
              v0->vVelocity.y += fixpoint_mul(v72b, v41->pFacePlane.vNormal.y);
              v0->vVelocity.z += fixpoint_mul(v72b, v41->pFacePlane.vNormal.z);
              if ( v42 != 4 )
              {
                v45 = v0->vPosition.z;
                v46 = stru_721530.prolly_normal_d
                    - ((v41->pFacePlane.dist
                      + v41->pFacePlane.vNormal.x * v0->vPosition.x
                      + v41->pFacePlane.vNormal.y * v0->vPosition.y
                      + v41->pFacePlane.vNormal.z * v0->vPosition.z) >> 16);
                if ( v46 > 0 )
                {
                  v0->vPosition.x += (unsigned int)(v46 * v41->pFacePlane.vNormal.x) >> 16;
                  v0->vPosition.y += (unsigned int)(v46 * v41->pFacePlane.vNormal.y) >> 16;
                  v0->vPosition.z = v45 + ((unsigned int)(v46 * v41->pFacePlane.vNormal.z) >> 16);
                }
                v0->uYawAngle = stru_5C6E00->Atan2(v0->vVelocity.x, v0->vVelocity.y);
              }
            }
          }
          break;
      }

      v0->vVelocity.x = fixpoint_mul(58500, v0->vVelocity.x);
      v0->vVelocity.y = fixpoint_mul(58500, v0->vVelocity.y);
      v0->vVelocity.z = fixpoint_mul(58500, v0->vVelocity.z);

      ++v69;
      if ( v69 >= 100 )
        break;
      v26 = stru_721530.prolly_normal_d;
    }
    v58 = ((unsigned int)~pOutdoor->ActuallyGetSomeOtherTileInfo(WorldPosToGridCellX(v66), WorldPosToGridCellZ(v65) - 1) >> 1) & 1;
    v59 = ((unsigned int)~pOutdoor->ActuallyGetSomeOtherTileInfo(WorldPosToGridCellX(v0->vPosition.x), WorldPosToGridCellZ(v0->vPosition.y) - 1) >> 1) & 1;
    if ( WorldPosToGridCellX(v66) == WorldPosToGridCellX(v0->vPosition.x) 
		&& WorldPosToGridCellZ(v65) == WorldPosToGridCellZ(v0->vPosition.y)
		&& v58 
		|| v67 != 0 )
    {
      if ( MonsterStats::BelongsToSupertype(v0->pMonsterInfo.uID, MONSTER_SUPERTYPE_WATER_ELEMENTAL) )
      {
        v58 = v58 == 0;
        v59 = v59 == 0;
      }
      if ( !uIsFlying && v58 && !v59 )
      {
        v0->vPosition.x = v66;
        v0->vPosition.y = v65;
        if ( v0->CanAct() )
        {
          v0->uYawAngle -= 32;
          v0->uCurrentActionTime = 0;
          v0->uCurrentActionLength = 128;
          v0->uAIState = Fleeing;
        }
      }
    }
  }
}

//----- (0047253E) --------------------------------------------------------
void UpdateObjects()
{
  unsigned int v0; // ebx@0
  //unsigned int v1; // edi@1
  //char *v2; // esi@2
  //__int16 v3; // dx@5
  ObjectDesc *v4; // eax@5
  int v5; // ecx@6
  __int16 v6; // cx@7
  signed int v7; // eax@9
  __int16 v8; // cx@14
  __int16 v9; // dx@14
  unsigned int v10; // ecx@16
  signed int v11; // eax@17
  int v12; // edi@27
  int v13; // eax@27
  int v14; // ebx@27
  unsigned int v15; // ecx@27
  unsigned int v16; // edx@30
  unsigned int v17; // edx@32
  int v18; // [sp+4h] [bp-10h]@27
  int v19; // [sp+8h] [bp-Ch]@27
  //signed int v20; // [sp+10h] [bp-4h]@1

  //v1 = 0;
  //v20 = 0;
  for (uint i = 0; i < uNumSpriteObjects; ++i)
  {
    auto item = &pSpriteObjects[i];
    //v2 = (char *)&item->uSpriteFrameID;
    //do
    //{
      //LOWORD(v0) = item->uAttributes;
    if (item->uAttributes & OBJECT_40)
      item->uAttributes &= ~OBJECT_40;
    else
    {
              //v3 = item->uObjectDescID;
      v4 = &pObjectList->pObjects[item->uObjectDescID];
      if (item->AttachedToActor())
      {
          v5 = PID_ID(item->spell_target_pid);
		  item->vPosition.x = pActors[v5].vPosition.x;
          item->vPosition.y = pActors[v5].vPosition.y;
          item->vPosition.z = pActors[v5].vPosition.z + pActors[v5].uActorHeight;
		  if ( !item->uObjectDescID || (v6 = LOWORD(pEventTimer->uTimeElapsed) + item->uSpriteFrameID, item->uSpriteFrameID = v6, !(v4->uFlags & 4)) )
            continue;
          if ( v6 >= 0 )
          {
            v7 = v4->uLifetime;
            if (item->uAttributes & 2)
              v7 = item->field_20;
            if ( v6 < v7 )
              continue;
          }
            v10 = i;
            SpriteObject::OnInteraction(v10);
            continue;
      }

        if ( item->uObjectDescID )
        {
          v8 = LOWORD(pEventTimer->uTimeElapsed) + item->uSpriteFrameID;
          item->uSpriteFrameID = v8;
          v9 = v4->uFlags;
          if ( v9 & 4 )
		  {    
			  if ( v8 < 0 )
			  {
				v10 = i;
				SpriteObject::OnInteraction(v10);
				continue;
			  }
			  v11 = v4->uLifetime;
			  if (item->uAttributes & 2)
				v11 = item->field_20;
		  }
		  if ( !(v9 & 4) || v8 < v11 )
          {
            if ( uCurrentlyLoadedLevelType == LEVEL_Indoor )
              SpriteObject::UpdateObject_fn0_BLV(i);
            else
              SpriteObject::UpdateObject_fn0_ODM(i);
			if ( pParty->bTurnBasedModeOn != 1 || !(item->uSectorID & 4) )
              continue;
			v12 = abs(pParty->vPosition.x - item->vPosition.x);
			v18 = abs(pParty->vPosition.y - item->vPosition.y);
			v19 = abs(pParty->vPosition.z - item->vPosition.z);
            v13 = v12;
            v14 = v18;
            v15 = v19;
            if ( v12 < v18 )
            {
              v13 = v18;
              v14 = v12;
            }
            if ( v13 < v19 )
            {
              v16 = v13;
              v13 = v19;
              v15 = v16;
            }
            if ( v14 < (signed int)v15 )
            {
              v17 = v15;
              v15 = v14;
              v14 = v17;
            }
            v0 = (unsigned int)(11 * v14) >> 5;
            if ( (signed int)(v0 + (v15 >> 2) + v13) <= 5120 )
              continue;
            v10 = i;
            SpriteObject::OnInteraction(v10);
            continue;
          }
          v10 = i;
          if ( !(v9 & 0x40) )
		  {
            SpriteObject::OnInteraction(v10);
            continue;
		  }
          _46BFFA_check_object_intercept(i, PID(OBJECT_Item,i));
        }
    }
      //v2 += 112;
      //v1 = v20++ + 1;
    //}
    //while ( v20 < (signed int)uNumSpriteObjects );
  }
}

//----- (0047272C) --------------------------------------------------------
int collide_against_floor_approximate(int x, int y, int z, unsigned int *pSectorID, unsigned int *pFaceID)
{
  signed int v5; // ebx@1
  int result; // eax@1
  int v7; // [sp+10h] [bp-8h]@1
  signed int v8; // [sp+14h] [bp-4h]@1

  v5 = x - 2;
  v7 = x;
  v8 = y;
  *pSectorID = pIndoor->GetSector(x - 2, y, z + 40);
  result = collide_against_floor(v5, v8, z + 40, pSectorID, pFaceID);
  if ( result == -30000 || !*pSectorID )
  {
    *pSectorID = pIndoor->GetSector(v7 + 2, v8, z + 40);
    result = collide_against_floor(v7 + 2, v8, z + 40, pSectorID, pFaceID);
    if ( result == -30000 || !*pSectorID )
    {
      *pSectorID = pIndoor->GetSector(v7, v8 - 2, z + 40);
      result = collide_against_floor(v7, v8 - 2, z + 40, pSectorID, pFaceID);
      if ( result == -30000 || !*pSectorID )
      {
        *pSectorID = pIndoor->GetSector(v7, v8 + 2, z + 40);
        result = collide_against_floor(v7, v8 + 2, z + 40, pSectorID, pFaceID);
        if ( result == -30000 || !*pSectorID )
        {
          *pSectorID = pIndoor->GetSector(v7, v8, z + 140);
          result = collide_against_floor(v7, v8, z + 140, pSectorID, pFaceID);
        }
      }
    }
  }
  return result;
}

//----- (00472866) --------------------------------------------------------
void BLV_ProcessPartyActions()
{
  int v1; // ebx@1
  int v2; // edi@1
  //int v6; // eax@18
  //signed __int64 v8; // qax@27
  //int v9; // eax@27
  double v10; // st7@27
  unsigned int v12; // eax@49
  double v13; // st7@50
  //int v14; // eax@51
  //signed __int64 v15; // qax@53
  //double v16; // st7@54
  int v17; // eax@62
  double v18; // st7@62
  int v19; // ST40_4@62
  int v20; // eax@65
  double v21; // st7@65
  int v22; // ST40_4@65
  int v23; // eax@66
  double v24; // st7@66
  int v25; // ST40_4@66
  int v26; // eax@67
  double v27; // st7@67
  int v28; // ST40_4@67
  unsigned int v35; // eax@74
  int v36; // ecx@88
  int new_party_z; // esi@96
  int v38; // eax@96
  int v39; // ecx@106
  int v40; // eax@106
  Player **v41; // esi@113
  int v42; // eax@120
  signed int v43; // ecx@123
  BLVFace *v44; // esi@126
  PolygonType v45; // al@126
  int v46; // ecx@133
  char v47; // zf@133
  int v48; // eax@133
  int v49; // ST40_4@136
  int v50; // ST40_4@140
  int v51; // eax@140
  int v52; // eax@140
  signed int v53; // edi@146
  int v54; // ebx@146
  int v55; // ST30_4@146
  AudioPlayer *v56; // ecx@162
  SoundID v57; // [sp-20h] [bp-80h]@163
  signed int v58; // [sp-1Ch] [bp-7Ch]@161
  unsigned int v59; // [sp-18h] [bp-78h]@161
  signed int v60; // [sp-14h] [bp-74h]@161
  signed int v61; // [sp-10h] [bp-70h]@161
  int v62; // [sp-Ch] [bp-6Ch]@161
  int v63; // [sp-8h] [bp-68h]@75
  unsigned int v64; // [sp-8h] [bp-68h]@161
  int v65; // [sp-4h] [bp-64h]@75
  int v66; // [sp-4h] [bp-64h]@161
  //int v68; // [sp+10h] [bp-50h]@45
  int v69; // [sp+10h] [bp-50h]@140
  unsigned int uFaceEvent; // [sp+14h] [bp-4Ch]@1
  //signed int v71; // [sp+18h] [bp-48h]@1
  signed int v72; // [sp+1Ch] [bp-44h]@1
  signed int v73; // [sp+20h] [bp-40h]@100
  int v74; // [sp+20h] [bp-40h]@140
  bool bFeatherFall; // [sp+24h] [bp-3Ch]@15
  unsigned int uSectorID; // [sp+28h] [bp-38h]@1
  int v78; // [sp+2Ch] [bp-34h]@1
  unsigned int uFaceID; // [sp+30h] [bp-30h]@1
  int v80; // [sp+34h] [bp-2Ch]@1
  int v81; // [sp+38h] [bp-28h]@47
  int v82; // [sp+3Ch] [bp-24h]@47
  int _view_angle; // [sp+40h] [bp-20h]@47
  int bJumping; // [sp+44h] [bp-1Ch]@1
  int new_party_y; // [sp+48h] [bp-18h]@1
  int new_party_x; // [sp+4Ch] [bp-14h]@1
  int party_z; // [sp+50h] [bp-10h]@1
  //int v89; // [sp+58h] [bp-8h]@1
  int angle; // [sp+5Ch] [bp-4h]@47

  uFaceEvent = 0;
  //v89 = pParty->uFallSpeed;
  v1 = 0;
  v2 = 0;
  new_party_x = pParty->vPosition.x;
  new_party_y = pParty->vPosition.y;
  party_z = pParty->vPosition.z;
  uSectorID = pIndoor->GetSector(pParty->vPosition.x, pParty->vPosition.y, pParty->vPosition.z);
  v72 = 0;
  v78 = 0;
  bJumping = 0;

  uFaceID = -1;
  auto floor_level = collide_against_floor(new_party_x, new_party_y, party_z + 40, &uSectorID, &uFaceID);

  if ( pParty->bFlying )
  {
    pParty->bFlying = false;
    if (pParty->FlyActive())
      pOtherOverlayList->pOverlays[pParty->pPartyBuffs[PARTY_BUFF_FLY].uOverlayID - 1].field_E |= 1;
  }

  if ( floor_level == -30000  || uFaceID == -1)
  {
    floor_level = collide_against_floor_approximate(new_party_x, new_party_y, party_z + 40, &uSectorID, &uFaceID);
    if ( floor_level == -30000 || uFaceID == -1)
    {
      __debugbreak(); // level built with errors 
      pParty->vPosition.x = blv_prev_party_x;
      pParty->vPosition.y = blv_prev_party_z;
      pParty->vPosition.z = blv_prev_party_y;
      pParty->uFallStartY = blv_prev_party_y;
      return;
    }
  }

  blv_prev_party_x = pParty->vPosition.x;
  blv_prev_party_z = pParty->vPosition.y;
  blv_prev_party_y = pParty->vPosition.z;
  if (!pParty->bTurnBasedModeOn)
  {
    auto v67 = GetTickCount() / 500;
    if (dword_720CDC != v67 )
    {
      dword_4F8580[3 * dword_4F8580[1]] = pParty->vPosition.x;
      dword_4F8580[3 * dword_4F8580[2]] = pParty->vPosition.y;
      dword_4F8580[3 * dword_4F8580[3]] = pParty->vPosition.z;
      if ( dword_4F8580[0] > 60 )
        dword_4F8580[0] = 1;
    }
    dword_720CDC = v67;
  }

  uint fall_start;
  if (!pParty->FeatherFallActive())
  {
    bFeatherFall = false;
    if (!pParty->pPlayers[0].WearsItemAnyWhere(ITEM_ARTIFACT_LADYS_ESCORT) &&  // grants feather fall
        !pParty->pPlayers[1].WearsItemAnyWhere(ITEM_ARTIFACT_LADYS_ESCORT) &&
        !pParty->pPlayers[2].WearsItemAnyWhere(ITEM_ARTIFACT_LADYS_ESCORT) &&
        !pParty->pPlayers[3].WearsItemAnyWhere(ITEM_ARTIFACT_LADYS_ESCORT))
    {
      fall_start = pParty->uFallStartY;
    }
  }
  else
  {
    fall_start = floor_level;
    bFeatherFall = true;
    pParty->uFallStartY = floor_level;
  }


  if (fall_start - party_z > 512 && !bFeatherFall && party_z <= floor_level + 1)
  {
    assert(~pParty->uFlags & PARTY_FLAGS_1_LANDING); // why land in indoor?
    if (pParty->uFlags & PARTY_FLAGS_1_LANDING)
      pParty->uFlags &= ~PARTY_FLAGS_1_LANDING;
    else for (uint i = 0; i < 4; ++i)
    {                                      // receive falling damage
      auto player = &pParty->pPlayers[i];
      if (!player->HasEnchantedItemEquipped(72) && !player->WearsItem(ITEM_ARTIFACT_HERMES_SANDALS, EQUIP_BOOTS))
      {
        player->ReceiveDamage((pParty->uFallStartY - party_z) * (0.1f * player->GetMaxHealth()) / 256, DMGT_PHISYCAL);
        v10 = (double)(20 - player->GetParameterBonus(player->GetActualEndurance())) * flt_6BE3A4_debug_recmod1 * 2.133333333333333;
        player->SetRecoveryTime((signed __int64)v10);
      }
    }
  }

  if ( party_z > floor_level + 1 )
    bJumping = 1;

  bool jumping_up = false;

  if ( party_z - floor_level <= 32 )
  {
    pParty->uFallStartY = party_z;
    jumping_up = true;
  }

  if (bWalkSound && pParty->walk_sound_timer)
  {
    if (pParty->walk_sound_timer > pEventTimer->uTimeElapsed)
      pParty->walk_sound_timer -= pEventTimer->uTimeElapsed;
    else pParty->walk_sound_timer = 0;
  }


  if (party_z <= floor_level + 1)
  {
    party_z = floor_level + 1;
    pParty->uFallStartY = floor_level + 1;

    if (!bJumping && pParty->floor_face_pid != uFaceID)
    {
      auto pFace = &pIndoor->pFaces[uFaceID];
      if (pFace->uAttributes & FACE_PRESSURE_PLATE)
        uFaceEvent = pIndoor->pFaceExtras[pFace->uFaceExtraID].uEventID;
    }
  }
  if (!bJumping)
    pParty->floor_face_pid = uFaceID;

  bool on_water = false;
  if ( pIndoor->pFaces[uFaceID].Fluid())
    on_water = true;

  v81 = pParty->uWalkSpeed;
  angle = pParty->sRotationY;
  _view_angle = pParty->sRotationX;
  v82 = (unsigned __int64)(pEventTimer->dt_in_some_format * (signed __int64)((signed int)(pParty->y_rotation_speed * stru_5C6E00->uIntegerPi)
                                          / 180)) >> 16;
//LABEL_87:
  while ( pPartyActionQueue->uNumActions )
  {
    switch ( pPartyActionQueue->Next() )
    {
      case PARTY_TurnLeft:
        if (uTurnSpeed)
          angle = stru_5C6E00->uDoublePiMask & (angle + uTurnSpeed);
        else
          angle = stru_5C6E00->uDoublePiMask & (angle + (int)(v82 * fTurnSpeedMultiplier));
        break;
      case PARTY_TurnRight:
        if (uTurnSpeed)
          angle = stru_5C6E00->uDoublePiMask & (angle - uTurnSpeed);
        else
          angle = stru_5C6E00->uDoublePiMask & (angle - (int)(v82 * fTurnSpeedMultiplier));
        break;

      case PARTY_FastTurnLeft:
        if (uTurnSpeed)
          angle = stru_5C6E00->uDoublePiMask & (angle + uTurnSpeed);
        else
          angle = stru_5C6E00->uDoublePiMask & (angle + (int)(2.0f * fTurnSpeedMultiplier * (double)v82));
        break;

      case PARTY_FastTurnRight:
        if (uTurnSpeed)
          angle = stru_5C6E00->uDoublePiMask & (angle - uTurnSpeed);
        else
          angle = stru_5C6E00->uDoublePiMask & (angle - (int)(2.0f * fTurnSpeedMultiplier * (double)v82));
        break;

      case PARTY_StrafeLeft:
        v2 -= fixpoint_mul(stru_5C6E00->Sin(angle), v81 * fWalkSpeedMultiplier / 2);
        v1 += fixpoint_mul(stru_5C6E00->Cos(angle), v81 * fWalkSpeedMultiplier / 2);
        v78 = 1;
        break;
      case PARTY_StrafeRight:
        v2 += fixpoint_mul(stru_5C6E00->Sin(angle), v81 * fWalkSpeedMultiplier / 2);
        v1 -= fixpoint_mul(stru_5C6E00->Cos(angle), v81 * fWalkSpeedMultiplier / 2);
        v78 = 1;
        break;
      case PARTY_WalkForward:
        v2 += fixpoint_mul(stru_5C6E00->Cos(angle), 5 * v81 * fWalkSpeedMultiplier);
        v1 += fixpoint_mul(stru_5C6E00->Sin(angle), 5 * v81 * fWalkSpeedMultiplier);
        v78 = 1;
        break;
      case PARTY_WalkBackward:
        v2 -= fixpoint_mul(stru_5C6E00->Cos(angle), v81 * fBackwardWalkSpeedMultiplier);
        v1 -= fixpoint_mul(stru_5C6E00->Sin(angle), v81 * fBackwardWalkSpeedMultiplier);
        v78 = 1;
        break;
      case PARTY_RunForward:
        v2 += fixpoint_mul(stru_5C6E00->Cos(angle), 2 * v81 * fWalkSpeedMultiplier);
        v1 += fixpoint_mul(stru_5C6E00->Sin(angle), 2 * v81 * fWalkSpeedMultiplier);
        v72 = 1;
        break;
      case PARTY_RunBackward:
        //v32 = stru_5C6E00->SinCos(angle);
        //v33 = (double)v81;
        //v88 = (double)v81;
        v2 -= fixpoint_mul(stru_5C6E00->Cos(angle), v81 * fBackwardWalkSpeedMultiplier);
        //v34 = stru_5C6E00->SinCos(angle - stru_5C6E00->uIntegerHalfPi);
        v1 -= fixpoint_mul(stru_5C6E00->Sin(angle), v81 * fBackwardWalkSpeedMultiplier);
        v72 = 1;
        break;
      case PARTY_LookUp:
        _view_angle += (signed __int64)(flt_6BE150_look_up_down_dangle * 25.0);
        if ( _view_angle > 128 )
          _view_angle = 128;
        v35 = uActiveCharacter;
        if ( uActiveCharacter )
          pPlayers[v35]->PlaySound((PlayerSpeech)SPEECH_63, 0);
        break;
      case PARTY_LookDown:
        _view_angle += (signed __int64)(flt_6BE150_look_up_down_dangle * -25.0);
        if ( _view_angle < -128 )
          _view_angle = -128;
        v35 = uActiveCharacter;
        if ( uActiveCharacter )
          pPlayers[v35]->PlaySound((PlayerSpeech)SPEECH_64, 0);
        break;
      case PARTY_CenterView:
        _view_angle = 0;
        break;
      case PARTY_Jump:
        if ( (!bJumping || party_z <= floor_level + 6 && pParty->uFallSpeed <= 0) && pParty->field_24 )
        {
          bJumping = 1;
          pParty->uFallSpeed = (signed __int64)((double)(pParty->field_24 << 6) * 1.5 + (double)pParty->uFallSpeed);
        }
        break;
      default:
        break;
    }
  }
  v36 = 0;
  pParty->sRotationY = angle;
  pParty->sRotationX = _view_angle;
  if ( bJumping )
  {
	pParty->uFallSpeed += -2 * pEventTimer->uTimeElapsed * GetGravityStrength();
	if ( bJumping != v36 && pParty->uFallSpeed <= v36 )
	{
		if ( pParty->uFallSpeed < -500 && !pParty->bFlying )
		{
			v41 = &pPlayers[1];
			do
			{
				if ( !(*v41)->HasEnchantedItemEquipped(72) && !(*v41)->WearsItem(ITEM_ARTIFACT_HERMES_SANDALS, EQUIP_BOOTS) ) //was 8 
					(*v41)->PlayEmotion(CHARACTER_EXPRESSION_SCARED, 0);
				++v41;
			}
			while ( (signed int)v41 <= (signed int)&pPlayers[4] );
		}
	}
	else
		pParty->uFallStartY = party_z;
  }
  else
  {
    if ( pIndoor->pFaces[uFaceID].pFacePlane_old.vNormal.z < 32768 )
    {
      pParty->uFallSpeed -= pEventTimer->uTimeElapsed * GetGravityStrength();
      pParty->uFallStartY = party_z;
    }
	else
	{
		if (! (pParty->uFlags & PARTY_FLAGS_1_LANDING) )
		  pParty->uFallSpeed = 0;
		pParty->uFallStartY = party_z;
	}
  }
  if ( v2 * v2 + v1 * v1 < 400 )
  {
    v1 = 0;
    v2 = 0;
  }
  stru_721530.field_84 = -1;
  stru_721530.field_70 = 0;
  stru_721530.prolly_normal_d = pParty->field_14_radius;
  stru_721530.field_8_radius = pParty->field_14_radius / 2;
  auto v83 = 0;
  stru_721530.field_0 = 1;
  stru_721530.height = pParty->uPartyHeight - 32;
  while ( 1 )
  {
    new_party_z = party_z;
    stru_721530.position.x = new_party_x;
    stru_721530.normal.x = new_party_x;
    stru_721530.velocity.x = v2;
    stru_721530.position.y = new_party_y;
    stru_721530.normal.y = new_party_y;
    stru_721530.velocity.y = v1;
    stru_721530.normal.z = stru_721530.prolly_normal_d + party_z + 1;
    stru_721530.position.z = stru_721530.height + party_z + 1;
    stru_721530.velocity.z = pParty->uFallSpeed;
    stru_721530.uSectorID = uSectorID;
    v38 = 0;
    if ( pParty->bTurnBasedModeOn == 1 && pTurnEngine->turn_stage == 3 )
      v38 = 13312;
    if ( stru_721530._47050A(v38) )
      break;
    v73 = 0;
    do
    {
      _46E44E_collide_against_faces_and_portals(1u);
      _46E0B2_collide_against_decorations();
      for ( v80 = 0; v80 < (signed int)uNumActors; ++v80 )
        Actor::_46DF1A_collide_against_actor(v80, 0);
      if ( _46F04E_collide_against_portals() )
        break;
      ++v73;
    }
    while ( v73 < 100 );
    if ( stru_721530.field_7C >= stru_721530.field_6C )
    {
      v39 = stru_721530.normal2.x;
      uSectorID = stru_721530.normal2.y;
      v40 = stru_721530.normal2.z - stru_721530.prolly_normal_d - 1;
    }
    else
    {
      v39 = ((unsigned __int64)(stru_721530.field_7C * (signed __int64)stru_721530.direction.x) >> 16) + new_party_x;
      uSectorID = new_party_y + ((unsigned __int64)(stru_721530.field_7C * (signed __int64)stru_721530.direction.y) >> 16);
      v40 = new_party_z + ((unsigned __int64)(stru_721530.field_7C * (signed __int64)stru_721530.direction.z) >> 16);
    }
    v42 = collide_against_floor(v39, uSectorID, v40 + 40, &stru_721530.uSectorID, &uFaceID);
    if ( v42 == -30000 || v42 - new_party_z > 128 )
      return;
    if ( stru_721530.field_7C >= stru_721530.field_6C )
    {
      new_party_x = stru_721530.normal2.x;
      new_party_y = stru_721530.normal2.y;
      new_party_z = stru_721530.normal2.z - stru_721530.prolly_normal_d - 1;
      break;
    }
    new_party_x += (unsigned __int64)(stru_721530.field_7C * (signed __int64)stru_721530.direction.x) >> 16;
    new_party_y += (unsigned __int64)(stru_721530.field_7C * (signed __int64)stru_721530.direction.y) >> 16;
    v43 = stru_721530.uFaceID;
    uSectorID = stru_721530.uSectorID;
    stru_721530.field_70 += stru_721530.field_7C;
    auto v87 = ((unsigned __int64)(stru_721530.field_7C * (signed __int64)stru_721530.direction.z) >> 16) + new_party_z;
    if ( PID_TYPE(stru_721530.uFaceID) == OBJECT_Actor)
    {
      if ( SHIDWORD(pParty->pPartyBuffs[PARTY_BUFF_INVISIBILITY].uExpireTime) >= 0
        && (SHIDWORD(pParty->pPartyBuffs[PARTY_BUFF_INVISIBILITY].uExpireTime) > 0 || LODWORD(pParty->pPartyBuffs[PARTY_BUFF_INVISIBILITY].uExpireTime)) )
        pParty->pPartyBuffs[PARTY_BUFF_INVISIBILITY].Reset();
      viewparams->bRedrawGameUI = 1;
    }
	else if ( PID_TYPE(stru_721530.uFaceID) == OBJECT_Decoration)
    {
      v53 = integer_sqrt(v2 * v2 + v1 * v1);
      v80 = v53;
      v54 = stru_5C6E00->Atan2(new_party_x - pLevelDecorations[stru_721530.uFaceID >> 3].vPosition.x,
              new_party_y - pLevelDecorations[stru_721530.uFaceID >> 3].vPosition.y);
      v2 = (unsigned __int64)(stru_5C6E00->Cos(v54) * (signed __int64)v53) >> 16;
      v55 = stru_5C6E00->Sin(v54);
      v1 = (unsigned __int64)(v55 * (signed __int64)v80) >> 16;
    }
    else
    {
      if ( PID_TYPE(stru_721530.uFaceID) == OBJECT_BModel)
      {
        v44 = &pIndoor->pFaces[(signed int)stru_721530.uFaceID >> 3];
        v45 = v44->uPolygonType;
        if ( v45 == 3 )
        {
          if ( pParty->uFallSpeed < 0 )
            pParty->uFallSpeed = 0;
          v87 = pIndoor->pVertices[*v44->pVertexIDs].z + 1;
          if ( pParty->uFallStartY - v87 < 512 )
            pParty->uFallStartY = v87;
          if ( v2 * v2 + v1 * v1 < 400 )
          {
            v1 = 0;
            v2 = 0;
          }
          if ( pParty->floor_face_pid != PID_ID(v43) && BYTE3(v44->uAttributes) & 4 )
            uFaceEvent = pIndoor->pFaceExtras[v44->uFaceExtraID].uEventID;
        }
		else
		{
			v46 = pParty->uFallSpeed * v44->pFacePlane_old.vNormal.z;
			v47 = v45 == 4;
			v48 = v44->pFacePlane_old.vNormal.x;
			if ( !v47 )
			{
			  v80 = abs(v1 * v44->pFacePlane_old.vNormal.y + v46 + v2 * v48) >> 16;
			  if ((stru_721530.speed >> 3) > v80 )
				v80 = stru_721530.speed >> 3;
			  v50 = (unsigned __int64)(v80 * (signed __int64)v44->pFacePlane_old.vNormal.x) >> 16;
			  v81 = v44->pFacePlane_old.vNormal.y;
			  v81 = (unsigned __int64)(v80 * (signed __int64)v81) >> 16;
			  v82 = v44->pFacePlane_old.vNormal.z;
			  v82 = (unsigned __int64)(v80 * (signed __int64)v82) >> 16;
			  v2 += v50;
			  pParty->uFallSpeed += v82;
			  v74 = v44->pFacePlane_old.vNormal.z;
			  v51 = v44->pFacePlane_old.vNormal.y;
			  v69 = v44->pFacePlane_old.vNormal.x;
			  v80 = v51;
			  v1 += v81;
			  v52 = stru_721530.prolly_normal_d - ((v44->pFacePlane_old.dist + v87 * v74 + new_party_y * v51 + new_party_x * v69) >> 16);
			  if ( v52 > 0 )
			  {
				new_party_x += v52 * v69 >> 16;
				new_party_y += v52 * v80 >> 16;
				v87 += v52 * v74 >> 16;
			  }
			  v43 = stru_721530.uFaceID;
			  if ( pParty->floor_face_pid != PID_ID(v43) && BYTE3(v44->uAttributes) & 4 )
				uFaceEvent = pIndoor->pFaceExtras[v44->uFaceExtraID].uEventID;
			}
			else
			{
				v80 = abs(v1 * v44->pFacePlane_old.vNormal.y + v46 + v2 * v48) >> 16;
				if ((stru_721530.speed >> 3) > v80 )
				  v80 = stru_721530.speed >> 3;
				v49 = (unsigned __int64)(v80 * (signed __int64)v44->pFacePlane_old.vNormal.x) >> 16;
				v81 = v44->pFacePlane_old.vNormal.y;
				v81 = (unsigned __int64)(v80 * (signed __int64)v81) >> 16;
				v82 = v44->pFacePlane_old.vNormal.z;
				v82 = (unsigned __int64)(v80 * (signed __int64)v82) >> 16;
				v2 += v49;
				v1 += v81;
				pParty->uFallSpeed += v82;
				if ( v2 * v2 + v1 * v1 >= 400 )
				{
				  v43 = stru_721530.uFaceID;
				  if ( pParty->floor_face_pid != PID_ID(v43) && BYTE3(v44->uAttributes) & 4 )
					uFaceEvent = pIndoor->pFaceExtras[v44->uFaceExtraID].uEventID;
				}
				else
				{
					v2 = 0;
					v1 = 0;
					pParty->uFallSpeed = 0;
				}
			}
		}
      }
    }
    v2 = (unsigned __int64)(58500i64 * v2) >> 16;
    v1 = (unsigned __int64)(58500i64 * v1) >> 16;
    ++v83;
    pParty->uFallSpeed = (unsigned __int64)(58500i64 * pParty->uFallSpeed) >> 16;
    if ( v83 >= 100 )
    {
      new_party_z = v87;
      break;
    }
  }
  if ( bWalkSound && !pParty->walk_sound_timer)
  {
    if ( integer_sqrt((pParty->vPosition.x - new_party_x) * (pParty->vPosition.x - new_party_x) + (pParty->vPosition.y - new_party_y)
         * (pParty->vPosition.y - new_party_y) + (pParty->vPosition.z - new_party_z)
         * (pParty->vPosition.z - new_party_z)) <= 16 )
	{
      pAudioPlayer->_4AA258(804);
      pParty->walk_sound_timer = 64;
	}
    else if ( v72 && (!bJumping || jumping_up) )
    {
      v66 = 0;
      v64 = 0;
      v62 = 0;
      v61 = 0;
      v60 = -1;
      v59 = 1;
      v58 = 804;
      if ( !on_water )
      {
        v56 = pAudioPlayer;
        if ( BYTE2(pIndoor->pFaces[uFaceID].uAttributes) & 0x20 )
          v57 = (SoundID)50;
        else
          v57 = (SoundID)64;
        pAudioPlayer->PlaySound(v57, v58, v59, v60, v61, v62, v64, v66);
      }
	  else
	  {
		  v57 = (SoundID)63;
		  v56 = pAudioPlayer;
		  pAudioPlayer->PlaySound(v57, v58, v59, v60, v61, v62, v64, v66);
	  }
    }
    else if ( v78 && (!bJumping || jumping_up) )
    {
      v66 = 0;
      v64 = 0;
      v62 = 0;
      v61 = 0;
      v60 = -1;
      v59 = 1;
      v58 = 804;
      if ( on_water )
      {
        v57 = (SoundID)102;
        v56 = pAudioPlayer;
      }
	  else
	  {
		  v56 = pAudioPlayer;
		  if ( BYTE2(pIndoor->pFaces[uFaceID].uAttributes) & 0x20 )
			v57 = (SoundID)89;
		  else
			v57 = (SoundID)103;
	  }
      pAudioPlayer->PlaySound(v57, v58, v59, v60, v61, v62, v64, v66);
    }
    else
    {
      pAudioPlayer->_4AA258(804);
      pParty->walk_sound_timer = 64;
    }
  }
  if ( !bJumping || jumping_up )
    pParty->uFlags &= ~PARTY_FLAGS_1_FALLING;
  else
    pParty->uFlags |= PARTY_FLAGS_1_FALLING;
  pParty->uFlags &= ~0x200;
  pParty->vPosition.x = new_party_x;
  pParty->vPosition.z = new_party_z;
  pParty->vPosition.y = new_party_y;
  //pParty->uFallSpeed = v89;
  if ( !bJumping && BYTE3(pIndoor->pFaces[uFaceID].uAttributes) & 0x40 )
    pParty->uFlags |= 0x200;
  if (uFaceEvent)
    EventProcessor(uFaceEvent, 0, 1);
}

//----- (00473893) --------------------------------------------------------
void ODM_ProcessPartyActions()
{
  int v1; // edi@1
  int v2; // ebx@1
  int v3; // eax@14
  int v6; // esi@45
  ODMFace *v7; // ecx@45
  signed int v33; // eax@143
  int v34; // esi@143
  int v35; // esi@147
  int v36; // eax@155
  signed int v37; // esi@159
  signed int v38; // eax@159
  signed int i; // esi@159
  int v40; // esi@162
  bool v42; // eax@180
  signed int v43; // ecx@184
  signed int v44; // edx@184
  int v45; // ecx@200
  BSPModel *pModel; // eax@203
  ODMFace *pODMFace; // esi@203
  int v48; // eax@203
  char v49; // zf@203
  char v50; // sf@203
  unsigned __int8 v51; // of@203
  int v52; // eax@203
  BSPModel *v54; // eax@215
  int v55; // eax@217
  signed int v56; // ebx@228
  int v57; // eax@228
  BSPModel *v58; // eax@228
  unsigned __int64 v59; // qax@228
  BSPModel *v60; // eax@228
  unsigned __int64 v61; // qax@228
  int v62; // eax@241
  unsigned int v65; // ebx@263
  unsigned int v66; // esi@263
  int v67; // eax@263
  signed int v68; // ecx@263
  int v69; // eax@263
  int v70; // ebx@271
  int v71; // esi@271
  int v72; // edi@271
  int v73; // eax@271
  unsigned int v76; // edi@293
  bool v77; // edx@297
  bool v78; // ecx@303
  int v79; // ecx@314
  __int16 v80; // dx@317
  int v81; // ebx@318
  int v82; // ecx@318
  int pTerrainHeight; // eax@321
  int v86; // [sp-20h] [bp-B4h]@246
  int v87; // [sp-20h] [bp-B4h]@248
  signed int v88; // [sp-1Ch] [bp-B0h]@246
  unsigned int v89; // [sp-18h] [bp-ACh]@246
  signed int v90; // [sp-14h] [bp-A8h]@246
  signed int v91; // [sp-10h] [bp-A4h]@246
  int v92; // [sp-Ch] [bp-A0h]@246
  unsigned int v94; // [sp-8h] [bp-9Ch]@246
  int v96; // [sp-4h] [bp-98h]@246
  int v97; // [sp+Ch] [bp-88h]@180
  Vec3_int_ v98;
  bool v101; // [sp+1Ch] [bp-78h]@33
  int v102; // [sp+20h] [bp-74h]@1
  int v103; // [sp+24h] [bp-70h]@1
  int bFeatherFall; // [sp+28h] [bp-6Ch]@4
  int v105; // [sp+2Ch] [bp-68h]@24
  int bWaterWalk; // [sp+30h] [bp-64h]@1
  int v109; // [sp+3Ch] [bp-58h]@28
  int v110; // [sp+40h] [bp-54h]@180
  int v111; // [sp+44h] [bp-50h]@14
  int bJumping; // [sp+48h] [bp-4Ch]@1
  int v113; // [sp+4Ch] [bp-48h]@1
  unsigned int v114; // [sp+50h] [bp-44h]@1
  int _walk_speed; // [sp+54h] [bp-40h]@48
  int pX; // [sp+58h] [bp-3Ch]@1
  int pY; // [sp+5Ch] [bp-38h]@1
  int v118; // [sp+60h] [bp-34h]@1
  int _angle_x; // [sp+68h] [bp-2Ch]@48
  unsigned int v122; // [sp+70h] [bp-24h]@180
  int pZ; // [sp+74h] [bp-20h]@1
  int v124; // [sp+78h] [bp-1Ch]@1
  int _angle_y; // [sp+7Ch] [bp-18h]@48
  int v126; // [sp+80h] [bp-14h]@48
  int v128; // [sp+88h] [bp-Ch]@1
  int v129; // [sp+8Ch] [bp-8h]@92

  pZ = pParty->vPosition.z;
  v1 = 0;
  v103 = 0;
  v2 = 0;
  //*(float *)&v128 = 0.0;
  v128 = 0;
  v129 = 0;
  pX = pParty->vPosition.x;
  pY = pParty->vPosition.y;
  v113 = pParty->field_6F0;
  bJumping = 0;
  auto partyAtHighSlope = IsTerrainSlopeTooHigh(pParty->vPosition.x, pParty->vPosition.y);
  v114 = 0;
  v124 = 0;
  v102 = 0;
  pModel = 0;
  bWaterWalk = 0;
  if (!pParty->FeatherFallActive())
  {
    bFeatherFall = 0;
    for (int i = 0; i < 4; ++i)
      if (pParty->pPlayers[i].WearsItemAnyWhere(ITEM_ARTIFACT_LADYS_ESCORT))  // seems like flying boots
      {
        bFeatherFall = 1;
        break;
      }
  }
  else
  {
	bFeatherFall = 1;
  }
//LABEL_9:
  pParty->uFlags &= ~PARTY_FLAGS_1_STANDING_ON_WATER;
  if (pParty->WaterWalkActive())
  {
    //LOBYTE(pParty->uFlags) &= 0x7Fu;
    bWaterWalk = 1;
    *(short *)&stru_5E4C90_MapPersistVars._decor_events[20 * pParty->pPartyBuffs[PARTY_BUFF_WATER_WALK].uOverlayID + 119] |= 1u;
    if (!(pParty->pPartyBuffs[PARTY_BUFF_WATER_WALK].uFlags & 1) &&
		pParty->pPlayers[pParty->pPartyBuffs[PARTY_BUFF_WATER_WALK].uCaster - 1].sMana <= 0 )
      bWaterWalk = 0;
  }
  int bmodel_standing_on_pid;
  int is_on_water = false;
  v3 = ODM_GetFloorLevel(pX, pY, pZ, pParty->uPartyHeight, &is_on_water, &bmodel_standing_on_pid, bWaterWalk);
  int is_not_on_bmodel = bmodel_standing_on_pid == 0;

  v111 = v3;
  if ( bFeatherFall )
    pParty->uFallStartY = v3;
  else
    v3 = pParty->uFallStartY;
  if ( v3 - pZ > 512 && !bFeatherFall && pZ <= v111 + 1 )
  {
    if (pParty->uFlags & PARTY_FLAGS_1_LANDING)
    {
      pParty->uFlags &= ~PARTY_FLAGS_1_LANDING;
    }
    else for (int _i = 0; _i < 4; ++_i)     // receive falling damage
    {
      auto player = &pParty->pPlayers[_i];

      if ( !player->HasEnchantedItemEquipped(72) && !player->WearsItem(ITEM_ARTIFACT_HERMES_SANDALS, EQUIP_BOOTS) )
      {
        player->ReceiveDamage(
            (signed int)((pParty->uFallStartY - pZ) * (unsigned __int64)(player->GetMaxHealth() / 10)) / 256,
            DMGT_PHISYCAL);
        v105 = 20 - player->GetParameterBonus(player->GetActualEndurance());
        player->SetRecoveryTime((signed __int64)((double)v105 * flt_6BE3A4_debug_recmod1 * 2.133333333333333));
      }
      //}
      //while ( (signed int)v4 <= (signed int)&pPlayers[4] );
    }
  }
  v109 = -1;
  if ( pParty->bFlying )
    v109 = sub_46D8E3(pX, pY, pZ + pParty->uPartyHeight, (int)&v102);
  //v107 = bmodel_standing_on_pid == 0;
  v105 = v111 + 1;
  if ( pZ <= v111 + 1 )
  {
    v109 = -1;
    pParty->bFlying = false;
  }
  else
  {
    bJumping = 1;
  }
  v101 = pZ - v111 <= 32;
  if ( bWalkSound && pParty->walk_sound_timer)
  {
    if (pParty->walk_sound_timer >= pEventTimer->uTimeElapsed)
      pParty->walk_sound_timer -= pEventTimer->uTimeElapsed;
    else pParty->walk_sound_timer = 0;
  }
  if (!bUnderwater && pParty->pPartyBuffs[PARTY_BUFF_FLY].uExpireTime <= 0)
    pParty->bFlying = false;
  if (!bJumping)
  {
    if ( pParty->floor_face_pid != PID(OBJECT_BModel, bmodel_standing_on_pid) )
    {
      if (bmodel_standing_on_pid)
      {
        if ( (bmodel_standing_on_pid >> 6) < pOutdoor->uNumBModels )
        {
          v7 = pOutdoor->pBModels[bmodel_standing_on_pid >> 6].pFaces;
          v6 = bmodel_standing_on_pid & 0x3F;
          /*if ( *(char *)(v7->pFacePlane.vNormal.x + 308 * v6 + 31) & 4 )
          {
            pParty->field_6F4_packedid = PID(OBJECT_BModel,v108);
            v103 = *(short *)(v7->pFacePlane.vNormal.x + 308 * v6 + 292);
          }*/
		  if ( BYTE3(v7[v6].uAttributes) & 4 )
          {
            pParty->floor_face_pid = PID(OBJECT_BModel, bmodel_standing_on_pid);
            v103 = v7[v6].sCogTriggeredID;
          }
        }
      }
    }
    pParty->floor_face_pid = PID(OBJECT_BModel, bmodel_standing_on_pid);
  }
  _walk_speed = pParty->uWalkSpeed;
  _angle_y = pParty->sRotationY;
  _angle_x = pParty->sRotationX;
  v126 = pEventTimer->dt_in_some_format;
  /*v119 = (Player **)((unsigned __int64)(pEventTimer->dt_in_some_format
                                      * (signed __int64)((signed int)(pParty->field_20_prolly_turn_speed
                                                                    * stru_5C6E00->uIntegerPi)
                                                       / 180)) >> 16);*/
  __int64 dturn = (unsigned __int64)(pEventTimer->dt_in_some_format * (signed __int64)((signed int)(pParty->y_rotation_speed * stru_5C6E00->uIntegerPi) / 180)) >> 16;
  while (pPartyActionQueue->uNumActions)
  {
    switch (pPartyActionQueue->Next())
    {
      case PARTY_FlyUp:
      {
        if (!pParty->FlyActive() && !bUnderwater)
          break;

        pParty->bFlying = false;
        if (bUnderwater ||
            pParty->pPartyBuffs[PARTY_BUFF_FLY].uFlags & 1 ||
            pParty->pPlayers[pParty->pPartyBuffs[PARTY_BUFF_FLY].uCaster - 1].sMana > 0 )
          {
            if ( pParty->vPosition.z < 4000 || bJumping )
            {
              pZ += 30;
              v113 += 30;
              pParty->bFlying = 1;
              if ( pZ > 4000 )
              {
                pZ = 4000;
                v113 = 4000;
              }
              v1 = 0;
              v2 = 0;
              pParty->uFallSpeed = 0;
              *(float *)&v128 = 0.0;
              if ( v102 && pZ < v109 && (signed int)(pParty->uPartyHeight + pZ) >= v109 )
              {
                pParty->field_6E0 = 0;
                pParty->field_6E4 = 0;
                pPartyActionQueue->uNumActions = 0;
                pParty->uFlags |= PARTY_FLAGS_1_LANDING;
                pParty->vPosition.z = v109 - pParty->uPartyHeight - 31;
                pParty->field_6F0 = pZ;
                pParty->bFlying = 0;
                pZ = v109 - pParty->uPartyHeight - 31;
                v113 = pParty->field_6F0;
              }
              pParty->uFallSpeed = 0;
              pModel = (BSPModel *)1;
            }
          }
      }
      break;

      case PARTY_FlyDown:
        if (pParty->FlyActive() || bUnderwater)
        {
          pParty->bFlying = 0;
          if ( bUnderwater
            || pParty->pPartyBuffs[PARTY_BUFF_FLY].uFlags & 1
            || pParty->pPlayers[pParty->pPartyBuffs[PARTY_BUFF_FLY].uCaster - 1].sMana > 0 )//*(int *)&pParty->pArtifactsFound[6972 * pParty->pPartyBuffs[PARTY_BUFF_FLY].uCaster + 10] > 0 )
          {
            pZ -= 30;
            v113 -= 30;
            pParty->uFallSpeed = 0;
            //pParty->uFallSpeed = 0;
            pParty->bFlying = 1;
            pModel = (BSPModel *)1;
            if ( pZ <= v111 )
            {
              pParty->bFlying = 0;
              pPartyActionQueue->uNumActions = 0;
            }
          }
        }
        break;

      case PARTY_TurnLeft:
        if (uTurnSpeed)
          _angle_y += uTurnSpeed;   //descrete turn
        else
          _angle_y += dturn * fTurnSpeedMultiplier;  // time-based smooth turn

        _angle_y &= stru_5C6E00->uDoublePiMask;
      break;

      case PARTY_TurnRight:
        if (uTurnSpeed)
          _angle_y -= uTurnSpeed;
        else
          _angle_y -= dturn * fTurnSpeedMultiplier;

        _angle_y &= stru_5C6E00->uDoublePiMask;
      break;

      case PARTY_FastTurnLeft:
        if (uTurnSpeed)
          _angle_y += uTurnSpeed;
        else
          _angle_y += 2.0f * fTurnSpeedMultiplier * (double)dturn;

        _angle_y &= stru_5C6E00->uDoublePiMask;
      break;

      case PARTY_FastTurnRight:
        if (!uTurnSpeed)
          _angle_y -= 2.0f * fTurnSpeedMultiplier * (double)dturn;
        else
          _angle_y -= uTurnSpeed;

        _angle_y &= stru_5C6E00->uDoublePiMask;
      break;

      case PARTY_StrafeLeft:
      {
        *(float *)&v128 = pParty->uWalkSpeed;

        float sin_y = sinf(2 * 3.141592653589 * _angle_y / 2048.0);
        int dx = sin_y * pParty->uWalkSpeed * fWalkSpeedMultiplier;
        v2 -= 3 * dx / 4;
        
        float cos_y = cosf(2 * 3.141592653589 * _angle_y / 2048.0);
        int dy = cos_y * pParty->uWalkSpeed * fWalkSpeedMultiplier;
        v1 += 3 * dy / 4;

        v128 = v1;
        v124 = 1;
      }
      break;

      case PARTY_StrafeRight:
      {
        *(float *)&v128 = pParty->uWalkSpeed;

        float sin_y = sinf(2 * 3.141592653589 * _angle_y / 2048.0);
        int dx = sin_y * pParty->uWalkSpeed * fWalkSpeedMultiplier;
        v2 += 3 * dx / 4;
        
        float cos_y = cosf(2 * 3.141592653589 * _angle_y / 2048.0);
        int dy = cos_y * pParty->uWalkSpeed * fWalkSpeedMultiplier;
        v1 -= 3 * dy / 4;

        v128 = v1;
        v124 = 1;
      }
      break;

      case PARTY_WalkForward:
      {
        *(float *)&v128 = _walk_speed;

        float sin_y = sinf(2 * 3.141592653589 * _angle_y / 2048.0),
              cos_y = cosf(2 * 3.141592653589 * _angle_y / 2048.0);

        int dx = cos_y * pParty->uWalkSpeed * fWalkSpeedMultiplier;
        v2 += dx * 12;
        
        int dy = sin_y * pParty->uWalkSpeed * fWalkSpeedMultiplier;
        v1 += dy * 12;

        v128 = v1;
        v124 = 1;
      }
      break;

      case PARTY_RunForward:
      {
        *(float *)&v128 = _walk_speed;

        float sin_y = sinf(2 * 3.141592653589 * _angle_y / 2048.0),
              cos_y = cosf(2 * 3.141592653589 * _angle_y / 2048.0);

        int dx = cos_y * pParty->uWalkSpeed * fWalkSpeedMultiplier;
        int dy = sin_y * pParty->uWalkSpeed * fWalkSpeedMultiplier;

        if (pParty->bFlying)
        {
          v2 += 4 * dx;
          v1 += 4 * dy;

          v128 = v1;
        }
        else if (partyAtHighSlope && !bmodel_standing_on_pid)
        {
          v2 += dx;
          v1 += dy;

          v128 = v1;
          v124 = 1;
        }
        else
        {
          v2 += 2 * dx;
          v1 += 2 * dy;
          
          v128 = v1;
          v114 = 1;
        }
      }
      break;


      case PARTY_WalkBackward:
      {
        *(float *)&v128 = _walk_speed;

        float sin_y = sinf(2 * 3.141592653589 * _angle_y / 2048.0),
              cos_y = cosf(2 * 3.141592653589 * _angle_y / 2048.0);

        int dx = cos_y * pParty->uWalkSpeed * fBackwardWalkSpeedMultiplier;
        v2 -= dx;
        
        int dy = sin_y * pParty->uWalkSpeed * fBackwardWalkSpeedMultiplier;
        v1 -= dy;

        v128 = v1;
        v124 = 1;
      }
      break;


      case PARTY_RunBackward:
      {
        float sin_y = sinf(2 * 3.141592653589 * _angle_y / 2048.0),
              cos_y = cosf(2 * 3.141592653589 * _angle_y / 2048.0);

        int dx = cos_y * pParty->uWalkSpeed * fBackwardWalkSpeedMultiplier;        
        int dy = sin_y * pParty->uWalkSpeed * fBackwardWalkSpeedMultiplier;

        if (pParty->bFlying)
        {
          v2 -= 4 * dx;
          v1 -= 4 * dy;
          v128 = v1;
        }
        else
        {
          v2 -= dx;
          v1 -= dy;

          v128 = v1;
          v124 = 1;
        }
      }
      break;

      case PARTY_CenterView:
        _angle_x = 0;
      break;

      case PARTY_LookUp:
        _angle_x += (signed __int64)(flt_6BE150_look_up_down_dangle * 25.0);
        if ( _angle_x > 128 )
          _angle_x = 128;
        if (uActiveCharacter)
          pPlayers[uActiveCharacter]->PlaySound(SPEECH_63, 0);
      break;

      case PARTY_LookDown:
        _angle_x += (signed __int64)(flt_6BE150_look_up_down_dangle * -25.0);
        if ( _angle_x < -128 )
          _angle_x = -128;
        if (uActiveCharacter)
          pPlayers[uActiveCharacter]->PlaySound(SPEECH_64, 0);
      break;

      case PARTY_Jump:
        if ( (!partyAtHighSlope || bmodel_standing_on_pid) && !bJumping && pParty->field_24 && !(pParty->uFlags & 4) && !(BYTE1(pParty->uFlags) & 2) )
        {
          v126 = pParty->field_24 << 6;
          bJumping = 1;
          pParty->uFallSpeed = (signed __int64)((double)(pParty->field_24 << 6) * 1.5 + (double)pParty->uFallSpeed);
        }
      break;

      default:
        assert(false);

      case PARTY_Land:
        if (pParty->bFlying)
        {
          pParty->uFlags |= PARTY_FLAGS_1_LANDING;
          pParty->uFallSpeed = 0;
        }
        pParty->bFlying = false;
        pPartyActionQueue->uNumActions = 0;
      break;
    }
  }

//LABEL_123:
  pParty->sRotationY = _angle_y;
  pParty->sRotationX = _angle_x;
  if ( pZ < v111 || pParty->bFlying)
  {
    if ( pParty->bFlying )
    {
      v126 = stru_5C6E00->Cos(GetTickCount());
      v129 = (unsigned __int64)(4i64 * v126) >> 16;
      pZ = v113 + v129;
      if ( pModel )
        pZ = v113;
      if (pParty->FlyActive())
        stru_5E4C90_MapPersistVars._decor_events[20 * pParty->pPartyBuffs[PARTY_BUFF_FLY].uOverlayID + 119] &= 0xFEu;
      pParty->uFallStartY = pZ;
    }
    else
    {
      if ( is_on_water && pParty->uFallSpeed )
        sub_42F960_create_object(pX, pY, v111);
      pParty->uFallSpeed = 0;
      pZ = v111;
      pParty->uFallStartY = v111;
      v113 = pZ;
      if (pParty->FlyActive())
        stru_5E4C90_MapPersistVars._decor_events[20 * pParty->pPartyBuffs[PARTY_BUFF_FLY].uOverlayID + 119] |= 1u;
    }
  }
  else
  {
	  v113 = pZ;
	  if (pParty->FlyActive())
		stru_5E4C90_MapPersistVars._decor_events[20 * pParty->pPartyBuffs[PARTY_BUFF_FLY].uOverlayID + 119] |= 1u;
  }
//LABEL_141:
  if (bJumping && !pParty->bFlying)
  {
    v33 = -(pEventTimer->uTimeElapsed * GetGravityStrength());
    v34 = pParty->uFallSpeed + 2 * v33;
    pParty->uFallSpeed += 2 * v33;
  }
  else if (!partyAtHighSlope)
  {
    v34 = pParty->uFallSpeed;
  }
  else if (!bJumping)
  {
    if ( !bmodel_standing_on_pid )
	{
		// rolling down the hill
		// how it's done: you get a little bit pushed in the air along terrain normal, getting in the air
		// and falling to the gravity, gradually sliding downwards. nice trick
		pZ = v111;
		ODM_GetTerrainNormalAt(pX, pY, &v98);
		v35 = pParty->uFallSpeed + -8 * pEventTimer->uTimeElapsed * GetGravityStrength();
		v129 = abs((signed __int64)v2 * v98.x + (signed __int64)v1 * v98.y + (signed __int64)v35 * v98.z) >> 16;
		v2 += (unsigned __int64)(v129 * (signed __int64)v98.x) >> 16;
		v1 += (unsigned __int64)(v129 * (signed __int64)v98.y) >> 16;
		v34 = v35 + ((unsigned __int64)(v129 * (signed __int64)v98.z) >> 16);
		v128 = v1;
		pParty->uFallSpeed = v34;
	}
  }
  else
	  v34 = pParty->uFallSpeed;

//LABEL_164:
  if(bJumping)
  {
	  if ( !bUnderwater && v34 <= 0)
	  {
		if ( v34 < -500
		  && !pParty->bFlying
		  && pParty->vPosition.z - v111 > 1000
		  && !pParty->FeatherFallActive())
		{ // falling scream
		  for (int i = 0; i < 4; ++i)
		  {
			auto player = &pParty->pPlayers[i];
			if (!player->HasEnchantedItemEquipped(72) && !player->WearsItem(ITEM_ARTIFACT_HERMES_SANDALS, EQUIP_BOOTS) && player->CanAct())
			  player->PlaySound(SPEECH_66, 0);
		  }
		}
	  }
  }
  else
  {
//LABEL_150:
  pParty->uFallStartY = pZ;
  }

  if ( v2 * v2 + v1 * v1 < 400 && !partyAtHighSlope )
  {
    *(float *)&v128 = 0.0;
    v2 = 0;
  }
  stru_721530.field_84 = -1;
  stru_721530.field_70 = 0;
  stru_721530.prolly_normal_d = pParty->field_14_radius;
  stru_721530.field_8_radius = pParty->field_14_radius >> 1;
  v126 = 0;
  stru_721530.field_0 = 1;
  stru_721530.height = pParty->uPartyHeight - 32;
  do
  {
    stru_721530.position.x = pX;
    stru_721530.normal.x = pX;
    stru_721530.velocity.x = v2;
    stru_721530.position.y = pY;
    stru_721530.normal.y = pY;
    stru_721530.normal.z = stru_721530.prolly_normal_d + pZ + 1;
    stru_721530.position.z = stru_721530.height + pZ + 1;
    stru_721530.velocity.y = v128;
    stru_721530.velocity.z = pParty->uFallSpeed;
    v36 = 0;
    stru_721530.uSectorID = 0;
    if ( pParty->bTurnBasedModeOn == 1 && pTurnEngine->turn_stage == 3 )
      v36 = 13312;
    if ( stru_721530._47050A(v36) )
      break;
    _46E889_collide_against_bmodels(1u);
    v37 = WorldPosToGridCellZ(pParty->vPosition.y);
    v38 = WorldPosToGridCellX(pParty->vPosition.x);
    _46E26D_collide_against_sprites(v38, v37);
    _46ED8A_collide_against_sprite_objects(4u);
    for ( i = 0; i < (signed int)uNumActors; ++i )
      Actor::_46DF1A_collide_against_actor(i, 0);
    if ( stru_721530.field_7C >= stru_721530.field_6C )
    {
      _angle_x = stru_721530.normal2.x;
      _angle_y = stru_721530.normal2.y;
      v40 = stru_721530.normal2.z - stru_721530.prolly_normal_d - 1;
    }
    else
    {
      _angle_x = pX + fixpoint_mul(stru_721530.field_7C, stru_721530.direction.x);
      _angle_y = pY + fixpoint_mul(stru_721530.field_7C, stru_721530.direction.y);
      pModel = (BSPModel *)fixpoint_mul(stru_721530.field_7C, stru_721530.direction.z);
      v40 = fixpoint_mul(stru_721530.field_7C, stru_721530.direction.z) + pZ;
    }
    v122 = v40;
    ODM_GetFloorLevel(_angle_x, _angle_y, v40, pParty->uPartyHeight, &is_on_water, &bmodel_standing_on_pid, 0);
    v129 = ODM_GetFloorLevel(_angle_x, pY, v40, pParty->uPartyHeight, &is_on_water, &v97, 0);
    auto v119 = ODM_GetFloorLevel(pX, _angle_y, v40, pParty->uPartyHeight, &is_on_water, &v110, 0);
    pModel = (BSPModel *)IsTerrainSlopeTooHigh(_angle_x, pY);
    v42 = IsTerrainSlopeTooHigh(pX, _angle_y);
    is_not_on_bmodel = false;
    v118 = v42;
    if ( !v97 && !v110 && !bmodel_standing_on_pid )
      is_not_on_bmodel = true;
    v43 = 1;
    v44 = 1;
    if ( bUnderwater || !is_not_on_bmodel )
	{
		  pX = _angle_x;
		  if ( v43 )
			  pY = _angle_y;
	}
	else
	{
		if ( pModel && v129 > pZ )
		  v44 = 0;
		if ( v118 && v119 > pZ )
		  v43 = 0;
		if ( v44 )
		{
			  pX = _angle_x;
			  if ( v43 )
				  pY = _angle_y;
		}
		else if ( v43 )
		  pY = _angle_y;
		else
		{
			pModel = (BSPModel *)ODM_GetFloorLevel(_angle_x, _angle_y, v40, pParty->uPartyHeight, &is_on_water, &bmodel_standing_on_pid, 0);
			if ( IsTerrainSlopeTooHigh(_angle_x, _angle_y) && (signed int)pModel <= pZ )
			{
			  v43 = 1;
			  pX = _angle_x;
			  if ( v43 )
				  pY = _angle_y;
			}
		}
	}
    if ( stru_721530.field_7C >= stru_721530.field_6C )
    {
      if ( !is_not_on_bmodel )
      {
        pX = stru_721530.normal2.x;
        pY = stru_721530.normal2.y;
      }
      pZ = stru_721530.normal2.z - stru_721530.prolly_normal_d - 1;
      break;
    }
    stru_721530.field_70 += stru_721530.field_7C;
    pX = _angle_x;
    pY = _angle_y;
    v45 = stru_721530.uFaceID;
    pZ = v40;
    if ( PID_TYPE(stru_721530.uFaceID) == OBJECT_Actor)
    {
      if (pParty->Invisible())
        pParty->pPartyBuffs[PARTY_BUFF_INVISIBILITY].Reset();

      viewparams->bRedrawGameUI = 1;
		v2 = (unsigned __int64)(58500i64 * v2) >> 16;
		pModel = (BSPModel *)58500;
		v128 = (unsigned __int64)(58500i64 * v128) >> 16;
		v122 = (unsigned __int64)(58500i64 * pParty->uFallSpeed) >> 16;
		++v126;
		pParty->uFallSpeed = (unsigned __int64)(58500i64 * pParty->uFallSpeed) >> 16;
		continue;
	}
    if ( PID_TYPE(stru_721530.uFaceID) == OBJECT_Decoration)
    {
      v56 = integer_sqrt(v2 * v2 + v128 * v128);
      v118 = v56;
      v57 = stru_5C6E00->Atan2(_angle_x - pLevelDecorations[(signed int)stru_721530.uFaceID >> 3].vPosition.x,
                               _angle_y - pLevelDecorations[(signed int)stru_721530.uFaceID >> 3].vPosition.y);
      v129 = v57;
      v58 = (BSPModel *)stru_5C6E00->Cos(v57);
      pModel = v58;
      v59 = (signed int)v58 * (signed __int64)v56;
      v122 = v59 >> 16;
      v2 = v59 >> 16;
      v60 = (BSPModel *)stru_5C6E00->Sin(v129);
      pModel = v60;
      v61 = (signed int)v60 * (signed __int64)v118;
      v122 = v61 >> 16;
      v128 = v61 >> 16;
    }
    else
    {
      if ( PID_TYPE(stru_721530.uFaceID) == OBJECT_BModel)
      {
        pParty->bFlying = 0;
        pModel = &pOutdoor->pBModels[(signed int)stru_721530.uFaceID >> 9];
        //v127 = v46;
        pODMFace = &pModel->pFaces[((signed int)stru_721530.uFaceID >> 3) & 0x3F];
        v48 = pODMFace->pBoundingBox.z2 - pODMFace->pBoundingBox.z1;
        v51 = __OFSUB__(v48, 32);
        v49 = v48 == 32;
        v50 = v48 - 32 < 0;
        v52 = pODMFace->pFacePlane.vNormal.z;
        v129 = (unsigned __int8)(v50 ^ v51 | v49);
        v119 = v52 < 46378;
        if ( bUnderwater == 1 )
          v119 = 0;
        if ( pODMFace->uPolygonType == POLYGON_Floor )
        {
          if ( pParty->uFallSpeed < 0 )
            pParty->uFallSpeed = 0;
          pZ = pModel->pVertices.pVertices[pODMFace->pVertexIDs[0]].z + 1;
          if ( v2 * v2 + v128 * v128 < 400 )
          {
            v2 = 0;
            *(float *)&v128 = 0.0;
          }
          if ( pParty->floor_face_pid != v45 && (pODMFace->uAttributes & FACE_PRESSURE_PLATE))
          {
            pParty->floor_face_pid = v45;
            v103 = pODMFace->sCogTriggeredID;
          }
          v2 = (unsigned __int64)(58500i64 * v2) >> 16;
          pModel = (BSPModel *)58500;
          v128 = (unsigned __int64)(58500i64 * v128) >> 16;
          v122 = (unsigned __int64)(58500i64 * pParty->uFallSpeed) >> 16;
          ++v126;
          pParty->uFallSpeed = (unsigned __int64)(58500i64 * pParty->uFallSpeed) >> 16;
          continue;
        }
        if ( !v129 && (pODMFace->uPolygonType != POLYGON_InBetweenFloorAndWall || v119) )// óï¸ðñÿ â ñòîëá
        {
          v118 = abs(v128 * pODMFace->pFacePlane.vNormal.y + pParty->uFallSpeed * v52 + v2 * pODMFace->pFacePlane.vNormal.x) >> 16;
          if ((stru_721530.speed >> 3) > v118 )
            v118 = stru_721530.speed >> 3;
          v129 = (unsigned __int64)(v118 * (signed __int64)pODMFace->pFacePlane.vNormal.x) >> 16;
          _walk_speed = (unsigned __int64)(v118 * (signed __int64)pODMFace->pFacePlane.vNormal.y) >> 16;
          v54 = 0;
          if ( !v119 )
          {
            pModel = (BSPModel *)pODMFace->pFacePlane.vNormal.z;
            pModel = (BSPModel *)((unsigned __int64)(v118 * (signed __int64)(signed int)pModel) >> 16);
            v54 = pModel;
          }
          pParty->uFallSpeed += (int)v54;
          v128 += _walk_speed;
          v2 += v129;
          v55 = stru_721530.prolly_normal_d
              - ((signed int)(pODMFace->pFacePlane.dist
                            + v122 * pODMFace->pFacePlane.vNormal.z
                            + _angle_y * pODMFace->pFacePlane.vNormal.y
                            + _angle_x * pODMFace->pFacePlane.vNormal.x) >> 16);
          if ( v55 > 0 )
          {
            pX = _angle_x + (pODMFace->pFacePlane.vNormal.x * v55 >> 16);
            pY = _angle_y + (pODMFace->pFacePlane.vNormal.y * v55 >> 16);
            if ( !v119 )
              pZ = v122 + (pODMFace->pFacePlane.vNormal.z * v55 >> 16);
          }
//LABEL_220:
			v45 = stru_721530.uFaceID;
			if ( pParty->floor_face_pid != v45 && BYTE3(pODMFace->uAttributes) & 4 )
			{
				pParty->floor_face_pid = v45;
				v103 = pODMFace->sCogTriggeredID;
			}
			v2 = (unsigned __int64)(58500i64 * v2) >> 16;
			pModel = (BSPModel *)58500;
			v128 = (unsigned __int64)(58500i64 * v128) >> 16;
			v122 = (unsigned __int64)(58500i64 * pParty->uFallSpeed) >> 16;
			++v126;
			pParty->uFallSpeed = (unsigned __int64)(58500i64 * pParty->uFallSpeed) >> 16;
			continue;
        }
        v118 = abs(v128 * pODMFace->pFacePlane.vNormal.y + pParty->uFallSpeed * v52 + v2 * pODMFace->pFacePlane.vNormal.x) >> 16;
        if ((stru_721530.speed >> 3) > v118 )
          v118 = stru_721530.speed >> 3;
        v122 = pODMFace->pFacePlane.vNormal.x;
        v122 = (unsigned __int64)(v118 * (signed __int64)(signed int)v122) >> 16;
        pModel = (BSPModel *)pODMFace->pFacePlane.vNormal.y;
        pModel = (BSPModel *)((unsigned __int64)(v118 * (signed __int64)(signed int)pModel) >> 16);
        v129 = pODMFace->pFacePlane.vNormal.z;
        v129 = (unsigned __int64)(v118 * (signed __int64)v129) >> 16;
        pParty->uFallSpeed += v129;
        v2 += v122;
        v128 += (int)pModel;
        if ( v2 * v2 + v128 * v128 >= 400 )
		{
			v45 = stru_721530.uFaceID;
			if ( pParty->floor_face_pid != v45 && BYTE3(pODMFace->uAttributes) & 4 )
			{
				pParty->floor_face_pid = v45;
				v103 = pODMFace->sCogTriggeredID;
			}
			v2 = (unsigned __int64)(58500i64 * v2) >> 16;
			pModel = (BSPModel *)58500;
			v128 = (unsigned __int64)(58500i64 * v128) >> 16;
			v122 = (unsigned __int64)(58500i64 * pParty->uFallSpeed) >> 16;
			++v126;
			pParty->uFallSpeed = (unsigned __int64)(58500i64 * pParty->uFallSpeed) >> 16;
			continue;
		}
        v2 = 0;
        pParty->uFallSpeed = 0;
        *(float *)&v128 = 0.0;
      }
    }
//LABEL_234:
    v2 = (unsigned __int64)(58500i64 * v2) >> 16;
    pModel = (BSPModel *)58500;
    v128 = (unsigned __int64)(58500i64 * v128) >> 16;
    v122 = (unsigned __int64)(58500i64 * pParty->uFallSpeed) >> 16;
    ++v126;
    pParty->uFallSpeed = (unsigned __int64)(58500i64 * pParty->uFallSpeed) >> 16;
  }
  while ( v126 < 100 );
  if ( bWalkSound && pParty->walk_sound_timer <= 0 )
  {
    v122 = abs(pParty->vPosition.x - pX);
    v126 = abs(pParty->vPosition.y - pY);
    v62 = abs(pParty->vPosition.z - pZ);
    if ( integer_sqrt(v122 * v122 + v126 * v126 + v62 * v62) < 8 )
	{
		  pAudioPlayer->_4AA258(804);
		  pParty->walk_sound_timer = 64;
	}
	else
	{
		if ( v114 && (!bJumping || v101) )
		{
		  if ( !is_not_on_bmodel
			&& !(BYTE1(pOutdoor->pBModels[pParty->floor_face_pid >> 9].pFaces[(pParty->floor_face_pid >> 3) & 0x3F].uAttributes) & 0x20) )
		  {
            pAudioPlayer->PlaySound(SOUND_64, 804, 1, -1, 0, 0, 0, 0);
		  }
		  else
		  {
			//v63 = WorldPosToGridCellZ(pParty->vPosition.y) - 1;
			//v64 = WorldPosToGridCellX(pParty->vPosition.x);
			v87 = pOutdoor->GetSoundIdByPosition(WorldPosToGridCellX(pParty->vPosition.x), WorldPosToGridCellZ(pParty->vPosition.y) - 1, 1);
			pAudioPlayer->PlaySound((SoundID)v87, 804, 1, -1, 0, 0, 0, 0);
		  }
		}
		else
		{
			if ( v124 && (!bJumping || v101) )
			{
			  if ( is_not_on_bmodel
				|| BYTE1(pOutdoor->pBModels[pParty->floor_face_pid >> 9].pFaces[(pParty->floor_face_pid >> 3) & 0x3F].uAttributes) & 0x20 )
			  {
				//v63 = WorldPosToGridCellZ(pParty->vPosition.y) - 1;
				//v64 = WorldPosToGridCellX(pParty->vPosition.x);
				v87 = pOutdoor->GetSoundIdByPosition(WorldPosToGridCellX(pParty->vPosition.x), WorldPosToGridCellZ(pParty->vPosition.y) - 1, 0);
				pAudioPlayer->PlaySound((SoundID)v87, 804, 1, -1, 0, 0, 0, 0);
			  }
			  else
                pAudioPlayer->PlaySound(SOUND_103, 804, 1, -1, 0, 0, 0, 0);
			}
			else
			{
			  pAudioPlayer->_4AA258(804);
			  pParty->walk_sound_timer = 64;
			}
		}
    }
  }
  if ( !bJumping || v101 )
    pParty->uFlags &= ~PARTY_FLAGS_1_FALLING;
  else
    pParty->uFlags |= PARTY_FLAGS_1_FALLING;
  v126 = WorldPosToGridCellX(pParty->vPosition.x);
  v65 = WorldPosToGridCellZ(pParty->vPosition.y) - 1;
  v114 = WorldPosToGridCellX(pX);
  v66 = WorldPosToGridCellZ(pY) - 1;
  pModel = (BSPModel *)((~(unsigned int)pOutdoor->ActuallyGetSomeOtherTileInfo(v126, v65) >> 1) & 1);
  v122 = (~(unsigned int)pOutdoor->ActuallyGetSomeOtherTileInfo(v114, v65) >> 1) & 1;
  v67 = pOutdoor->ActuallyGetSomeOtherTileInfo(v126, v66);
  v68 = 0;
  v69 = (~(unsigned int)v67 >> 1) & 1;
  if ( v114 == v126 && v66 == v65 && v122 && v69 )
    v68 = 1;
  if ( !is_not_on_bmodel )
    v68 = 1;
  if ( v68 )
  {
    v70 = pZ;
    v71 = pX;
    v72 = pY;
    //pParty->uFallSpeed = v121;
    v73 = pZ;
    pParty->vPosition.x = pX;
    pParty->vPosition.y = pY;
    pParty->vPosition.z = pZ;
    pParty->field_6F0 = v113;
    if ( pZ > 8160 )
    {
      v73 = 8160;
      pParty->uFallStartY = 8160;
      pParty->vPosition.z = 8160;
    }
    if ( !v103
      || (EventProcessor(v103, 0, 1), pParty->vPosition.x == v71)
      && pParty->vPosition.y == v72
      && (v73 = pParty->vPosition.z, pParty->vPosition.z == v70) )
    {
      if ( v73 < v111 )
      {
        pParty->uFallSpeed = 0;
        v73 = v105;
        pParty->vPosition.z = v105;
        if ( pParty->uFallStartY - v70 > 512 && !bFeatherFall && v70 <= v105 && !bUnderwater )//Fall to the ground(ïàäåíèå íà çåìëþ ñ âûñîòû)
        {
          if ( pParty->uFlags & PARTY_FLAGS_1_LANDING )
          {
            pParty->uFlags &= ~PARTY_FLAGS_1_LANDING;
          }
          else
          {
            for ( uint i = 1; i <= 4; ++i )
            {
              v110 = pPlayers[i]->GetMaxHealth();
              pPlayers[i]->ReceiveDamage((signed int)((pParty->uFallStartY - v70) * (unsigned __int64)(signed __int64)((double)v110 * 0.1)) / 256,
                DMGT_PHISYCAL);
              v110 = 20 - pPlayers[i]->GetParameterBonus(pPlayers[i]->GetActualEndurance());
              pPlayers[i]->SetRecoveryTime((signed __int64)((double)v110 * flt_6BE3A4_debug_recmod1 * 2.133333333333333));
            }
            v73 = pParty->vPosition.z;
          }
        }
        pParty->uFallStartY = v70;
      }
      if ( v102 && v73 < v109 )
      {
        if ( (signed int)(pParty->uPartyHeight + v73) >= v109 )
        {
          pParty->vPosition.z = v109 - pParty->uPartyHeight - 1;
          pParty->field_6F0 = v109 - pParty->uPartyHeight - 1;
        }
      }
      pParty->uFlags &= ~0x204;
    }
    return;
  }
  v76 = pParty->bFlying;
  if ( pParty->bFlying || v101 == 0 || bWaterWalk || !pModel )
    v77 = 1;
  else
    v77 = v122 != 0;
  v114 = 0;
  if ( !pParty->bFlying && v101 != 0 && !bWaterWalk )
  {
    if ( pModel )
    {
      v78 = v69 != 0;
    }
	else
	{
		v114 = 1;
		v78 = 1;
	}
  }
  else
	v78 = 1;
//LABEL_306:
  if ( v77 )
  {
    pParty->vPosition.x = pX;
  }
  if ( v78 )
  {
    pParty->vPosition.y = pY;
  }
  if ( v78 || v77)
  {
    if ( bWaterWalk )
    {
      pParty->uFlags &= ~PARTY_FLAGS_1_STANDING_ON_WATER;
      //v79 = 20 * pParty->pPartyBuffs[PARTY_BUFF_WATER_WALK].uOverlayID + 6180178;
      //*(short *)&stru_5E4C90._decor_events[20 * pParty->pPartyBuffs[PARTY_BUFF_WATER_WALK].uOverlayID + 119] |= 1u;
      v79 = (int)&stru_5E4C90_MapPersistVars._decor_events[20 * pParty->pPartyBuffs[PARTY_BUFF_WATER_WALK].uOverlayID + 119];
      *(short *)v79 |= 1u;
      if ( !v122 || !v69 )
      {
        if ( !v76 )
        {
          v80 = *(short *)v79;
          pParty->uFlags |= PARTY_FLAGS_1_STANDING_ON_WATER;
          *(short *)v79 = v80 & 0xFFFE;
        }
      }
    }
  }
  else if ( bWalkSound && pParty->walk_sound_timer <= 0 )
  {
    pAudioPlayer->_4AA258(804);
    pParty->walk_sound_timer = 64;
  }
//LABEL_318:
  v81 = pZ;
  v82 = pZ;
  pParty->vPosition.z = pZ;
  if ( pZ > 8160 )
  {
    v82 = 8160;
    pParty->uFallStartY = 8160;
    pParty->vPosition.z = 8160;
  }
  LOWORD(pParty->uFlags) &= 0xFDFBu;
  //pParty->uFallSpeed = v121;
  pParty->field_6F0 = v113;
  if ( v114 )//party stand to the water(ãðóïïà ñòîèò íà âîäå)
  {
    pTerrainHeight = GetTerrainHeightsAroundParty2(pParty->vPosition.x, pParty->vPosition.y, &v110, 1);
    if ( pParty->vPosition.z <= pTerrainHeight + 1 )//ïîëîæåíèå ãðóïïû âñåãäà +1
      pParty->uFlags |= PARTY_FLAGS_1_WATER_DAMAGE;
  }
  if ( !v103
    || (EventProcessor(v103, 0, 1), pParty->vPosition.x == pX)
    && pParty->vPosition.y == pY
    && (v82 = pParty->vPosition.z, pParty->vPosition.z == v81) )
  {
    if ( v82 < v111 )
    {
      v82 = v105;
      pParty->uFallSpeed = 0;
      pParty->vPosition.z = v105;
      if ( pParty->uFallStartY - v81 > 512 && !bFeatherFall && v81 <= v105 && !bUnderwater )//Fall to the water(ïàäåíèå íà âîäó ñ âûñîòû)
      {
        if ( pParty->uFlags & PARTY_FLAGS_1_LANDING )
        {
          pParty->uFlags &= ~PARTY_FLAGS_1_LANDING;
        }
        else
        {
          for ( uint i = 1; i <= 4; ++i )
          {
            v110 = pPlayers[i]->GetMaxHealth();
            pPlayers[i]->ReceiveDamage((signed int)((pParty->uFallStartY - v81) * (unsigned __int64)(signed __int64)((double)v110 * 0.1)) / 256,
              DMGT_PHISYCAL);
            v110 = 20 - pPlayers[i]->GetParameterBonus(pPlayers[i]->GetActualEndurance());
            pPlayers[i]->SetRecoveryTime((signed __int64)((double)v110 * flt_6BE3A4_debug_recmod1 * 2.133333333333333));
          }
          v82 = pParty->vPosition.z;
        }
      }
      pParty->uFallStartY = v81;
    }
    if ( v102 && v82 < v109 && (signed int)(pParty->uPartyHeight + v82) >= v109 )
    {
      pParty->vPosition.z = v82 + pParty->uPartyHeight - v109 + 1;
      pParty->field_6F0 = v82 + pParty->uPartyHeight - v109 + 1;
    }
  }
}

//----- (0047531C) --------------------------------------------------------
bool __fastcall sub_47531C(int a1, int *a2, int a3, int a4, int a5, int a6, int a7, int a8, BLVFace *a9, int a10)
{
  BLVFace *v10; // ebx@1
  int v11; // ST1C_4@3
  int v12; // edi@3
  int v13; // esi@3
  int v14; // edi@4
  signed __int64 v15; // qtt@6
  __int16 v16; // si@7
  int *v18; // [sp+Ch] [bp-Ch]@1
  int v19; // [sp+10h] [bp-8h]@1
  int a7a; // [sp+30h] [bp+18h]@7
  int a9b; // [sp+38h] [bp+20h]@3
  int a9a; // [sp+38h] [bp+20h]@3
  int a10b; // [sp+3Ch] [bp+24h]@3
  signed int a10a; // [sp+3Ch] [bp+24h]@4
  int a10c; // [sp+3Ch] [bp+24h]@5

  v10 = a9;
  v18 = a2;
  v19 = a1;
  if ( a10 && BYTE3(a9->uAttributes) & 0x20 )
    return 0;
  v11 = (unsigned __int64)(a6 * (signed __int64)a9->pFacePlane_old.vNormal.x) >> 16;
  a10b = (unsigned __int64)(a7 * (signed __int64)a9->pFacePlane_old.vNormal.y) >> 16;
  a9b = (unsigned __int64)(a8 * (signed __int64)a9->pFacePlane_old.vNormal.z) >> 16;
  v12 = v11 + a9b + a10b;
  a9a = v11 + a9b + a10b;
  v13 = (a1 << 16)
      - a3 * v10->pFacePlane_old.vNormal.x
      - a4 * v10->pFacePlane_old.vNormal.y
      - a5 * v10->pFacePlane_old.vNormal.z
      - v10->pFacePlane_old.dist;
  if ( abs((a1 << 16)
         - a3 * v10->pFacePlane_old.vNormal.x
         - a4 * v10->pFacePlane_old.vNormal.y
         - a5 * v10->pFacePlane_old.vNormal.z - v10->pFacePlane_old.dist) >= a1 << 16 )
  {
    a10c = abs(v13) >> 14;
    if ( a10c > abs(v12) )
      return 0;
    LODWORD(v15) = v13 << 16;
    HIDWORD(v15) = v13 >> 16;
    v14 = v19;
    a10a = v15 / a9a;
  }
  else
  {
    a10a = 0;
    v14 = abs(v13) >> 16;
  }
  v16 = a4 + ((unsigned int)((unsigned __int64)(a10a * (signed __int64)a7) >> 16) >> 16);
  LOWORD(a7a) = (short)a3
              + ((unsigned int)((unsigned __int64)(a10a * (signed __int64)a6) >> 16) >> 16)
              - ((unsigned int)(v14 * v10->pFacePlane_old.vNormal.x) >> 16);
  HIWORD(a7a) = v16 - ((unsigned int)(v14 * v10->pFacePlane_old.vNormal.y) >> 16);
  if ( !sub_475665(
          v10,
          a7a,
          (short)a5
        + ((unsigned int)((unsigned __int64)(a10a * (signed __int64)a8) >> 16) >> 16)
        - ((unsigned int)(v14 * v10->pFacePlane_old.vNormal.z) >> 16)) )
    return 0;
  *v18 = a10a >> 16;
  if ( a10a >> 16 < 0 )
    *v18 = 0;
  return 1;
}

//----- (004754BF) --------------------------------------------------------
bool __fastcall sub_4754BF(int a1, int *a2, int a3, int a4, int a5, int a6, int a7, int a8, BLVFace *a9, int a10, int a11)
{
  BLVFace *v11; // ebx@1
  int v12; // ST1C_4@3
  int v13; // edi@3
  int v14; // esi@3
  int v15; // edi@4
  signed __int64 v16; // qtt@6
  __int16 v17; // si@7
  int *v19; // [sp+Ch] [bp-Ch]@1
  int v20; // [sp+10h] [bp-8h]@1
  int a7a; // [sp+30h] [bp+18h]@7
  int a1b; // [sp+38h] [bp+20h]@3
  int a1a; // [sp+38h] [bp+20h]@3
  int a11b; // [sp+40h] [bp+28h]@3
  signed int a11a; // [sp+40h] [bp+28h]@4
  int a11c; // [sp+40h] [bp+28h]@5

  v11 = a9;
  v19 = a2;
  v20 = a1;
  if ( a11 && BYTE3(a9->uAttributes) & 0x20 )
    return 0;
  v12 = (unsigned __int64)(a6 * (signed __int64)a9->pFacePlane_old.vNormal.x) >> 16;
  a11b = (unsigned __int64)(a7 * (signed __int64)a9->pFacePlane_old.vNormal.y) >> 16;
  a1b = (unsigned __int64)(a8 * (signed __int64)a9->pFacePlane_old.vNormal.z) >> 16;
  v13 = v12 + a1b + a11b;
  a1a = v12 + a1b + a11b;
  v14 = (a1 << 16)
      - a3 * v11->pFacePlane_old.vNormal.x
      - a4 * v11->pFacePlane_old.vNormal.y
      - a5 * v11->pFacePlane_old.vNormal.z
      - v11->pFacePlane_old.dist;
  if ( abs((a1 << 16)
         - a3 * v11->pFacePlane_old.vNormal.x
         - a4 * v11->pFacePlane_old.vNormal.y
         - a5 * v11->pFacePlane_old.vNormal.z - v11->pFacePlane_old.dist) >= a1 << 16 )
  {
    a11c = abs(v14) >> 14;
    if ( a11c > abs(v13) )
      return 0;
    LODWORD(v16) = v14 << 16;
    HIDWORD(v16) = v14 >> 16;
    v15 = v20;
    a11a = v16 / a1a;
  }
  else
  {
    a11a = 0;
    v15 = abs(v14) >> 16;
  }
  v17 = a4 + ((unsigned int)((unsigned __int64)(a11a * (signed __int64)a7) >> 16) >> 16);
  LOWORD(a7a) = (short)a3
              + ((unsigned int)((unsigned __int64)(a11a * (signed __int64)a6) >> 16) >> 16)
              - ((unsigned int)(v15 * v11->pFacePlane_old.vNormal.x) >> 16);
  HIWORD(a7a) = v17 - ((unsigned int)(v15 * v11->pFacePlane_old.vNormal.y) >> 16);
  if ( !sub_4759C9(
          v11,
          a10,
          a7a,
          (short)a5
        + ((unsigned int)((unsigned __int64)(a11a * (signed __int64)a8) >> 16) >> 16)
        - ((unsigned int)(v15 * v11->pFacePlane_old.vNormal.z) >> 16)) )
    return 0;
  *v19 = a11a >> 16;
  if ( a11a >> 16 < 0 )
    *v19 = 0;
  return 1;
}

//----- (00475665) --------------------------------------------------------
int sub_475665(BLVFace *_this, int a2, __int16 a3)
{
  unsigned int v3; // eax@1
  Vec3_short_ *v4; // edx@3
  signed int v5; // eax@4
  int v6; // esi@4
  signed int v7; // eax@7
  Vec3_short_ *v8; // edx@8
  signed int v9; // eax@9
  int v10; // esi@9
  signed int v11; // eax@11
  Vec3_short_ *v12; // edx@12
  signed int v13; // eax@13
  int v14; // esi@13
  int v15; // esi@14
  bool v16; // edi@14
  int v17; // ecx@16
  signed int v18; // edx@16
  int v19; // eax@17
  signed int v20; // ebx@18
  int v21; // edi@20
  signed int v22; // ST14_4@22
  signed __int64 v23; // qtt@22
  signed int result; // eax@25
  int v25; // [sp+14h] [bp-10h]@14
  int v26; // [sp+1Ch] [bp-8h]@2
  signed int v27; // [sp+20h] [bp-4h]@2
  signed int v28; // [sp+30h] [bp+Ch]@2
  signed int v29; // [sp+30h] [bp+Ch]@7
  signed int v30; // [sp+30h] [bp+Ch]@11
  signed int v31; // [sp+30h] [bp+Ch]@14

  v3 = _this->uAttributes;
  if ( BYTE1(v3) & 1 )
  {
    v28 = 0;
    v26 = (signed __int16)a2;
    v27 = SHIWORD(a2);
    if ( _this->uNumVertices )
    {
      v4 = pIndoor->pVertices;
      do
      {
        v5 = v28;
        v6 = 2 * v28;
        word_720C10_intercepts_xs[2 * v28] = _this->pXInterceptDisplacements[v28] + v4[_this->pVertexIDs[v28]].x;
        word_720B40_intercepts_zs[2 * v28] = _this->pYInterceptDisplacements[v5] + v4[_this->pVertexIDs[v5]].y;
        word_720C10_intercepts_xs[2 * v28++ + 1] = _this->pXInterceptDisplacements[v5 + 1]
                                                 + v4[_this->pVertexIDs[v5 + 1]].x;
        word_720B40_intercepts_zs[v6 + 1] = _this->pYInterceptDisplacements[v5 + 1] + v4[_this->pVertexIDs[v5 + 1]].y;
      }
      while ( v28 < _this->uNumVertices );
    }
  }
  else
  {
    if ( BYTE1(v3) & 2 )
    {
      v26 = (signed __int16)a2;
      v7 = a3;
      v29 = 0;
      v27 = v7;
      if ( _this->uNumVertices )
      {
        v8 = pIndoor->pVertices;
        do
        {
          v9 = v29;
          v10 = 2 * v29;
          word_720C10_intercepts_xs[2 * v29] = _this->pXInterceptDisplacements[v29] + v8[_this->pVertexIDs[v29]].x;
          word_720B40_intercepts_zs[2 * v29] = _this->pZInterceptDisplacements[v9] + v8[_this->pVertexIDs[v9]].z;
          word_720C10_intercepts_xs[2 * v29++ + 1] = _this->pXInterceptDisplacements[v9 + 1] + v8[_this->pVertexIDs[v9 + 1]].x;
          word_720B40_intercepts_zs[v10 + 1] = _this->pZInterceptDisplacements[v9 + 1] + v8[_this->pVertexIDs[v9 + 1]].z;
        }
        while ( v29 < _this->uNumVertices );
      }
    }
    else
    {
      v26 = SHIWORD(a2);
      v11 = a3;
      v30 = 0;
      v27 = v11;
      if ( _this->uNumVertices )
      {
        v12 = pIndoor->pVertices;
        do
        {
          v13 = v30;
          v14 = 2 * v30;
          word_720C10_intercepts_xs[2 * v30] = _this->pYInterceptDisplacements[v30] + v12[_this->pVertexIDs[v30]].y;
          word_720B40_intercepts_zs[2 * v30] = _this->pZInterceptDisplacements[v13] + v12[_this->pVertexIDs[v13]].z;
          word_720C10_intercepts_xs[2 * v30++ + 1] = _this->pYInterceptDisplacements[v13 + 1] + v12[_this->pVertexIDs[v13 + 1]].y;
          word_720B40_intercepts_zs[v14 + 1] = _this->pZInterceptDisplacements[v13 + 1] + v12[_this->pVertexIDs[v13 + 1]].z;
        }
        while ( v30 < _this->uNumVertices );
      }
    }
  }
  v15 = 2 * _this->uNumVertices;
  v31 = 0;
  word_720C10_intercepts_xs[2 * _this->uNumVertices] = word_720C10_intercepts_xs[0];
  word_720B40_intercepts_zs[v15] = word_720B40_intercepts_zs[0];
  v25 = 0;
  v16 = word_720B40_intercepts_zs[0] >= v27;
  if ( v15 <= 0 )
    return 0;
  do
  {
    if ( v31 >= 2 )
      break;
    v17 = v25;
    v18 = word_720B40_intercepts_zs[v25 + 1];
    if ( v16 ^ (v18 >= v27) )
    {
      v19 = word_720C10_intercepts_xs[v17 + 1];
      if ( v19 >= v26 )
        v20 = 0;
      else
        v20 = 2;
      v21 = v20 | (word_720C10_intercepts_xs[v17] < v26);
      if ( v21 != 3 )
      {
        if ( !v21
          || (v22 = v19 - word_720C10_intercepts_xs[v17],
              LODWORD(v23) = v22 << 16,
              HIDWORD(v23) = v22 >> 16,
              word_720C10_intercepts_xs[v17]
            + ((signed int)(((unsigned __int64)(v23
                                              / (v18 - word_720B40_intercepts_zs[v17])
                                              * ((v27 - (signed int)word_720B40_intercepts_zs[v17]) << 16)) >> 16)
                          + 32768) >> 16) >= v26) )
          ++v31;
      }
    }
    ++v25;
    v16 = v18 >= v27;
  }
  while ( v25 < v15 );
  result = 1;
  if ( v31 != 1 )
    result = 0;
  return result;
}

//----- (004759C9) --------------------------------------------------------
bool __fastcall sub_4759C9(BLVFace *a1, int a2, int a3, __int16 a4)
{
  unsigned int v4; // eax@1
  int v5; // edx@4
  __int16 v6; // si@4
  int v7; // edx@9
  __int16 v8; // si@9
  int v9; // edx@13
  __int16 v10; // si@13
  int v11; // esi@14
  bool v12; // edi@14
  int v13; // ecx@16
  signed int v14; // edx@16
  int v15; // eax@17
  signed int v16; // ebx@18
  int v17; // edi@20
  signed int v18; // ST14_4@22
  signed __int64 v19; // qtt@22
  bool result; // eax@25
  int v21; // [sp+14h] [bp-10h]@14
  signed int v22; // [sp+18h] [bp-Ch]@1
  int v23; // [sp+1Ch] [bp-8h]@2
  signed int v24; // [sp+20h] [bp-4h]@2
  Vec3_int_ **a4a; // [sp+30h] [bp+Ch]@3
  Vec3_int_ **a4b; // [sp+30h] [bp+Ch]@8
  Vec3_int_ **a4c; // [sp+30h] [bp+Ch]@12
  signed int a4d; // [sp+30h] [bp+Ch]@14

  v4 = a1->uAttributes;
  v22 = 0;
  if ( BYTE1(v4) & 1 )
  {
    v23 = (signed __int16)a3;
    v24 = SHIWORD(a3);
    if ( a1->uNumVertices )
    {
      a4a = &pOutdoor->pBModels[a2].pVertices.pVertices;
      do
      {
        v5 = 2 * v22;
        word_720A70_intercepts_xs_plus_xs[2 * v22] = a1->pXInterceptDisplacements[v22] + LOWORD((*a4a)[a1->pVertexIDs[v22]].x);
        word_7209A0_intercepts_ys_plus_ys[2 * v22] = a1->pYInterceptDisplacements[v22] + LOWORD((*a4a)[a1->pVertexIDs[v22]].y);
        word_720A70_intercepts_xs_plus_xs[2 * v22 + 1] = a1->pXInterceptDisplacements[v22 + 1] + LOWORD((*a4a)[a1->pVertexIDs[v22 + 1]].x);
        word_7209A0_intercepts_ys_plus_ys[v5 + 1] = v6 = a1->pYInterceptDisplacements[v22 + 1] + LOWORD((*a4a)[a1->pVertexIDs[v22 + 1]].y);
        ++v22;
      }
      while ( v22 < a1->uNumVertices );
    }
  }
  else
  {
    if ( BYTE1(v4) & 2 )
    {
      v23 = (signed __int16)a3;
      v24 = a4;
      if ( a1->uNumVertices )
      {
        a4b = &pOutdoor->pBModels[a2].pVertices.pVertices;
        do
        {
          v7 = 2 * v22;
          word_720A70_intercepts_xs_plus_xs[2 * v22] = a1->pXInterceptDisplacements[v22] + LOWORD((*a4b)[a1->pVertexIDs[v22]].x);
          word_7209A0_intercepts_ys_plus_ys[2 * v22] = a1->pZInterceptDisplacements[v22] + LOWORD((*a4b)[a1->pVertexIDs[v22]].z);
          word_720A70_intercepts_xs_plus_xs[2 * v22 + 1] = a1->pXInterceptDisplacements[v22 + 1] + LOWORD((*a4b)[a1->pVertexIDs[v22 + 1]].x);
          word_7209A0_intercepts_ys_plus_ys[v7 + 1] = v8 = a1->pZInterceptDisplacements[v22 + 1] + LOWORD((*a4b)[a1->pVertexIDs[v22 + 1]].z);
          ++v22;
        }
        while ( v22 < a1->uNumVertices );
      }
    }
    else
    {
      v23 = SHIWORD(a3);
      v24 = a4;
      if ( a1->uNumVertices )
      {
        a4c = &pOutdoor->pBModels[a2].pVertices.pVertices;
        do
        {
          v9 = 2 * v22;
          word_720A70_intercepts_xs_plus_xs[2 * v22] = a1->pYInterceptDisplacements[v22] + LOWORD((*a4c)[a1->pVertexIDs[v22]].y);
          word_7209A0_intercepts_ys_plus_ys[2 * v22] = a1->pZInterceptDisplacements[v22] + LOWORD((*a4c)[a1->pVertexIDs[v22]].z);
          word_720A70_intercepts_xs_plus_xs[2 * v22 + 1] = a1->pYInterceptDisplacements[v22 + 1] + LOWORD((*a4c)[a1->pVertexIDs[v22 + 1]].y);
          word_7209A0_intercepts_ys_plus_ys[v9 + 1] = v10 = a1->pZInterceptDisplacements[v22 + 1] + LOWORD((*a4c)[a1->pVertexIDs[v22 + 1]].z);
          ++v22;
        }
        while ( v22 < a1->uNumVertices );
      }
    }
  }
  v11 = 2 * a1->uNumVertices;
  a4d = 0;
  word_720A70_intercepts_xs_plus_xs[2 * a1->uNumVertices] = word_720A70_intercepts_xs_plus_xs[0];
  word_7209A0_intercepts_ys_plus_ys[v11] = word_7209A0_intercepts_ys_plus_ys[0];
  v21 = 0;
  v12 = word_7209A0_intercepts_ys_plus_ys[0] >= v24;
  if ( v11 <= 0 )
    return 0;
  do
  {
    if ( a4d >= 2 )
      break;
    v13 = v21;
    v14 = word_7209A0_intercepts_ys_plus_ys[v21 + 1];
    if ( v12 ^ (v14 >= v24) )
    {
      v15 = word_720A70_intercepts_xs_plus_xs[v13 + 1];
      if ( v15 >= v23 )
        v16 = 0;
      else
        v16 = 2;
      v17 = v16 | (word_720A70_intercepts_xs_plus_xs[v13] < v23);
      if ( v17 != 3 )
      {
        if ( !v17
          || (v18 = v15 - word_720A70_intercepts_xs_plus_xs[v13],
              LODWORD(v19) = v18 << 16,
              HIDWORD(v19) = v18 >> 16,
              word_720A70_intercepts_xs_plus_xs[v13]
            + ((signed int)(((unsigned __int64)(v19
                                              / (v14 - word_7209A0_intercepts_ys_plus_ys[v13])
                                              * ((v24 - (signed int)word_7209A0_intercepts_ys_plus_ys[v13]) << 16)) >> 16)
                          + 32768) >> 16) >= v23) )
          ++a4d;
      }
    }
    ++v21;
    v12 = v14 >= v24;
  }
  while ( v21 < v11 );
  result = 1;
  if ( a4d != 1 )
    result = 0;
  return result;
}

//----- (00475D85) --------------------------------------------------------
bool __fastcall sub_475D85(Vec3_int_ *a1, Vec3_int_ *a2, int *a3, BLVFace *a4)
{
  BLVFace *v4; // ebx@1
  int v5; // ST24_4@2
  int v6; // ST28_4@2
  int v7; // edi@2
  int v8; // eax@5
  signed int v9; // esi@5
  signed __int64 v10; // qtt@10
  Vec3_int_ *v11; // esi@11
  int v12; // ST14_4@11
  Vec3_int_ *v14; // [sp+Ch] [bp-18h]@1
  Vec3_int_ *v15; // [sp+14h] [bp-10h]@1
  int v16; // [sp+18h] [bp-Ch]@2
  int v17; // [sp+20h] [bp-4h]@10
  int a4b; // [sp+30h] [bp+Ch]@2
  int a4c; // [sp+30h] [bp+Ch]@9
  signed int a4a; // [sp+30h] [bp+Ch]@10

  v4 = a4;
  v15 = a2;
  v14 = a1;
  if ( BYTE3(a4->uAttributes) & 0x20
    || (v5 = (unsigned __int64)(a2->x * (signed __int64)a4->pFacePlane_old.vNormal.x) >> 16,
        a4b = (unsigned __int64)(a2->y * (signed __int64)a4->pFacePlane_old.vNormal.y) >> 16,
        v6 = (unsigned __int64)(a2->z * (signed __int64)v4->pFacePlane_old.vNormal.z) >> 16,
        v7 = v5 + v6 + a4b,
        (v16 = v5 + v6 + a4b) == 0)
    || v7 > 0 && !v4->Portal())
    return 0;
  v8 = v4->pFacePlane_old.vNormal.z * a1->z;
  v9 = -(v4->pFacePlane_old.dist + v8 + a1->y * v4->pFacePlane_old.vNormal.y + a1->x * v4->pFacePlane_old.vNormal.x);
  if ( v7 <= 0 )
  {
    if ( v4->pFacePlane_old.dist + v8 + a1->y * v4->pFacePlane_old.vNormal.y + a1->x * v4->pFacePlane_old.vNormal.x < 0 )
      return 0;
  }
  else
  {
    if ( v9 < 0 )
      return 0;
  }
  a4c = abs(-(v4->pFacePlane_old.dist + v8 + a1->y * v4->pFacePlane_old.vNormal.y + a1->x * v4->pFacePlane_old.vNormal.x)) >> 14;
  if ( a4c > abs(v7)
    || (LODWORD(v10) = v9 << 16, HIDWORD(v10) = v9 >> 16, a4a = v10 / v16, v17 = v10 / v16, v17 > *a3 << 16)
    || (v11 = v14,
        LOWORD(v12) = LOWORD(v14->x)
                    + (((unsigned int)((unsigned __int64)(v17 * (signed __int64)v15->x) >> 16) + 32768) >> 16),
        HIWORD(v12) = LOWORD(v11->y)
                    + (((unsigned int)((unsigned __int64)(v17 * (signed __int64)v15->y) >> 16) + 32768) >> 16),
        !sub_475665(
           v4,
           v12,
           LOWORD(v11->z) + (((unsigned int)((unsigned __int64)(v17 * (signed __int64)v15->z) >> 16) + 32768) >> 16))) )
    return 0;
  *a3 = a4a >> 16;
  return 1;
}

//----- (00475F30) --------------------------------------------------------
bool __fastcall sub_475F30(int *a1, BLVFace *a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9)
{
  BLVFace *v9; // ebx@1
  int v10; // ST20_4@2
  int v11; // ST28_4@2
  int v12; // ST24_4@2
  char v13; // zf@2
  int v14; // edi@2
  int v15; // eax@5
  signed int v16; // esi@5
  int v17; // ST20_4@9
  signed __int64 v18; // qtt@10
  int v19; // ST14_4@11
  int *v21; // [sp+14h] [bp-10h]@1
  int v22; // [sp+1Ch] [bp-8h]@2
  int v23; // [sp+1Ch] [bp-8h]@10
  signed int v24; // [sp+20h] [bp-4h]@10

  v9 = a2;
  v21 = a1;
  if ( BYTE3(a2->uAttributes) & 0x20
    || (v10 = (unsigned __int64)(a6 * (signed __int64)a2->pFacePlane_old.vNormal.x) >> 16,
        v11 = (unsigned __int64)(a7 * (signed __int64)a2->pFacePlane_old.vNormal.y) >> 16,
        v12 = (unsigned __int64)(a8 * (signed __int64)a2->pFacePlane_old.vNormal.z) >> 16,
        v13 = v10 + v12 + v11 == 0,
        v14 = v10 + v12 + v11,
        v22 = v10 + v12 + v11,
        v13)
    || v14 > 0 && !a2->Portal())
    return 0;
  v15 = a4 * a2->pFacePlane_old.vNormal.y;
  v16 = -(a2->pFacePlane_old.dist + v15 + a3 * a2->pFacePlane_old.vNormal.x + a5 * a2->pFacePlane_old.vNormal.z);
  if ( v14 <= 0 )
  {
    if ( a2->pFacePlane_old.dist + v15 + a3 * a2->pFacePlane_old.vNormal.x + a5 * a2->pFacePlane_old.vNormal.z < 0 )
      return 0;
  }
  else
  {
    if ( v16 < 0 )
      return 0;
  }
  v17 = abs(-(a2->pFacePlane_old.dist + v15 + a3 * a2->pFacePlane_old.vNormal.x + a5 * a2->pFacePlane_old.vNormal.z)) >> 14;
  if ( v17 > abs(v14)
    || (LODWORD(v18) = v16 << 16, HIDWORD(v18) = v16 >> 16, v24 = v18 / v22, v23 = v18 / v22, v23 > *v21 << 16)
    || (LOWORD(v19) = a3 + (((unsigned int)((unsigned __int64)(v23 * (signed __int64)a6) >> 16) + 32768) >> 16),
        HIWORD(v19) = a4 + (((unsigned int)((unsigned __int64)(v23 * (signed __int64)a7) >> 16) + 32768) >> 16),
        !sub_4759C9(
           v9,
           a9,
           v19,
           a5 + (((unsigned int)((unsigned __int64)(v23 * (signed __int64)a8) >> 16) + 32768) >> 16))) )
    return 0;
  *v21 = v24 >> 16;
  return 1;
}

//----- (004760D5) --------------------------------------------------------
PartyAction ActionQueue::Next()
{
  if (!uNumActions)
    return PARTY_INVALID;

  auto result = pActions[0];
  for (unsigned int i = 0; i < uNumActions - 1; ++i)
    pActions[i] = pActions[i + 1];
  --uNumActions;

  return result;
}

//----- (004775ED) --------------------------------------------------------
int stru6_stru1_indoor_sw_billboard::_4775ED(float a2)
{
  char *v2; // edi@1
  int v3; // eax@1
  char *v4; // edx@2
  char *v5; // esi@3
  double v6; // st7@6
  signed __int64 v7; // ST84_8@6
  double v8; // ST0C_8@6
  int v9; // esi@6
  double v10; // ST44_8@6
  int v11; // ecx@6
  double v12; // ST34_8@6
  int v13; // ecx@6
  double v14; // ST14_8@6
  double v15; // st7@8
  unsigned int v16; // ecx@8
  signed __int64 v17; // ST64_8@8
  double v18; // ST24_8@8
  int v19; // edi@8
  double v20; // ST3C_8@8
  int v21; // ecx@8
  double v22; // ST2C_8@8
  int v23; // ST9C_4@8
  double v24; // ST1C_8@8
  int *v25; // edi@8
  int v26; // esi@8
  int *v27; // edi@10
  int v28; // esi@10
  int result; // eax@12
  __int64 v30; // [sp+A8h] [bp-30h]@8
  float v31; // [sp+B0h] [bp-28h]@6
  float v32; // [sp+B4h] [bp-24h]@6
  int v33; // [sp+B8h] [bp-20h]@6
  int v34; // [sp+BCh] [bp-1Ch]@2
  stru6_stru1_indoor_sw_billboard *v35; // [sp+C0h] [bp-18h]@1
  float v36; // [sp+C4h] [bp-14h]@6
  int v37; // [sp+C8h] [bp-10h]@6
  int v38; // [sp+CCh] [bp-Ch]@1
  float v39; // [sp+D0h] [bp-8h]@6
  int *v40; // [sp+D4h] [bp-4h]@2

  v2 = (char *)&this->field_64[4 * this->uNumVertices];
  v38 = 0;
  *(int *)v2 = this->field_64[0];
  v2 += 4;
  *(int *)v2 = this->field_64[1];
  v2 += 4;
  *(int *)v2 = this->field_64[2];
  *((int *)v2 + 1) = this->field_64[3];
  v3 = this->uNumVertices;
  v35 = this;
  if ( v3 > 0 )
  {
    v40 = &this->field_64[20];
    v4 = (char *)&this->field_64[3] + 3;
    v34 = v3;
    while ( 1 )
    {
      v5 = v4 - 15;
      if ( *(float *)(v4 - 15) <= (double)a2 && *(float *)(v4 + 1) <= (double)a2 )
	  {
        v4 += 16;
		--v34;
		if ( !v34 )
		  return this->uNumVertices = v38;
		continue;
	  }
      if ( *(float *)v5 <= (double)a2 )
	  {
		v6 = (a2 - *(float *)v5) / (*(float *)(v4 + 1) - *(float *)v5);
		v7 = (unsigned __int8)v4[16] - (unsigned int)(unsigned __int8)*v4;
		v36 = v6;
		v31 = (*(float *)(v4 + 5) - *(float *)(v4 - 11)) * v6 + *(float *)(v4 - 11);
		v32 = (*(float *)(v4 + 9) - *(float *)(v4 - 7)) * v6 + *(float *)(v4 - 7);
		*(float *)&v37 = (double)v7 * v6;
		v8 = *(float *)&v37 + 6.7553994e15;
		v9 = (unsigned __int8)*v4;
		*(float *)&v37 = (double)((unsigned __int8)v4[15] - (unsigned int)(unsigned __int8)*(v4 - 1)) * v36;
		v10 = *(float *)&v37 + 6.7553994e15;
		v11 = (unsigned __int8)*(v4 - 2);
		v37 = LODWORD(v10) + (unsigned __int8)*(v4 - 1);
		v39 = (double)((unsigned int)(unsigned __int8)v4[14] - v11) * v36;
		v12 = v39 + 6.7553994e15;
		v13 = LODWORD(v12) + (unsigned __int8)*(v4 - 2);
		v39 = (double)((*(int *)(v4 + 13) & 0xFF) - (*(int *)(v4 - 3) & 0xFFu)) * v36;
		v14 = v39 + 6.7553994e15;
		v33 = (LODWORD(v14) + (*(int *)(v4 - 3) & 0xFF)) | ((v13 | ((v37 | ((LODWORD(v8) + v9) << 8)) << 8)) << 8);
		//this = v35;
		v5 = (char *)&v30 + 4;
	  }
      else if ( *(float *)(v4 + 1) <= (double)a2 )
      {
        v15 = (a2 - *(float *)v5) / (*(float *)(v4 + 1) - *(float *)v5);
        v16 = (unsigned __int8)*v4;
        HIDWORD(v30) = LODWORD(a2);
        v17 = (unsigned __int8)v4[16] - v16;
        v36 = v15;
        v31 = (*(float *)(v4 + 5) - *(float *)(v4 - 11)) * v15 + *(float *)(v4 - 11);
        v32 = (*(float *)(v4 + 9) - *(float *)(v4 - 7)) * v15 + *(float *)(v4 - 7);
        v39 = (double)v17 * v15;
        v18 = v39 + 6.7553994e15;
        v19 = (unsigned __int8)*v4;
        v39 = (double)((unsigned __int8)v4[15] - (unsigned int)(unsigned __int8)*(v4 - 1)) * v36;
        v20 = v39 + 6.7553994e15;
        v21 = (unsigned __int8)*(v4 - 2);
        v37 = LODWORD(v20) + (unsigned __int8)*(v4 - 1);
        v39 = (double)((unsigned int)(unsigned __int8)v4[14] - v21) * v36;
        v22 = v39 + 6.7553994e15;
        v23 = LODWORD(v22) + (unsigned __int8)*(v4 - 2);
        v39 = (double)((*(int *)(v4 + 13) & 0xFF) - (*(int *)(v4 - 3) & 0xFFu)) * v36;
        v24 = v39 + 6.7553994e15;
        v33 = (LODWORD(v24) + (*(int *)(v4 - 3) & 0xFF)) | ((v23 | ((v37 | ((LODWORD(v18) + v19) << 8)) << 8)) << 8);
        v25 = v40;
        *v40 = *(int *)v5;
        v26 = (int)(v5 + 4);
        ++v25;
        *v25 = *(int *)v26;
        v26 += 4;
        ++v25;
        ++v38;
        v40 += 4;
        *v25 = *(int *)v26;
        v25[1] = *(int *)(v26 + 4);
		v5 = (char *)&v30 + 4;
      }
      v27 = v40;
      ++v38;
      *v40 = *(int *)v5;
      v28 = (int)(v5 + 4);
      ++v27;
      *v27 = *(int *)v28;
      v28 += 4;
      ++v27;
      v40 += 4;
      *v27 = *(int *)v28;
      v27[1] = *(int *)(v28 + 4);
      v4 += 16;
      --v34;
      if ( !v34 )
          return this->uNumVertices = v38;
    }
  }
  return this->uNumVertices = v38;
}

//----- (00477927) --------------------------------------------------------
int stru6_stru1_indoor_sw_billboard::_477927(float a2)
{
  char *v2; // edi@1
  int v3; // eax@1
  char *v4; // edx@2
  char *v5; // esi@3
  double v6; // st7@6
  signed __int64 v7; // ST84_8@6
  double v8; // ST0C_8@6
  int v9; // esi@6
  double v10; // ST44_8@6
  int v11; // ecx@6
  double v12; // ST34_8@6
  int v13; // ecx@6
  double v14; // ST14_8@6
  double v15; // st7@8
  unsigned int v16; // ecx@8
  signed __int64 v17; // ST64_8@8
  double v18; // ST24_8@8
  int v19; // edi@8
  double v20; // ST3C_8@8
  int v21; // ecx@8
  double v22; // ST2C_8@8
  int v23; // ST9C_4@8
  double v24; // ST1C_8@8
  int *v25; // edi@8
  int v26; // esi@8
  int *v27; // edi@10
  int v28; // esi@10
  int result; // eax@12
  __int64 v30; // [sp+A8h] [bp-30h]@8
  float v31; // [sp+B0h] [bp-28h]@6
  float v32; // [sp+B4h] [bp-24h]@6
  int v33; // [sp+B8h] [bp-20h]@6
  int v34; // [sp+BCh] [bp-1Ch]@2
  stru6_stru1_indoor_sw_billboard *v35; // [sp+C0h] [bp-18h]@1
  float v36; // [sp+C4h] [bp-14h]@6
  int v37; // [sp+C8h] [bp-10h]@6
  int v38; // [sp+CCh] [bp-Ch]@1
  float v39; // [sp+D0h] [bp-8h]@6
  int *v40; // [sp+D4h] [bp-4h]@2

  v2 = (char *)&this->field_64[4 * this->uNumVertices];
  v38 = 0;
  *(int *)v2 = this->field_64[0];
  v2 += 4;
  *(int *)v2 = this->field_64[1];
  v2 += 4;
  *(int *)v2 = this->field_64[2];
  *((int *)v2 + 1) = this->field_64[3];
  v3 = this->uNumVertices;
  v35 = this;
  if ( v3 > 0 )
  {
    v40 = &this->field_64[20];
    v4 = (char *)&this->field_64[3] + 3;
    v34 = v3;
    while ( 1 )
    {
      v5 = v4 - 15;
      if ( *(float *)(v4 - 15) >= (double)a2 && *(float *)(v4 + 1) >= (double)a2 )
	  {
        v4 += 16;
		--v34;
		if ( !v34 )
          return this->uNumVertices = v38;
		continue;
	  }
      if ( *(float *)v5 >= (double)a2 )
	  {
		v6 = (a2 - *(float *)v5) / (*(float *)(v4 + 1) - *(float *)v5);
		v7 = (unsigned __int8)v4[16] - (unsigned int)(unsigned __int8)*v4;
		v36 = v6;
		v31 = (*(float *)(v4 + 5) - *(float *)(v4 - 11)) * v6 + *(float *)(v4 - 11);
		v32 = (*(float *)(v4 + 9) - *(float *)(v4 - 7)) * v6 + *(float *)(v4 - 7);
		*(float *)&v37 = (double)v7 * v6;
		v8 = *(float *)&v37 + 6.7553994e15;
		v9 = (unsigned __int8)*v4;
		*(float *)&v37 = (double)((unsigned __int8)v4[15] - (unsigned int)(unsigned __int8)*(v4 - 1)) * v36;
		v10 = *(float *)&v37 + 6.7553994e15;
		v11 = (unsigned __int8)*(v4 - 2);
		v37 = LODWORD(v10) + (unsigned __int8)*(v4 - 1);
		v39 = (double)((unsigned int)(unsigned __int8)v4[14] - v11) * v36;
		v12 = v39 + 6.7553994e15;
		v13 = LODWORD(v12) + (unsigned __int8)*(v4 - 2);
		v39 = (double)((*(int *)(v4 + 13) & 0xFF) - (*(int *)(v4 - 3) & 0xFFu)) * v36;
		v14 = v39 + 6.7553994e15;
		v33 = (LODWORD(v14) + (*(int *)(v4 - 3) & 0xFF)) | ((v13 | ((v37 | ((LODWORD(v8) + v9) << 8)) << 8)) << 8);
		//this = v35;
		v5 = (char *)&v30 + 4;
	  }
      else if ( *(float *)(v4 + 1) >= (double)a2 )
      {
        v15 = (a2 - *(float *)v5) / (*(float *)(v4 + 1) - *(float *)v5);
        v16 = (unsigned __int8)*v4;
        HIDWORD(v30) = LODWORD(a2);
        v17 = (unsigned __int8)v4[16] - v16;
        v36 = v15;
        v31 = (*(float *)(v4 + 5) - *(float *)(v4 - 11)) * v15 + *(float *)(v4 - 11);
        v32 = (*(float *)(v4 + 9) - *(float *)(v4 - 7)) * v15 + *(float *)(v4 - 7);
        v39 = (double)v17 * v15;
        v18 = v39 + 6.7553994e15;
        v19 = (unsigned __int8)*v4;
        v39 = (double)((unsigned __int8)v4[15] - (unsigned int)(unsigned __int8)*(v4 - 1)) * v36;
        v20 = v39 + 6.7553994e15;
        v21 = (unsigned __int8)*(v4 - 2);
        v37 = LODWORD(v20) + (unsigned __int8)*(v4 - 1);
        v39 = (double)((unsigned int)(unsigned __int8)v4[14] - v21) * v36;
        v22 = v39 + 6.7553994e15;
        v23 = LODWORD(v22) + (unsigned __int8)*(v4 - 2);
        v39 = (double)((*(int *)(v4 + 13) & 0xFF) - (*(int *)(v4 - 3) & 0xFFu)) * v36;
        v24 = v39 + 6.7553994e15;
        v33 = (LODWORD(v24) + (*(int *)(v4 - 3) & 0xFF)) | ((v23 | ((v37 | ((LODWORD(v18) + v19) << 8)) << 8)) << 8);
        v25 = v40;
        *v40 = *(int *)v5;
        v26 = (int)(v5 + 4);
        ++v25;
        *v25 = *(int *)v26;
        v26 += 4;
        ++v25;
        ++v38;
        v40 += 4;
        *v25 = *(int *)v26;
        v25[1] = *(int *)(v26 + 4);
	    v5 = (char *)&v30 + 4;
      }
      v27 = v40;
      ++v38;
      *v40 = *(int *)v5;
      v28 = (int)(v5 + 4);
      ++v27;
      *v27 = *(int *)v28;
      v28 += 4;
      ++v27;
      v40 += 4;
      *v27 = *(int *)v28;
      v27[1] = *(int *)(v28 + 4);
      v4 += 16;
      --v34;
      if ( !v34 )
          return this->uNumVertices = v38;
    }
  }
  return this->uNumVertices = v38;
}

//----- (00477C61) --------------------------------------------------------
int stru6_stru1_indoor_sw_billboard::sub_477C61()
{
  //stru6_stru1_indoor_sw_billboard *v1; // ebx@1
  int v2; // ecx@2
  int v3; // eax@3
  double v4; // st7@4
  double v5; // st7@5
  double v6; // st6@5
  double v7; // st5@6
  float v8; // ST30_4@8
  float v9; // ST24_4@8
  double v10; // st7@8
  double v11; // st6@8
  double v12; // st5@8
  float v13; // ST24_4@13
  int v14; // esi@13
  char *v15; // esi@15
  //signed int v16; // eax@16
  __int16 v17; // fps@16
  unsigned __int8 v18; // c2@16
  unsigned __int8 v19; // c3@16
  double v20; // st6@16
  float v21; // ST18_4@17
  float v22; // ST2C_4@17
  float v23; // ST34_4@17
  float v24; // ST24_4@17
  double v25; // st7@17
  double v26; // st6@17
  float v27; // ST34_4@18
  float v28; // ST30_4@18
  int v29; // eax@19
  signed int v31; // [sp+8h] [bp-28h]@15
  float v32; // [sp+Ch] [bp-24h]@16
  float v33; // [sp+14h] [bp-1Ch]@16
  float v34; // [sp+18h] [bp-18h]@16
  float v35; // [sp+1Ch] [bp-14h]@17
  float v36; // [sp+20h] [bp-10h]@4
  float v37; // [sp+24h] [bp-Ch]@4
  float v38; // [sp+24h] [bp-Ch]@16
  float v39; // [sp+28h] [bp-8h]@9
  float v40; // [sp+28h] [bp-8h]@16
  float v41; // [sp+2Ch] [bp-4h]@6
  float v42; // [sp+2Ch] [bp-4h]@9

  //v1 = this;
  if ( uCurrentlyLoadedLevelType == LEVEL_Indoor )
  {
    v2 = 0;
    if ( this->uNumVertices > 0 )
    {
      v3 = (int)&this->field_14[1];
      do
      {
        v4 = *(float *)(v3 - 4);
        LODWORD(v37) = *(int *)v3;
        LODWORD(v36) = *(int *)(v3 + 4);
        if (pGame->pIndoorCameraD3D->sRotationX)
        {
          v5 = v4 - (double)pGame->pIndoorCameraD3D->vPartyPos.x;
          v6 = v37 - (double)pGame->pIndoorCameraD3D->vPartyPos.y;
          //if ( pRenderer->pRenderD3D )
          //{
            v41 = pGame->pIndoorCameraD3D->fRotationYSine * v6 + pGame->pIndoorCameraD3D->fRotationYCosine * v5;
            v7 = pGame->pIndoorCameraD3D->fRotationYSine * v5 - pGame->pIndoorCameraD3D->fRotationYCosine * v6;
          /*}
          else
          {
            v41 = pBLVRenderParams->fCosineY * v5 - pBLVRenderParams->fSineY * v6;
            v7 = pBLVRenderParams->fSineY * v5 + pBLVRenderParams->fCosineY * v6;
          }*/
          v8 = v7;
          v9 = v36 - (double)pGame->pIndoorCameraD3D->vPartyPos.z;
          v10 = pGame->pIndoorCameraD3D->fRotationXCosine * v41 - pGame->pIndoorCameraD3D->fRotationXSine * v9;
          v11 = v8;
          v12 = pGame->pIndoorCameraD3D->fRotationXCosine * v9 + pGame->pIndoorCameraD3D->fRotationXSine * v41;
        }
        else
        {
          v42 = v4 - (double)pGame->pIndoorCameraD3D->vPartyPos.x;
          v39 = v37 - (double)pGame->pIndoorCameraD3D->vPartyPos.y;
          //if ( pRenderer->pRenderD3D )
          //{
            v10 = pGame->pIndoorCameraD3D->fRotationYSine * v39 + pGame->pIndoorCameraD3D->fRotationYCosine * v42;
            v11 = pGame->pIndoorCameraD3D->fRotationYSine * v42 - pGame->pIndoorCameraD3D->fRotationYCosine * v39;
          /*}
          else
          {
            v10 = pBLVRenderParams->fCosineY * v42 - pBLVRenderParams->fSineY * v39;
            v11 = pBLVRenderParams->fSineY * v42 + pBLVRenderParams->fCosineY * v39;
          }*/
          v12 = v36 - (double)pGame->pIndoorCameraD3D->vPartyPos.z;
        }
        v13 = v12;
        ++v2;
        *(int *)(v3 + 84) = LODWORD(v13);
        v14 = *(int *)(v3 + 8);
        *(float *)(v3 + 76) = v10;
        *(int *)(v3 + 88) = v14;
        *(float *)(v3 + 80) = v11;
        v3 += 16;
      }
      while ( v2 < this->uNumVertices );
    }
  }
  else
  {
    v15 = (char *)&this->field_14[1];
    v31 = 3;
    do
    {
      v40 = (double)stru_5C6E00->Cos(pGame->pIndoorCameraD3D->sRotationX) * 0.0000152587890625;
      v32 = (double)stru_5C6E00->Sin(pGame->pIndoorCameraD3D->sRotationX) * 0.0000152587890625;
      v34 = (double)stru_5C6E00->Cos(pGame->pIndoorCameraD3D->sRotationY) * 0.0000152587890625;
      v33 = (double)stru_5C6E00->Sin(pGame->pIndoorCameraD3D->sRotationY) * 0.0000152587890625;
      //v16 = stru_5C6E00->Sin(pODMRenderParams->rotation_y);
      LODWORD(v38) = *(int *)v15;
      //UNDEF(v17);
      v20 = *((float *)v15 - 1) - (double)pGame->pIndoorCameraD3D->vPartyPos.x;
      //if ( v19 | v18 )
	  if (pGame->pIndoorCameraD3D->vPartyPos.x == 0)
      {
        v27 = v20;
        LODWORD(v35) = *((int *)v15 + 1);
        v28 = v38 - (double)pGame->pIndoorCameraD3D->vPartyPos.y;
        v25 = v33 * v28 + v34 * v27;
        v26 = v34 * v28 - v33 * v27;
      }
      else
      {
        v21 = v20;
        v22 = v38 - (double)pGame->pIndoorCameraD3D->vPartyPos.y;
        v23 = v33 * v22 + v34 * v21;
        v24 = *((float *)v15 + 1) - (double)pGame->pIndoorCameraD3D->vPartyPos.z;
        v25 = v32 * v24 + v40 * v23;
        v26 = v34 * v22 - v33 * v21;
        v35 = v40 * v24 - v32 * v23;
      }
      *((int *)v15 + 21) = LODWORD(v35);
      v29 = *((int *)v15 + 2);
      *((float *)v15 + 19) = v25;
      *((int *)v15 + 22) = v29;
      *((float *)v15 + 20) = v26;
      v15 += 16;
      --v31;
    }
    while ( v31 );
  }
  this->uNumVertices = 3;
  return 1;
}

//----- (00477F63) --------------------------------------------------------
bool stru6_stru1_indoor_sw_billboard::sub_477F63()
{
  signed int v1; // ebx@1
  stru6_stru1_indoor_sw_billboard *v2; // esi@1
  double v3; // st7@2
  int v4; // edx@4
  char *v5; // ecx@5
  int v6; // edi@5
  float v7; // ST08_4@13
  signed int v9; // [sp+Ch] [bp-8h]@1
  float v10; // [sp+10h] [bp-4h]@2

  auto a1 = this;

  v1 = 0;
  v2 = a1;
  v9 = 0;
  if ( uCurrentlyLoadedLevelType == LEVEL_Indoor )
  {
    v10 = 16192.0;
    v3 = (double)pBLVRenderParams->fov_rad_fixpoint * 0.000015258789;
  }
  else
  {
    v10 = (double)pODMRenderParams->shading_dist_mist;
    v3 = 8.0;
  }
  v4 = a1->uNumVertices;
  if ( v4 <= 0 )
  {
    memcpy(&v2->field_14[40], &v2->field_14[20], 16 * v4);
    return v2->uNumVertices != 0;
  }
  v5 = (char *)&a1->field_14[20];
  v6 = v4;
  do
  {
    if ( v3 >= *(float *)v5 || *(float *)v5 >= (double)v10 )
    {
      if ( v3 < *(float *)v5 )
        v9 = 1;
      else
        v1 = 1;
    }
    v5 += 16;
    --v6;
  }
  while ( v6 );
  if ( !v1 )
  {
    if ( v9 )
    {
      v2->_477927(v10);
      return v2->uNumVertices != 0;
    }
    memcpy(&v2->field_14[40], &v2->field_14[20], 16 * v4);
    return v2->uNumVertices != 0;
  }
  v7 = v3;
  _4775ED(v7);
  return v2->uNumVertices != 0;
}

//----- (0047802A) --------------------------------------------------------
int stru6_stru1_indoor_sw_billboard::sub_47802A()
{
  double v6; // st7@4
  double v12; // st7@16
  signed int v16; // [sp+38h] [bp-Ch]@1
  int a6; // [sp+3Ch] [bp-8h]@5
  int a5; // [sp+40h] [bp-4h]@5

  auto a1 = this;

  v16 = 0;
  if ( uCurrentlyLoadedLevelType == LEVEL_Indoor )
  {
	for(int i = 0; i < a1->uNumVertices; i++)
    {
		v6 = (double)pBLVRenderParams->fov_rad_fixpoint * 0.000015258789 / a1->field_B4[i*4];
		if ( pRenderer->pRenderD3D )
		{
			pGame->pIndoorCameraD3D->Project(
				round(a1->field_B4[i*4]),
				round(a1->field_B4[i*4+1]),
				round(a1->field_B4[i*4+2]),
				&a5,
				&a6);
			a1->field_B4[i*4+16] = (double)a5;
			a1->field_B4[i*4+17] = (double)a6;
			a1->field_B4[i*4+18] = round(a1->field_B4[i*4]);
		}
		else
		{
			a1->field_B4[i*4+16] = (double)pBLVRenderParams->uViewportCenterX - v6 * a1->field_B4[i*4+1];
			a1->field_B4[i*4+17] = (double)pBLVRenderParams->uViewportCenterY - v6 * a1->field_B4[i*4+2];
			a1->field_B4[i*4+18] = a1->field_B4[i*4];
		}
		a1->field_B4[i*4+19] = a1->field_B4[i*4+3];
		if ( (double)(signed int)pViewport->uViewportTL_X <= a1->field_B4[i*4+16]
			&& (double)(signed int)pViewport->uViewportBR_X > a1->field_B4[i*4+16]
			&& (double)(signed int)pViewport->uViewportTL_Y <= a1->field_B4[i*4+17]
			&& (double)(signed int)pViewport->uViewportBR_Y > a1->field_B4[i*4+17] )
			v16 = 1;
    }
  }
  else
  {
	for(int i = 0; i < a1->uNumVertices; i++)
    {
		v12 = (double)pODMRenderParams->int_fov_rad / a1->field_B4[i*4];
		a1->field_B4[i*4+20] = (double)pViewport->uScreenCenterX - v12 * a1->field_B4[i*4+1];
		a1->field_B4[i*4+21] = (double)pViewport->uScreenCenterY - v12 * a1->field_B4[i*4+2];
		*((int *)&a1->field_B4[i*4+22]) = (int)a1->field_B4[i*4];
		*((int *)&a1->field_B4[i*4+23]) = a1->field_B4[i*4+3];
		if ( (double)(signed int)pViewport->uViewportTL_X <= a1->field_B4[i*4+20]
			&& (double)(signed int)pViewport->uViewportBR_X > a1->field_B4[i*4+20]
			&& (double)(signed int)pViewport->uViewportTL_Y <= a1->field_B4[i*4+21]
			&& (double)(signed int)pViewport->uViewportBR_Y > a1->field_B4[i*4+21] )
			v16 = 1;
    }
  }
  return v16;
}

// 73C84C: using guessed type char static_RenderBuildingsD3D_byte_73C84C_init_flag;

//----- (00479089) --------------------------------------------------------
bool __fastcall IsBModelVisible(unsigned int uModelID, int *reachable)
{
  BSPModel *v2; // eax@1
  int v3; // edi@1
  int v4; // ebx@1
  int v5; // ST28_4@1
  int v6; // ecx@1
  int v7; // ebx@3
  int v8; // eax@3
  int v9; // eax@3
  //int v10; // ebx@3
  signed int v11; // esi@6
  int v12; // esi@8
  bool result; // eax@9
  //unsigned int v14; // [sp+Ch] [bp-20h]@1
  int v15; // [sp+Ch] [bp-20h]@5
  //int *v16; // [sp+10h] [bp-1Ch]@1
  int v17; // [sp+1Ch] [bp-10h]@1
  int v18; // [sp+20h] [bp-Ch]@1
  int v19; // [sp+20h] [bp-Ch]@3
  int angle; // [sp+24h] [bp-8h]@1
  int v21; // [sp+28h] [bp-4h]@1
  //int v22; // [sp+28h] [bp-4h]@3

  //v16 = unused;
  angle = (signed int)(pODMRenderParams->uCameraFovInDegrees << 11) / 360 >> 1;
  //v14 = uModelID;
  v2 = &pOutdoor->pBModels[uModelID];
  v3 = v2->vBoundingCenter.x - pGame->pIndoorCameraD3D->vPartyPos.x;
  v4 = v2->vBoundingCenter.y - pGame->pIndoorCameraD3D->vPartyPos.y;
  v5 = stru_5C6E00->Cos(pGame->pIndoorCameraD3D->sRotationY);
  v21 = stru_5C6E00->Sin(pGame->pIndoorCameraD3D->sRotationY);
  v18 = stru_5C6E00->Cos(pGame->pIndoorCameraD3D->sRotationX);
  stru_5C6E00->Sin(pGame->pIndoorCameraD3D->sRotationX);
  v6 = v5;
  v17 = v3 * v5 + v4 * v21;
  if (pGame->pIndoorCameraD3D->sRotationX)
    v17 = (unsigned __int64)(v17 * (signed __int64)v18) >> 16;
  v19 = v4 * v6 - v3 * v21;
  v7 = abs(v4);
  v8 = abs(v3);
  v9 = int_get_vector_length(v8, v7, 0);
  //v10 = v14 * 188;
  //v22 = v9;
  *reachable = false;
  if ( v9 < pOutdoor->pBModels[uModelID].sBoundingRadius + 256 )
    *reachable = true;
  v15 = stru_5C6E00->Sin(angle);
  if ( v19 >= 0 )
    v11 = ((unsigned __int64)(v15 * (signed __int64)v17) >> 16) - ((unsigned __int64)(stru_5C6E00->Cos(angle) * (signed __int64)v19) >> 16);
  else
    v11 = ((unsigned __int64)(stru_5C6E00->Cos(angle) * (signed __int64)v19) >> 16) + ((unsigned __int64)(v15 * (signed __int64)v17) >> 16);
  v12 = v11 >> 16;
  if ( v9 <= pODMRenderParams->shading_dist_mist + 2048 )
  {
    //if ( abs(v12) > *(int *)((char *)&pOutdoor->pBModels->sBoundingRadius + v10) + 512 )
	if ( abs(v12) > pOutdoor->pBModels[uModelID].sBoundingRadius + 512 )
    {
      result = v12 < 0;
      LOBYTE(result) = v12 >= 0;
      return result;
    }
    else
      return true;
  }
  return false;
}

//----- (00479295) --------------------------------------------------------
int Polygon::_479295()
{
  ODMFace *v2; // esi@1
  int v3; // ecx@4
  int v4; // eax@4
  int v5; // edx@4
  int v6; // ST14_4@5
  int v7; // ST04_4@5
  stru149 *v8; // ecx@5
  Vec3_int_ thisa; // [sp+Ch] [bp-10h]@8
  int v11; // [sp+18h] [bp-4h]@4

  v2 = this->pODMFace;
  if ( !v2->pFacePlane.vNormal.z )
  {
    v3 = v2->pFacePlane.vNormal.x;
    v4 = -v2->pFacePlane.vNormal.y;
    v5 = 0;
    v11 = 65536;
  }
  else if ( (v2->pFacePlane.vNormal.x || v2->pFacePlane.vNormal.y) && abs(v2->pFacePlane.vNormal.z) < 59082 )
  {
    thisa.x = -v2->pFacePlane.vNormal.y;
    thisa.y = v2->pFacePlane.vNormal.x;
    thisa.z = 0;
    thisa.Normalize_float();
    v4 = thisa.x;
    v3 = thisa.y;
    v5 = 0;
    v11 = 65536;
  }
  else
  {
	  v3 = 0;
	  v4 = 65536;
	  v11 = 0;
	  v5 = -65536;
  }
  v6 = v11;
  sTextureDeltaU = v2->sTextureDeltaU;
  v7 = v3;
  v8 = ptr_38;
  sTextureDeltaV = v2->sTextureDeltaV;
  v8->_48616B_frustum_odm(v4, v7, 0, 0, v5, v6);
  return 1;
}


unsigned short *LoadTgaTexture(const wchar_t *filename, int *out_width = nullptr, int *out_height = nullptr)
{
  #pragma pack(push, 1)
    struct TGAHeader
    {
      unsigned char  tgaSkip;
      unsigned char  colourmaptype;      // type of colour map 0=none, 1=has palette
      unsigned char  tgaType;            // type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed

      short colourmapstart;     // first colour map entry in palette
      short colourmaplength;    // number of colours in palette
      char  colourmapbits;      // number of bits per palette entry 15,16,24,32

      //unsigned char  tgaDontCare2[9];
      short xstart;             // image x origin
      short ystart;             // image y origin

      unsigned short tgaWidth;
      unsigned short tgaHeight;
      unsigned char  tgaBPP;

      char  descriptor;         // image descriptor bits:   00vhaaaa
        //      h horizontal flip
        //      v vertical flip
        //      a alpha bits
    };
  #pragma pack(pop)

  if (out_width)
    *out_width = 0;
  if (out_height)
    *out_height = 0;

  DWORD w;
  auto  file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
  if (file == INVALID_HANDLE_VALUE)
    return nullptr;

  TGAHeader header;
  ReadFile(file, &header, sizeof(header), &w, nullptr);
  SetFilePointer(file, header.tgaSkip, nullptr, FILE_CURRENT);

  if (header.tgaBPP != 24 || header.tgaType != 2)
  {
    CloseHandle(file);
    return nullptr;
  }

  int imgSize = header.tgaWidth * header.tgaHeight * 3;
  auto pixels = new unsigned char[imgSize];
  ReadFile(file, pixels, imgSize, &w, nullptr);
  CloseHandle(file);

  if (w != imgSize)
  {
    delete [] pixels;
    return nullptr;
  }

  if (out_width)
    *out_width = header.tgaWidth;
  if (out_height)
    *out_height = header.tgaHeight;

  auto pixels_16bit = new unsigned short[imgSize / 3];
  for (int i = 0; i < imgSize / 3; ++i)
  {
    pixels_16bit[i] = (pixels[i * 3] / 8 & 0x1F) |
                      ((pixels[i * 3 + 1] / 4 & 0x3F) << 5) |
                      ((pixels[i * 3 + 2] / 8 & 0x1F) << 11);
  }
  delete [] pixels;
  return pixels_16bit;
}

unsigned short *skybox_xn, *skybox_xp,
              *skybox_yn, *skybox_yp,
              *skybox_zn, *skybox_zp;
int            skybox_width, skybox_height;

IDirect3DTexture2   *skybox_texture;
IDirectDrawSurface4 *skybox_surface;

bool Skybox_Initialize(const wchar_t *skybox_name)
{
  wchar_t xn_filename[1024], xp_filename[1024],
          yn_filename[1024], yp_filename[1024],
          zn_filename[1024], zp_filename[1024];
  swprintf(xn_filename, wcslen(L"%s_xn.tga"), L"%s_xn.tga", skybox_name); swprintf(xp_filename, wcslen(L"%s_xp.tga"), L"%s_xp.tga", skybox_name);
  swprintf(yn_filename, wcslen(L"%s_yn.tga"), L"%s_yn.tga", skybox_name); swprintf(yp_filename, wcslen(L"%s_yp.tga"), L"%s_yp.tga", skybox_name);
  swprintf(zn_filename, wcslen(L"%s_zn.tga"), L"%s_zn.tga", skybox_name); swprintf(zp_filename, wcslen(L"%s_zp.tga"), L"%s_zp.tga", skybox_name);

  int xn_width, xn_height;
  skybox_xn = LoadTgaTexture(xn_filename, &xn_width, &xn_height);
  if (!skybox_xn)
    return false;

  int xp_width, xp_height;
  skybox_xp = LoadTgaTexture(xp_filename, &xp_width, &xp_height);
  if (!skybox_xp || xp_width != xn_width || xp_height != xn_height)
  {
    delete [] skybox_xn;
    if (skybox_xp) delete [] skybox_xp;
    return false;
  }

  int yn_width, yn_height;
  skybox_yn = LoadTgaTexture(yn_filename, &yn_width, &yn_height);
  if (!skybox_yn || yn_width != xn_width || yn_height != xn_height)
  {
    delete [] skybox_xn;
    if (skybox_xp) delete [] skybox_xp;
    if (skybox_yn) delete [] skybox_yn;
    return false;
  }

  int yp_width, yp_height;
  skybox_yp = LoadTgaTexture(yp_filename, &yp_width, &yp_height);
  if (!skybox_yp || yp_width != xn_width || yp_height != xn_height)
  {
    delete [] skybox_xn;
    if (skybox_xp) delete [] skybox_xp;
    if (skybox_yn) delete [] skybox_yn;
    if (skybox_yp) delete [] skybox_yp;
    return false;
  }

  int zn_width, zn_height;
  skybox_zn = LoadTgaTexture(zn_filename, &zn_width, &zn_height);
  if (!skybox_zn || zn_width != xn_width || zn_height != xn_height)
  {
    delete [] skybox_xn;
    if (skybox_xp) delete [] skybox_xp;
    if (skybox_yn) delete [] skybox_yn;
    if (skybox_yp) delete [] skybox_yp;
    if (skybox_zn) delete [] skybox_zn;
    return false;
  }

  int zp_width, zp_height;
  skybox_zp = LoadTgaTexture(zp_filename, &zp_width, &zp_height);
  if (!skybox_zp || zp_width != xn_width || zp_height != xn_height)
  {
    delete [] skybox_xn;
    if (skybox_xp) delete [] skybox_xp;
    if (skybox_yn) delete [] skybox_yn;
    if (skybox_yp) delete [] skybox_yp;
    if (skybox_zn) delete [] skybox_zn;
    if (skybox_zp) delete [] skybox_zp;
    return false;
  }

  skybox_width = xn_width;
  skybox_height = xn_height;

  
  if (!pRenderer->pRenderD3D->CreateTexture(skybox_width, skybox_height, &skybox_surface, &skybox_texture,
                                            false, false, pRenderer->uMinDeviceTextureDim))
    return false;

  return true;
}

struct vector
{
  float x, y, z;
};

struct matrix
{
  float m[4][4];
};

void VectorNormalize(vector *v)
{
  float invmag = 1.0f / sqrtf(v->x * v->x + v->y * v->y + v->z * v->z);
  v->x *= invmag;
  v->y *= invmag;
  v->z *= invmag;
}

void MatrixRotationAxis(matrix *pout, CONST vector *pv, float angle)
{
  memset(pout, 0, sizeof(matrix));
  pout->m[3][0] = 0;
  pout->m[3][1] = 0;
  pout->m[3][2] = 0;
  pout->m[3][3] = 1;

  vector v;
  v.x = pv->x; v.y = pv->y; v.z = pv->z;
  VectorNormalize(&v);

    pout->m[0][0] = (1.0f - cos(angle)) * v.x * v.x + cos(angle);
    pout->m[1][0] = (1.0f - cos(angle)) * v.x * v.y - sin(angle) * v.z;
    pout->m[2][0] = (1.0f - cos(angle)) * v.x * v.z + sin(angle) * v.y;
    pout->m[0][1] = (1.0f - cos(angle)) * v.y * v.x + sin(angle) * v.z;
    pout->m[1][1] = (1.0f - cos(angle)) * v.y * v.y + cos(angle);
    pout->m[2][1] = (1.0f - cos(angle)) * v.y * v.z - sin(angle) * v.x;
    pout->m[0][2] = (1.0f - cos(angle)) * v.z * v.x - sin(angle) * v.y;
   pout->m[1][2] = (1.0f - cos(angle)) * v.z * v.y + sin(angle) * v.x;
    pout->m[2][2] = (1.0f - cos(angle)) * v.z * v.z + cos(angle);
}

void VectorTransform(const matrix *m, const vector *v, vector *out)
{
  out->x = m->m[0][0] * v->x + m->m[1][0] * v->y + m->m[2][0] * v->z + m->m[3][0];
  out->y = m->m[0][1] * v->x + m->m[1][1] * v->y + m->m[2][1] * v->z + m->m[3][1];
  out->z = m->m[0][2] * v->x + m->m[1][2] * v->y + m->m[2][2] * v->z + m->m[3][2];
}

bool DrawSkyD3D_Skybox()
{
  static bool initialized = false,
              initialization_failed = false;
  if (initialization_failed)
    return false;
  
  static int last_camera_rot_y,
             last_camera_rot_x;
  if (!initialized)
  {
    if (!Skybox_Initialize(L"data/skybox/stars"))
    {
      initialization_failed = true;
      return false;
    }
    initialized = true;

    last_camera_rot_y = pParty->sRotationY + 1; // force update for the first run 
    last_camera_rot_x = pParty->sRotationX + 1;
  }

  /*
  r(y) = 
cos y	0	sin y	0
0	1	0	0
-sin y	0	cos y	0
0	0	0	1

x cos y - z sin y
y
x sin y + z cos y
1



r(x) =     // should be r(right) actually
1	0      	0	0
0	cos x	-sin x	0
0	sin x	cos x	0
0	0	    0	1


x
y cos x + z sin x
-y sin x + z cos x
1

  */

  if (last_camera_rot_y == pParty->sRotationY &&
      last_camera_rot_x == pParty->sRotationX)
  {
draw:
    struct RenderVertexD3D3  v[6];

    v[0].pos.x = pViewport->uScreen_TL_X;
    v[0].pos.y = pViewport->uScreen_TL_Y;
    v[0].pos.z = 0.99989998;
    v[0].rhw = 1;
    v[0].diffuse = 0xFFFFFFFF;
    v[0].specular = 0;
    v[0].texcoord.x = 0;
    v[0].texcoord.y = 0;
    
    v[1].pos.x = pViewport->uScreen_TL_X + pViewport->uScreenWidth;
    v[1].pos.y = pViewport->uScreen_TL_Y + pViewport->uScreenHeight;
    v[1].pos.z = 0.99989998;
    v[1].rhw = 1;
    v[1].diffuse = 0xFFFFFFFF;
    v[1].specular = 0;
    v[1].texcoord.x = (float)pViewport->uScreenWidth / skybox_width;
    v[1].texcoord.y = (float)pViewport->uScreenHeight / skybox_height;

    v[2].pos.x = pViewport->uScreen_TL_X + pViewport->uScreenWidth;
    v[2].pos.y = pViewport->uScreen_TL_Y;
    v[2].pos.z = 0.99989998;
    v[2].rhw = 1;
    v[2].diffuse = 0xFFFFFFFF;
    v[2].specular = 0;
    v[2].texcoord.x = (float)pViewport->uScreenWidth / skybox_width;
    v[2].texcoord.y = 0;

    memcpy(&v[3], &v[0], sizeof(*v));

    v[4].pos.x = pViewport->uScreen_TL_X;
    v[4].pos.y = pViewport->uScreen_TL_Y + pViewport->uScreenHeight;
    v[4].pos.z = 0.99989998;
    v[4].rhw = 1;
    v[4].diffuse = 0xFFFFFFFF;
    v[4].specular = 0;
    v[4].texcoord.x = 0;
    v[4].texcoord.y = (float)pViewport->uScreenHeight / skybox_height;

    memcpy(&v[5], &v[1], sizeof(*v));

    pRenderer->pRenderD3D->pDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
    pRenderer->pRenderD3D->pDevice->SetTexture(0, skybox_texture);
    pRenderer->pRenderD3D->pDevice->DrawPrimitive(D3DPT_TRIANGLELIST, D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1, v, 6, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT);
    //pRenderer->pRenderD3D->pDevice->DrawPrimitive(D3DPT_TRIANGLELIST, D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1, v + 1, 3, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT);

    return true;
  }


  DDSURFACEDESC2 desc;
  desc.dwSize = sizeof(desc);
  if (!pRenderer->LockSurface_DDraw4(skybox_surface, &desc, DDLOCK_WAIT | DDLOCK_WRITEONLY))
    return false;
  
  last_camera_rot_y = pParty->sRotationY;
  last_camera_rot_x = pParty->sRotationX;

  float aspect = (float)pViewport->uScreenWidth / (float)pViewport->uScreenHeight;
  float fov_x = 3.141592f * (pODMRenderParams->uCameraFovInDegrees + 0) / 360.0f;
  float fov_y = fov_x / aspect;

  float ray_dx = fov_x / (float)pViewport->uScreenWidth,
        ray_dy = fov_y / (float)pViewport->uScreenHeight;
  float party_angle_x = 2 * 3.141592653589 * pParty->sRotationX / 2048.0,
        party_angle_y = 2 * 3.141592653589 * pParty->sRotationY / 2048.0;
  for (int y = 0; y < pViewport->uScreenHeight; ++y)
    for (int x = 0; x < pViewport->uScreenWidth; ++x)
    {
      float angle_x = party_angle_x - (y - pViewport->uScreenHeight / 2) * ray_dy;
      float angle_y = party_angle_y - (x - pViewport->uScreenWidth / 2) * ray_dx;

      float _dir_x_ = 1,
            _dir_y_ = 0,
            _dir_z_ = 0;

      float dir_x_ = _dir_x_ * cosf(angle_y);// - _dir_z_ * sinf(angle_y);  // rotation around y
      //float dir_y_ = _dir_y_;
      float dir_z_ = _dir_x_ * sinf(angle_y);// + _dir_z_ * cosf(angle_y);

      //float dir_x =  dir_x_;                                               // rotation around x
      //float dir_y =  /*dir_y_ * cosf(angle_x)*/ + dir_z_ * sinf(angle_x);
      //float dir_z = /*-dir_y_ * sinf(angle_x)*/ + dir_z_ * cosf(angle_x);

      vector right;                                            // rotate around right actually to avoid space distortion
      right.x = /*dir_y * 0*/ - dir_z_ * 1;
      right.y = /*dir_z_ * 0 - dir_x_ * */0;
      right.z = dir_x_ * 1/* - dir_y_ * 0*/;
      //VectorNormalize(&right);

      matrix rightMatrix;
      MatrixRotationAxis(&rightMatrix, &right, angle_x);

      vector v1, v2;
      v1.x = dir_x_; v1.y = 0; v1.z = dir_z_;
      VectorTransform(&rightMatrix, &v1, &v2);

      float dir_x = v2.x,
            dir_y = v2.y,
            dir_z = v2.z;

      float abs_dir_x = fabsf(dir_x),
            abs_dir_y = fabsf(dir_y),
            abs_dir_z = fabsf(dir_z);

      unsigned short color = (0x1F << 11) | (0x1F << 5) | (5);  //default to orange
      if (abs_dir_x >= abs_dir_y)
      {
        if (abs_dir_x >= abs_dir_z)
        {
          if (dir_x >= 0)
          {
            float instersect_y = dir_y / (2.0f * dir_x); // plane equation for this side is x + 0.5 = 0
            float instersect_z = dir_z / (2.0f * dir_x);

            float u = 1.0f - (instersect_z + 0.5f),
                  v = 1.0f - (instersect_y + 0.5f);
            
            int tx = u * (skybox_width - 1),
                ty = v * (skybox_height - 1);

            color = skybox_xp[ty * skybox_width + tx];
            //color = ty * 0x1F / skybox_height;
          }
          else
          {
            float instersect_y = dir_y / (2.0f * dir_x);
            float instersect_z = dir_z / (2.0f * dir_x);

            float u = 1.0f - (instersect_z + 0.5f),
                  v = instersect_y + 0.5f;
            
            int tx = u * (skybox_width - 1),
                ty = v * (skybox_height - 1);

            color = skybox_xn[ty * skybox_width + tx];
            //color = tx * 0x1F / skybox_height;
          }
        }
        else if (dir_z >= 0)
          goto DIR_ZP;
        else
          goto DIR_ZN;
      }
      else if (abs_dir_y >= abs_dir_z)
      {
        if (dir_y >= 0)
        {
            float instersect_x = dir_x / (2.0f * dir_y);
            float instersect_z = dir_z / (2.0f * dir_y);

            float u = instersect_x + 0.5f,
                  v = instersect_z + 0.5f;
            
            int tx = u * (skybox_width - 1),
                ty = v * (skybox_height - 1);

            color = skybox_yp[ty * skybox_width + tx];
            //color = tx * 0x1F / skybox_height;
        }
        /*else   should never be seen i guess
        {
            __debugbreak();
          // -y
            //Log::Warning(L"(%03u, %03u): -y", x, y);
        }*/
      }
      else if (dir_z >= 0)
      {
DIR_ZP:
        // +z
        float instersect_x = dir_x / (2.0f * dir_z);
        float instersect_y = dir_y / (2.0f * dir_z);
        //float intersect_z = 0.5f;

        float u = instersect_x + 0.5f,
              v = -instersect_y + 0.5f;

        int tx = u * (skybox_width - 1),
            ty = v * (skybox_height - 1);

        color = skybox_zp[ty * skybox_width + tx];
      }
      else
      {
DIR_ZN:
        // -z
        float instersect_x = -dir_x / (2.0f * dir_z);
        float instersect_y = -dir_y / (2.0f * dir_z);
        //float intersect_z = -0.5f;

        float u = 1.0f - instersect_x - 0.5f,
              v = -instersect_y + 0.5f;

        int tx = u * (skybox_width - 1),
            ty = v * (skybox_height - 1);

        color = skybox_zn[ty * skybox_width + tx];
      }

      //pRenderer->pTargetSurface[(pViewport->uScreenY + y) * pRenderer->uTargetSurfacePitch + pViewport->uScreenX + x] = color;
      ((unsigned __int16 *)((char *)desc.lpSurface + y * desc.lPitch))[x] = color;
    }
    
  ErrD3D((skybox_surface)->Unlock(0));
  goto draw;
}
//----- (0047A384) --------------------------------------------------------
void ODM_LoadAndInitialize(const char *pLevelFilename, ODMRenderParams *thisa)
{
  int v2; // ebx@3
  unsigned int v3; // eax@3
  MapInfo *v4; // edi@4
  //int v5; // eax@8
  //SpawnPointMM7 *v6; // edx@14
  size_t v7; // eax@19
  //char *v8; // eax@19
  //char *v9; // eax@21
  char Source[120]; // [sp+Ch] [bp-84h]@19
  const char *pFilename; // [sp+84h] [bp-Ch]@1
  //unsigned int v12; // [sp+88h] [bp-8h]@12
  //int v13; // [sp+8Ch] [bp-4h]@11

  pFilename = pLevelFilename;
  //thisa->AllocSoftwareDrawBuffers();
  pODMRenderParams->Initialize();
  pWeather->bRenderSnow = false;
  pRenderer->ClearZBuffer(0, 479);
  thisa = (ODMRenderParams *)1;
  GetAlertStatus();
  if ( qword_A750D8 )
    qword_A750D8 = 0;
  v2 = pMapStats->GetMapInfo(pCurrentMapName);
  v3 = 0;
  if ( v2 )
  {
    v4 = &pMapStats->pInfos[v2];
    v3 = v4->uRespawnIntervalDays;
  }
  else
  {
    v4 = (MapInfo *)thisa;
  }
  day_attrib &= ~DAY_ATTRIB_FOG;
  dword_6BE13C_uCurrentlyLoadedLocationID = v2;
  pOutdoor->Initialize(
    pFilename,
    (unsigned int)(signed __int64)((double)(signed __int64)pParty->uTimePlayed * 0.234375) / 0x3C / 0x3C / 0x18 + 1,
    v3,
    (int)&thisa);
  if ( !(BYTE1(dword_6BE364_game_settings_1) & 0x20) )
  {
    InitializeActors();
    InitializeSpriteObjects();
  }
  BYTE1(dword_6BE364_game_settings_1) &= 0xDFu;
  //v5 = 0;
  if ( !v2 )
    thisa = 0;
  if ( thisa == (ODMRenderParams *)1 )
  {
    //v13 = 0;
    for (uint i = 0; i < pOutdoor->uNumSpawnPoints; ++i)
    {
      //v12 = 0;
      //while ( 1 )
      //{
      auto spawn = pOutdoor->pSpawnPoints + i;
        //v6 = &pOutdoor->pSpawnPoints[v12 / 0x18];
      if (spawn->uKind == 3 )
        SpawnEncounter(v4, spawn, 0, 0, 0);
      else
        v4->SpawnRandomTreasure(spawn);
        //++v13;
        //v12 += 24;
        //if ( v13 >= (signed int)pOutdoor->uNumSpawnPoints )
        //  break;
        //v5 = 0;
      //}
    }
    RespawnGlobalDecorations();
  }
  pOutdoor->PrepareDecorations();
  pOutdoor->_47F223_LooksLikeGenerateMonsterLoot();
  pOutdoor->InitalizeActors(v2);
  pOutdoor->MessWithLUN();
  v7 = strlen("levels\\");
  strcpy(Source, &pFilename[v7]);
  strcpy(pOutdoor->pLevelFilename, Source);
  pWeather->Initialize();
  pGame->pIndoorCameraD3D->sRotationY = pParty->sRotationY;
  pGame->pIndoorCameraD3D->sRotationX = pParty->sRotationX;
  //pODMRenderParams->RotationToInts();
  pOutdoor->UpdateSunlightVectors();

  float fov_rad;
  float fov_rad_inv;
  //----- (0042394D) --------------------------------------------------------
  //void IndoorCamera::Initialize(int degFov, unsigned int uViewportWidth, unsigned int uViewportHeight)
  {
    //pIndoorCamera->Initialize(65, viewparams->uScreen_BttmR_X - viewparams->uScreen_topL_X + 1,
    //                              viewparams->uScreen_BttmR_Y - viewparams->uScreen_topL_Y + 1);

    int uViewportWidth = viewparams->uScreen_BttmR_X - viewparams->uScreen_topL_X + 1;

    extern float _calc_fov(int viewport_width, int angle_degree);
    fov_rad = _calc_fov(uViewportWidth, 65);
    fov_rad_inv = 65536.0 / fov_rad;
  }
  pODMRenderParams->int_fov_rad = (signed __int64)fov_rad;
  pODMRenderParams->int_fov_rad_inv = (signed __int64)fov_rad_inv;

  for (int i = 0; i < 20000; ++i)
  {
    array_77EC08[i].ptr_38 = &stru_8019C8;

    array_77EC08[i].ptr_48 = nullptr;
  }

  MM7Initialization();
}

//----- (0047C370) --------------------------------------------------------
unsigned int GetLevelFogColor()
{
  signed __int64 v1; // qax@5
  int v2; // eax@6

  if (bUnderwater)
    return 0xFF258F5C;

  if (day_attrib & DAY_ATTRIB_FOG)
  {
      if ( pWeather->bNight ) // night-time fog
      {
        __debugbreak(); // decompilation can be inaccurate, please send savegame to Nomad
        v2 = -(pWeather->bNight != 1);
        return (v2 & 0xE0E0E1) - 0xE0E0E1;
      }
      else
      {
        v1 = (signed __int64)((1.0 - pOutdoor->fFogDensity) * 200.0 + pOutdoor->fFogDensity * 31.0);
        return v1 | (((unsigned int)v1 | (((unsigned int)v1 | 0xFFFFFF00) << 8)) << 8);
      }
  }

  return 0;
}

//----- (0047C3D7) --------------------------------------------------------
int __fastcall sub_47C3D7_get_fog_related_stuff(int a1, int a2, float a3)
{
  int v3; // ecx@1
  double v5; // st7@10
  signed int v7; // ecx@11
  double v8; // st6@12
  double v9; // st7@15
  double v10; // st6@16
  float v11; // ST14_4@17
  double v12; // ST08_8@17

  v3 = pWeather->bNight;
  if ( bUnderwater == 1 )
    v3 = 0;
  if ( pParty->armageddon_timer || !(day_attrib & DAY_ATTRIB_FOG) && !bUnderwater )
    return 0xFF000000;
  if ( v3 )
  {
    v5 = (double)day_fogrange_1;
    if ( a3 < v5 )
	{
      v7 = 0;
      if ( a3 == 0.0 )
	  {
		v7 = 216;
	  }
	  goto LABEL_21;
	}
	else
	{
		v8 = (double)day_fogrange_2;
		if ( a3 > v8 )
		{
		  v7 = 216;
 		  if ( a3 == 0.0 )
		  {
			v7 = 216;
		  }
		  goto LABEL_21;
		}
		v7 = (signed __int64)((a3 - v5) / (v8 - v5) * 216.0);
	}
  }
  else
  {
    v9 = (double)day_fogrange_1;
    if ( a3 < v9 )
    {
      v7 = 0;
	  if ( a3 == 0.0 )
	  {
		v7 = 216;
	  }
      goto LABEL_21;
    }
	else
	{
		v10 = (double)day_fogrange_2;
		if ( a3 > v10 )
		{  
		  v7 = 216;
		  if ( a3 == 0.0 )
		  {
			v7 = 216;
		  }
		  goto LABEL_21;
		}
		else
		{
			v11 = (a3 - v9) * 216.0 / (v10 - v9);
			v12 = v11 + 6.7553994e15;
			v7 = LODWORD(v12);
		}
	}
  }
  if ( v7 > 216 )
  {
    v7 = 216;
  }
  else
  {
	  if ( a3 == 0.0 )
	  {
		v7 = 216;
	  }
  }
LABEL_21:
  if ( a2 )
    v7 = 248;
  return (-1 - v7) << 24;
}

//----- (0047C4FC) --------------------------------------------------------
int __fastcall GetActorTintColor(int max_dimm, int min_dimm, float distance, int a4, RenderBillboard *a5)
{
  //int v5; // esi@1
  signed int v6; // edx@1
  //signed int result; // eax@2
  int v8; // eax@3
  double v9; // st7@12
  //double v10; // ST0C_8@18
  int v11; // ecx@28
  //signed int v12; // edi@28
  //double v13; // ST0C_8@33
  //double v14; // ST0C_8@34
  double v15; // st7@44
  //double v16; // ST0C_8@44
  //double v17; // ST0C_8@44
  int v18; // ST14_4@44
  //double v19; // ST0C_8@44
  signed int v20; // [sp+10h] [bp-4h]@10
  float a3a; // [sp+1Ch] [bp+8h]@33
  //float a3b; // [sp+1Ch] [bp+8h]@34
  float a3c; // [sp+1Ch] [bp+8h]@44
  //float a3d; // [sp+1Ch] [bp+8h]@44
  //float a4b; // [sp+20h] [bp+Ch]@18
  //int a4a; // [sp+20h] [bp+Ch]@33
  //float a4c; // [sp+20h] [bp+Ch]@44
  //float a4d; // [sp+20h] [bp+Ch]@44
  int a5a; // [sp+24h] [bp+10h]@44

  //v5 = a2;
  v6 = 0;

  if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
    return 8 * (31 - max_dimm) | ((8 * (31 - max_dimm) | ((31 - max_dimm) << 11)) << 8);

  if (pParty->armageddon_timer)
    return 0xFFFF0000;

  v8 = pWeather->bNight;
  if (bUnderwater)
    v8 = 0;
  if ( v8 )
  {
    v20 = 1;
    if ( (signed __int64)pParty->pPartyBuffs[PARTY_BUFF_TORCHLIGHT].uExpireTime > 0 )
      v20 = pParty->pPartyBuffs[PARTY_BUFF_TORCHLIGHT].uPower;
    v9 = (double)v20 * 1024.0;
    if ( a4 )
    {
      v6 = 216;
      goto LABEL_20;
    }
    if ( distance <= v9 )
    {
      if ( distance > 0.0 )
      {
        //a4b = distance * 216.0 / v9;
        //v10 = a4b + 6.7553994e15;
        //v6 = LODWORD(v10);
        v6 = floorf(0.5f + distance * 216.0 / v9);
        if (v6 > 216 )
        {
          v6 = 216;
          goto LABEL_20;
        }
      }
    }
    else
    {
      v6 = 216;
    }
    if ( distance != 0.0 )
    {
LABEL_20:
      if ( a5 )
        v6 = 8 * _43F55F_get_billboard_light_level(a5, v6 >> 3);
      if ( v6 > 216 )
        v6 = 216;
      return (255 - v6) | ((255 - v6) << 16) | ((255 - v6) << 8);
    }
//LABEL_19:
    v6 = 216;
    goto LABEL_20;
  }



  if (fabsf(distance) < 1.0e-6f)
    return 0xFFF8F8F8;

  // dim in measured in 8-steps
  v11 = 8 * (max_dimm - min_dimm);
    //v12 = v11;
    if ( v11 >= 0 )
    {
      if ( v11 > 216 )
        v11 = 216;
    }
    else
      v11 = 0;

    float fog_density_mult = 216.0f;
    if (a4)
      fog_density_mult += distance / (double)pODMRenderParams->shading_dist_shade * 32.0;

    v6 = v11 + floorf(pOutdoor->fFogDensity * fog_density_mult + 0.5f);
    /*if ( a4 )
    {
      //a3b = pOutdoor->fFogDensity * 216.0;
      //v14 = a3b + 6.7553994e15;
      //a4a = floorf(a3b + 0.5f);//LODWORD(v14);
    }
    else
    {
      //a3a = (distance / (double)pODMRenderParams->shading_dist_shade * 32.0 + 216.0) * pOutdoor->fFogDensity;
      //v13 = a3a + 6.7553994e15;
      //a4a = floorf(a3a + 0.5f);//LODWORD(v13);
    }
    v6 = a4a + v11;*/
    if ( a5 )
      v6 = 8 * _43F55F_get_billboard_light_level(a5, v6 >> 3);
    if ( v6 > 216 )
      v6 = 216;
    if ( v6 < v11 )
      v6 = v11;
    if ( v6 > 8 * pOutdoor->max_terrain_dimming_level )
      v6 = 8 * pOutdoor->max_terrain_dimming_level;
    if ( !bUnderwater )
      return (255 - v6) | ((255 - v6) << 16) | ((255 - v6) << 8);
    else
    {
    v15 = (double)(255 - v6) * 0.0039215689;
    a3c = v15;
    //a4c = v15 * 16.0;
    //v16 = a4c + 6.7553994e15;
    a5a = floorf(v15 * 16.0 + 0.5f);//LODWORD(v16);
    //a4d = a3c * 194.0;
    //v17 = a4d + 6.7553994e15;
    v18 = floorf(a3c * 194.0 + 0.5f);//LODWORD(v17);
    //a3d = a3c * 153.0;
    //v19 = a3d + 6.7553994e15;
     return (int)floorf(a3c * 153.0 + 0.5f)/*LODWORD(v19)*/ | ((v18 | (a5a << 8)) << 8);
    }
}
// 6BE3C4: using guessed type char bUnderwater;

//----- (0047F44B) --------------------------------------------------------
unsigned int WorldPosToGridCellX(int sWorldPosX)
{
  return (sWorldPosX >> 9) + 64; // sar is in original exe, resulting -880 / 512 = -1
                                 //                               and -880 sar 9 = -2
}

//----- (0047F458) --------------------------------------------------------
unsigned int WorldPosToGridCellZ(int sWorldPosZ)
{
  return 64 - (sWorldPosZ >> 9); // sar is in original exe, resulting -880 / 512 = -1
                                 //                               and -880 sar 9 = -2
}

//----- (0047F469) --------------------------------------------------------
int GridCellToWorldPosX(int a1)
{
  return (a1 - 64) << 9;
}

//----- (0047F476) --------------------------------------------------------
int GridCellToWorldPosZ(int a1)
{
  return (64 - a1) << 9;
}


//----- (004811A3) --------------------------------------------------------
void Polygon::DrawBorderTiles()
{
  //__debugbreak();

  pRenderer->pRenderD3D->pDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false);
  pRenderer->DrawTerrainPolygon(uNumVertices, this,
    pBitmaps_LOD->pHardwareTextures[pRenderer->pHDWaterBitmapIDs[pRenderer->hd_water_current_frame]], false, true);

  pRenderer->pRenderD3D->pDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, true);
  //pRenderer->DrawTerrainPolygon(uNumVertices, this, pBitmaps_LOD->pHardwareTextures[uTileBitmapID], true, true);
}


//----- (00481ED9) --------------------------------------------------------
void  sub_481ED9_MessWithODMRenderParams()
{
  stru_8019C8._48616B_frustum_odm(65536, 0, 0, 0, 65536, 0);
  pODMRenderParams->uNumPolygons = 0;
  //pODMRenderParams->uNumEdges = 0;
  //pODMRenderParams->uNumSpans = 0;
  //pODMRenderParams->uNumSurfs = 0;
  pODMRenderParams->uNumBillboards = 0;
  pODMRenderParams->field_44 = 0;
}

//----- (004823F4) --------------------------------------------------------
bool IsTerrainSlopeTooHigh(int pos_x, int pos_z)
{
  //unsigned int v2; // ebx@1
  //unsigned int v3; // edi@1
  //int v4; // eax@1
  //int v6; // esi@5
  //int v7; // ecx@6
  //int v8; // edx@6
  //int v9; // eax@6
  //int v10; // esi@10
  //int v11; // [sp+14h] [bp-8h]@1
  //int v12; // [sp+18h] [bp-4h]@1

  //v12 = a1;
  //v11 = a2;
  auto grid_x = WorldPosToGridCellX(pos_x);
  auto grid_z = WorldPosToGridCellZ(pos_z) - 1;

  auto party_grid_x1 = GridCellToWorldPosX(grid_x);
  //dword_76D56C_terrain_cell_world_pos_around_party_x = GridCellToWorldPosX(grid_x + 1);
  //dword_76D570_terrain_cell_world_pos_around_party_x = GridCellToWorldPosX(grid_x + 1);
  //dword_76D574_terrain_cell_world_pos_around_party_x = GridCellToWorldPosX(grid_x);
  auto party_grid_z1 = GridCellToWorldPosZ(grid_z);
  //dword_76D55C_terrain_cell_world_pos_around_party_z = GridCellToWorldPosZ(grid_z);
  //dword_76D560_terrain_cell_world_pos_around_party_z = GridCellToWorldPosZ(grid_z + 1);
  //dword_76D564_terrain_cell_world_pos_around_party_z = GridCellToWorldPosZ(grid_z + 1);
  auto party_x1z1_y = pOutdoor->DoGetHeightOnTerrain(grid_x, grid_z);
  auto party_x2z1_y = pOutdoor->DoGetHeightOnTerrain(grid_x + 1, grid_z);
  auto party_x2z2_y = pOutdoor->DoGetHeightOnTerrain(grid_x + 1, grid_z + 1);
  auto party_x1z2_y = pOutdoor->DoGetHeightOnTerrain(grid_x, grid_z + 1);
  //dword_76D554_terrain_cell_world_pos_around_party_y = v4;
  if (party_x1z1_y == party_x2z1_y &&
      party_x2z1_y == party_x2z2_y &&
      party_x2z2_y == party_x1z2_y )
    return false;

  auto dx = abs(pos_x - party_grid_x1),
       dz = abs(party_grid_z1 - pos_z);

  int y1, y2, y3;
  if (dz >= dx)
  {
    y1 = party_x1z2_y;  //  lower-left triangle
    y2 = party_x2z2_y;  //  y3 | \ 
    y3 = party_x1z1_y;  //     |   \ 
                        /*     |     \ 
                               |______ \
                            y1           y2   */
  }
  else
  {
    y1 = party_x2z1_y;  // upper-right
    y2 = party_x1z1_y;  //  y2_______ y1
    y3 = party_x2z2_y;  //    \     |
                        /*      \   |
                                  \ |
                                    y3     */
  }

  int y_min = min(y1, min(y2, y3)),
      y_max = max(y1, max(y2, y3));
  return (y_max - y_min) > 512;

  /*if ( y1 >= y2 )
  {
    y_min = y2;
    if ( y2 < y3 )
      goto LABEL_13;
LABEL_12:
    y_min = y3;
    goto LABEL_13;
  }
  else if ( y1 >= y3 )
    goto LABEL_12;
  else
  y_min = y1;

LABEL_13:
  if ( y1 <= y2 )
  {
    if ( y2 > y3 )
      y3 = y2;
  }
  else
  {
    if ( y1 > y3 )
      y3 = y1;
  }
  return y3 - v10 > 512;*/
}

//----- (0048257A) --------------------------------------------------------
int __fastcall GetTerrainHeightsAroundParty2(int a1, int a2, int *pIsOnWater, int bFloatAboveWater)
{
  //unsigned int v4; // ebx@1
  //unsigned int v5; // edi@1
  int result; // eax@9
  //int v7; // ebx@10
  int v8; // ebx@11
  int v9; // eax@11
  int v10; // ecx@11
  //int v11; // [sp+Ch] [bp-Ch]@1
  //int v12; // [sp+10h] [bp-8h]@1
  int v13; // [sp+10h] [bp-8h]@11
  signed int v14; // [sp+14h] [bp-4h]@3
  int v15; // [sp+24h] [bp+Ch]@11

  //v11 = a1;
  //v12 = a2;
  auto grid_x = WorldPosToGridCellX(a1);
  auto grid_z = WorldPosToGridCellZ(a2) - 1;

  auto grid_x1 = GridCellToWorldPosX(grid_x),
       grid_x2 = GridCellToWorldPosX(grid_x + 1);
  auto grid_z1 = GridCellToWorldPosZ(grid_z),
       grid_z2 = GridCellToWorldPosZ(grid_z + 1);

  auto y_x1z1 = pOutdoor->DoGetHeightOnTerrain(grid_x,     grid_z),
       y_x2z1 = pOutdoor->DoGetHeightOnTerrain(grid_x + 1, grid_z),
       y_x2z2 = pOutdoor->DoGetHeightOnTerrain(grid_x + 1, grid_z + 1),
       y_x1z2 = pOutdoor->DoGetHeightOnTerrain(grid_x,     grid_z + 1);
  //v4 = WorldPosToGridCellX(a1);
  //v5 = WorldPosToGridCellZ(v12) - 1;
  //dword_76D538_terrain_cell_world_pos_around_party_x = GridCellToWorldPosX(v4);
  //dword_76D53C_terrain_cell_world_pos_around_party_x = GridCellToWorldPosX(v4 + 1);
  //dword_76D540_terrain_cell_world_pos_around_party_x = GridCellToWorldPosX(v4 + 1);
  //dword_76D544_terrain_cell_world_pos_around_party_x = GridCellToWorldPosX(v4);
  //dword_76D528_terrain_cell_world_pos_around_party_z = GridCellToWorldPosZ(v5);
  //dword_76D52C_terrain_cell_world_pos_around_party_z = GridCellToWorldPosZ(v5);
  //dword_76D530_terrain_cell_world_pos_around_party_z = GridCellToWorldPosZ(v5 + 1);
  //dword_76D534_terrain_cell_world_pos_around_party_z = GridCellToWorldPosZ(v5 + 1);
  //dword_76D518_terrain_cell_world_pos_around_party_y = pOutdoor->DoGetHeightOnTerrain(v4, v5);
  //dword_76D51C_terrain_cell_world_pos_around_party_y = pOutdoor->DoGetHeightOnTerrain(v4 + 1, v5);
  //dword_76D520_terrain_cell_world_pos_around_party_y = pOutdoor->DoGetHeightOnTerrain(v4 + 1, v5 + 1);
  //dword_76D524_terrain_cell_world_pos_around_party_y = pOutdoor->DoGetHeightOnTerrain(v4, v5 + 1);
  *pIsOnWater = false;
  if ( pOutdoor->ActuallyGetSomeOtherTileInfo(grid_x, grid_z) & 2 )
    *pIsOnWater = true;
  v14 = 0;
  if ( !bFloatAboveWater && *pIsOnWater )
    v14 = -60;
  if ( y_x1z1 != y_x2z1 ||
       y_x2z1 != y_x2z2 ||
       y_x2z2 != y_x1z2 )
  {
    if ( abs(grid_z1 - a2) >= abs(a1 - grid_x1) )
    {
      v8 = y_x1z2;
      v9 = y_x2z2;
      v10 = y_x1z1;
      v15 = a1 - grid_x1;
      v13 = a2 - grid_z2;
    }
    else
    {
      v8 = y_x2z1;
      v9 = y_x1z1;
      v10 = y_x2z2;
      v15 = grid_x2 - a1;
      v13 = grid_z1 - a2;
    }
    return v14 + v8 + fixpoint_mul(v13, (v10 - v8) * 128) + fixpoint_mul(v15, (v9 - v8) * 128);
  }
  else
    return y_x1z1;
}





//----- (00485F53) --------------------------------------------------------
void  sr_485F53(Vec2_int_ *v)
{
  ++v->y;
  if ( v->y > 1000 )
    v->y = 0;
}

//----- (0048607B) --------------------------------------------------------
void Polygon::Create_48607B(stru149 *a2)
{
  this->pTexture = 0;
  this->ptr_38 = a2;
}

//----- (00486089) --------------------------------------------------------
void Polygon::_normalize_v_18()
{
  double v2; // st7@1
  double v3; // st6@1
  double v5; // st5@1

  //v1 = this;
  v2 = (double)this->v_18.x;
  v3 = (double)this->v_18.y;
  v5 = (double)this->v_18.z;
  float len = sqrt(v5 * v5 + v3 * v3 + v2 * v2);
  if (fabsf(len) < 1e-6f)
  {
    v_18.x = 0;
    v_18.y = 0;
    v_18.z = 65536;
  }
  else
  {
    v_18.x = round(v2 / len * 65536.0);
    v_18.y = round(v3 / len * 65536.0);
    v_18.y = round(v5 / len * 65536.0);
  }
}

//----- (0048616B) --------------------------------------------------------
void stru149::_48616B_frustum_odm(int a2, int a3, int a4, int a5, int a6, int a7)
{
  int v7; // ebx@1
  //int v8; // esi@1
  int v9; // edi@1
  //int v10; // eax@1
  int v11; // edx@1
  //int v12; // esi@2
  //int v13; // eax@2
  //int v14; // ST10_4@3
  //int v15; // esi@3
  //int v16; // eax@5
  int v17; // ST0C_4@6
  //int v18; // eax@8
  int v19; // ST0C_4@9
  //int v20; // eax@10
  //int v21; // edx@10
  //int v22; // eax@10
  //int result; // eax@10
  int v24; // [sp+14h] [bp-14h]@1
  int v25; // [sp+18h] [bp-10h]@1
  //int v26; // [sp+1Ch] [bp-Ch]@1
  int v27; // [sp+24h] [bp-4h]@1
  //int v28; // [sp+30h] [bp+8h]@10
  //int v29; // [sp+3Ch] [bp+14h]@10

  v25 = pGame->pIndoorCameraD3D->int_cosine_x;
  v7 = pGame->pIndoorCameraD3D->int_sine_y;
  v27 = pGame->pIndoorCameraD3D->int_sine_x;
  //v8 = -pIndoorCamera->pos.y;
  v9 = pGame->pIndoorCameraD3D->int_cosine_y;
  //v26 = -pIndoorCamera->pos.z;
  v11 = pGame->pIndoorCameraD3D->int_cosine_y * -pGame->pIndoorCameraD3D->vPartyPos.x + pGame->pIndoorCameraD3D->int_sine_y * -pGame->pIndoorCameraD3D->vPartyPos.y;
  v24 = pGame->pIndoorCameraD3D->int_cosine_y * -pGame->pIndoorCameraD3D->vPartyPos.y - pGame->pIndoorCameraD3D->int_sine_y * -pGame->pIndoorCameraD3D->vPartyPos.x;
  if (pGame->pIndoorCameraD3D->sRotationX)
  {
    this->field_0_party_dir_x = fixpoint_mul(v11, pGame->pIndoorCameraD3D->int_cosine_x) +
                                fixpoint_mul((-pGame->pIndoorCameraD3D->vPartyPos.z) << 16, pGame->pIndoorCameraD3D->int_sine_x);
    this->field_4_party_dir_y = v24;
    this->field_8_party_dir_z = fixpoint_mul((-pGame->pIndoorCameraD3D->vPartyPos.z) << 16, v25) - fixpoint_mul(v11, v27);
  }
  else
  {
    this->field_0_party_dir_x = v11;
    this->field_4_party_dir_y = v24;
    this->field_8_party_dir_z = (-pGame->pIndoorCameraD3D->vPartyPos.z) << 16;
  }

  if (pGame->pIndoorCameraD3D->sRotationX)
  {
    v17 = fixpoint_mul(a2, v9) + fixpoint_mul(a3, v7);

    this->angle_from_north = fixpoint_mul(v17, v25) + fixpoint_mul(a4, v27);
    this->angle_from_west = fixpoint_mul(a3, v9) - fixpoint_mul(a2, v7);
    this->viewing_angle_from_west_east = fixpoint_mul(a4, v25) - fixpoint_mul(v17, v27);
  }
  else
  {
    this->angle_from_north = fixpoint_mul(a2, v9) + fixpoint_mul(a3, v7);
    this->angle_from_west = fixpoint_mul(a3, v9) - fixpoint_mul(a2, v7);
    this->viewing_angle_from_west_east = a4;
  }

  if (pGame->pIndoorCameraD3D->sRotationX)
  {
    v19 = fixpoint_mul(a5, v9) + fixpoint_mul(a6, v7);

    this->angle_from_east = fixpoint_mul(v19, v25) + fixpoint_mul(a7, v27);
    this->angle_from_south = fixpoint_mul(a6, v9) - fixpoint_mul(a5, v7);
    this->viewing_angle_from_north_south = fixpoint_mul(a7, v25) - fixpoint_mul(v19, v27);
  }
  else
  {
    this->angle_from_east = fixpoint_mul(a5, v9) + fixpoint_mul(a6, v7);
    this->angle_from_south = fixpoint_mul(a6, v9) - fixpoint_mul(a5, v7);
    this->viewing_angle_from_north_south = a7;
  }

  this->angle_from_east = -this->angle_from_east;
  this->angle_from_south = -this->angle_from_south;
  this->viewing_angle_from_north_south = -this->viewing_angle_from_north_south;

  this->field_24 = fixpoint_dot(this->angle_from_north,  this->field_0_party_dir_x,
                                this->angle_from_west, this->field_4_party_dir_y,
                                this->viewing_angle_from_west_east, this->field_8_party_dir_z);
  this->field_28 = fixpoint_dot(this->angle_from_east, this->field_0_party_dir_x,
                                this->angle_from_south, this->field_4_party_dir_y,
                                this->viewing_angle_from_north_south, this->field_8_party_dir_z);
}

//----- (0048694B) --------------------------------------------------------
void stru149::_48694B_frustum_sky()
{
  this->angle_from_east = -this->angle_from_east;
  this->angle_from_south = -this->angle_from_south;
  this->viewing_angle_from_north_south = -this->viewing_angle_from_north_south;

  this->field_24 = fixpoint_dot(this->angle_from_north, this->field_0_party_dir_x,
                                this->angle_from_west, this->field_4_party_dir_y,
                                this->viewing_angle_from_west_east, this->field_8_party_dir_z);
  this->field_28 = fixpoint_dot(this->angle_from_east, this->field_0_party_dir_x,
                                this->angle_from_south, this->field_4_party_dir_y,
                                this->viewing_angle_from_north_south, this->field_8_party_dir_z);
}

//----- (0044100D) --------------------------------------------------------
bool sub_44100D()
{
  return pCurrentScreen == SCREEN_NPC_DIALOGUE || pCurrentScreen == SCREEN_CHARACTERS ||
         pCurrentScreen > SCREEN_LOADGAME && pCurrentScreen <= SCREEN_E ||
         pCurrentScreen > SCREEN_VIDEO && pCurrentScreen <= SCREEN_INPUT_BLV || pCurrentScreen == SCREEN_CASTING;
}
// 4E28F8: using guessed type int pCurrentScreen;

//----- (00441A4E) --------------------------------------------------------
__int16 __fastcall sub_441A4E(int a1)//for blessing
{
  __int16 result; // ax@1
  int v2; // ebx@1
  char *v3; // esi@1
  int v4; // edi@4
  bool v5; // ecx@4
  SpriteFrame *pFrame; // eax@6
  //SpriteFrame *v7; // edi@6
  int v8; // eax@6
  unsigned __int16 v9; // ax@6
  RenderBillboardTransform_local0 v10; // [sp+Ch] [bp-5Ch]@1
  int v11; // [sp+5Ch] [bp-Ch]@6
  int v12; // [sp+60h] [bp-8h]@1
  int v13; // [sp+64h] [bp-4h]@6

  v10.uParentBillboardID = -1;
  v10.pTarget = pRenderer->pTargetSurface;
  v10.pTargetZ = pRenderer->pActiveZBuffer;
  v10.uTargetPitch = pRenderer->field_10;
  result = 0;
  v2 = a1;
  v10.uViewportX = 0;
  v10.uViewportY = 0;
  v10.uViewportZ = 639;
  v10.uViewportW = 479;
  v12 = 0;
  //v3 = (char *)&pOtherOverlayList->pOverlays[0].field_C;
  //do
  for ( uint i = 0; i < 50; ++i )
  {
    if ( pOtherOverlayList->pOverlays[i].field_6 > 0 )
    {
      result = pOtherOverlayList->pOverlays[i].field_0;
      if ( pOtherOverlayList->pOverlays[i].field_0 >= 300 )
      {
        //v4 = result;
        v5 = pOtherOverlayList->pOverlays[i].field_0 == v2 + 320 
           || pOtherOverlayList->pOverlays[i].field_0 == v2 + 330 
           || pOtherOverlayList->pOverlays[i].field_0 == v2 + 340 
           || pOtherOverlayList->pOverlays[i].field_0 == v2 + 350;
        pOtherOverlayList->pOverlays[i].field_0 = v2 + 310;
        if ( pOtherOverlayList->pOverlays[i].field_0 == v2 + 310 || v5 )
        {
          if ( !pOtherOverlayList->pOverlays[i].field_0 )
          {
            pFrame = pSpriteFrameTable->GetFrame(pOverlayList->pOverlays[pOtherOverlayList->pOverlays[i].field_2].uSpriteFramesetID,
                   pOtherOverlayList->pOverlays[i].field_4);
            //v7 = v6;
            v11 = pOtherOverlayList->pOverlays[i].field_E;
            //v13 = pFrame->scale;
            v13 = (unsigned __int64)(v11 * (signed __int64)pFrame->scale) >> 16;
            v10.uScreenSpaceX = pOtherOverlayList->pOverlays[i].field_8;
            v10.uScreenSpaceY = pOtherOverlayList->pOverlays[i].field_A;
            v10._screenspace_x_scaler_packedfloat = v13;
            v10._screenspace_y_scaler_packedfloat = v13;
            v10.pPalette = PaletteManager::Get_Dark_or_Red_LUT(pFrame->uPaletteIndex, 0, 1);
            v8 = pOtherOverlayList->pOverlays[i].field_2;
            v10.sZValue = 0;
            v10.uFlags = 0;
            v9 = pOverlayList->pOverlays[v8].uOverlayType;
            if ( !v9 || v9 == 2 )
              v10.uScreenSpaceY += pSprites_LOD->pSpriteHeaders[pFrame->pHwSpriteIDs[0]].uHeight >> 1;
            result = pSprites_LOD->pSpriteHeaders[pFrame->pHwSpriteIDs[0]]._4AD2D1(&v10, 0);
            ++v12;
            if ( v12 == 5 )
              break;
          }
        }
      }
    }
    //v3 += 20;
  }
  //while ( (signed int)v3 < (signed int)&pOverlayList->pOverlays );
  return result;
}

//----- (00443801) --------------------------------------------------------
void Initialize2DA()
{
 
  int i;
	char* test_string;
	unsigned char c;
	bool break_loop;
	unsigned int temp_str_len;
	char* tmp_pos;
	int decode_step;

	if ( p2DEventsTXT_Raw )
		free(p2DEventsTXT_Raw);
	p2DEventsTXT_Raw = NULL;
	p2DEventsTXT_Raw = (char *)pEvents_LOD->LoadRaw("2dEvents.txt", 0);
	strtok(p2DEventsTXT_Raw, "\r");
	strtok(NULL, "\r");

	for (i=0;i<525;++i)
		{
		test_string = strtok(NULL, "\r") + 1;
		break_loop = false;
		decode_step=0;
		do 
			{
			c = *(unsigned char*)test_string;
			temp_str_len = 0;
			while((c!='\t')&&(c>0))
				{
				++temp_str_len;
				c=test_string[temp_str_len];
				}		
			tmp_pos=test_string+temp_str_len;
			if (*tmp_pos == 0)
				break_loop = true;
			*tmp_pos = 0;
			if (temp_str_len)
				{
				switch (decode_step)
					{
				case 2:
					{
					if ( !_strnicmp(test_string, "wea", 3) )
						{
						p2DEvents[i].uType = BuildingType_WeaponShop;
						break;
						}
					if ( !_strnicmp(test_string, "arm", 3) )
						{
						p2DEvents[i].uType = BuildingType_ArmorShop;
						break;
						}
					if ( !_strnicmp(test_string, "mag", 3) )
						{
						p2DEvents[i].uType = BuildingType_MagicShop;
						break;
						}
					if ( !_strnicmp(test_string, "alc", 3) )
						{
						p2DEvents[i].uType = BuildingType_AlchemistShop;
						break;
						}
					if ( !_strnicmp(test_string, "sta", 3) )
						{
						p2DEvents[i].uType = BuildingType_Stables;
						break;
						}
					if ( !_strnicmp(test_string, "boa", 3) )
						{
						p2DEvents[i].uType = BuildingType_Boats;
						break;
						}
					if ( !_strnicmp(test_string, "tem", 3) )
						{
						p2DEvents[i].uType = BuildingType_Temple;
						break;
						}
					if ( !_strnicmp(test_string, "tra", 3) )
						{
						p2DEvents[i].uType = BuildingType_Training;
						break;
						}
					if ( !_strnicmp(test_string, "tow", 3) )
						{
						p2DEvents[i].uType = BuildingType_TownHall;
						break;
						}

					if ( !_strnicmp(test_string, "tav", 3) )
						{
						p2DEvents[i].uType = BuildingType_Tavern;
						break;
						}
					if ( !_strnicmp(test_string, "ban", 3) )
						{
						p2DEvents[i].uType = BuildingType_Bank;
						break;
						}
					if ( !_strnicmp(test_string, "fir", 3) )
						{
						p2DEvents[i].uType = BuildingType_FireGuild;
						break;
						}
					if ( !_strnicmp(test_string, "air", 3) )
						{
						p2DEvents[i].uType = BuildingType_AirGuild;
						break;
						}
					if ( !_strnicmp(test_string, "wat", 3) )
						{
						p2DEvents[i].uType = BuildingType_WaterGuild;
						break;
						}
					if ( !_strnicmp(test_string, "ear", 3) )
						{
						p2DEvents[i].uType = BuildingType_EarthGuild;
						break;
						}
					if ( !_strnicmp(test_string, "spi", 3) )
						{
						p2DEvents[i].uType = BuildingType_SpiritGuild;
						break;
						}
					if ( !_strnicmp(test_string, "min", 3) )
						{
						p2DEvents[i].uType = BuildingType_MindGuild;
						break;
						}
					if ( !_strnicmp(test_string, "bod", 3) )
						{
						p2DEvents[i].uType = BuildingType_BodyGuild;
						break;
						}
					if ( !_strnicmp(test_string, "lig", 3) )
						{
						p2DEvents[i].uType = BuildingType_LightGuild;
						break;
						}
					if ( !_strnicmp(test_string, "dar", 3) )
						{
						p2DEvents[i].uType = BuildingType_DarkGuild;
						break;
						}
					if ( !_strnicmp(test_string, "ele", 3) ) // "Element Guild" from mm6
						{
						p2DEvents[i].uType = BuildingType_ElementalGuild;
						break;
						}
					if ( !_strnicmp(test_string, "sel", 3) )
						{
						p2DEvents[i].uType = BuildingType_SelfGuild;
						break;
						}
					if ( !_strnicmp(test_string, "mir", 3) )
						{
						p2DEvents[i].uType = BuildingType_16;
						break;
						}
					if ( !_strnicmp(test_string, "mer", 3) ) // "Merc Guild" from mm6
						{
						p2DEvents[i].uType = BuildingType_TownHall;
						break;
						}
					p2DEvents[i].uType = BuildingType_18;
					}
					break;

				case 4:
					p2DEvents[i].uAnimationID = atoi(test_string);
					break;
				case 5:
					p2DEvents[i].pName = RemoveQuotes(test_string);
					break;
				case 6:
					p2DEvents[i].pProprieterName = RemoveQuotes(test_string);
					break;
				case 7:
					p2DEvents[i].pProprieterTitle = RemoveQuotes(test_string);
					break;
				case 8:
					p2DEvents[i].field_14 = atoi(test_string);
					break;
				case 9:
					p2DEvents[i]._state = atoi(test_string);
					break;
				case 10:
					p2DEvents[i]._rep = atoi(test_string);
					break;
				case 11:
					p2DEvents[i]._per = atoi(test_string);
					break;
				case 12:
					p2DEvents[i].fPriceMultiplier = atof(test_string);
					break;
				case 13:
					p2DEvents[i].flt_24 = atof(test_string);
					break;
				case 15:
					p2DEvents[i].field_1C = atoi(test_string);
					break;
				case 18:
					p2DEvents[i].uOpenTime = atoi(test_string);
					break;
				case 19:
					p2DEvents[i].uCloseTime = atoi(test_string);
					break;
				case 20:
					p2DEvents[i].uExitPicID = atoi(test_string);
					break;
				case 21:
					p2DEvents[i].uExitMapID = atoi(test_string);
					break;
				case 22:
					p2DEvents[i]._quest_related = atoi(test_string);
					break;
				case 23:
					p2DEvents[i].pEnterText = RemoveQuotes(test_string);
					break;
					}
				}
			++decode_step;
			test_string=tmp_pos+1;
			} while ((decode_step<24)&&!break_loop);
		}

}

//----- (00443E31) --------------------------------------------------------
void LoadLevel_InitializeLevelStr()
    {
  
  char Args[100]; 
  int string_num;
  int max_string_length;
  int current_string_length;
  int prev_string_offset;

  if (sizeof(pLevelStrOffsets) != 2000)
    Log::Warning(L"pLevelStrOffsets: deserialization warning");
  memset(pLevelStrOffsets.data(), 0, 2000);
  
  max_string_length = 0;
  string_num = 1;
  prev_string_offset = 0;
  pLevelStrOffsets[0]=0;
  for (uint i = 0; i < uLevelStrFileSize; ++i)
  {
      if ( !pLevelStr[i] )
      {
        pLevelStrOffsets[string_num] = i + 1;
		++string_num;
        if ( i - prev_string_offset > max_string_length )
          max_string_length = i - prev_string_offset;
        prev_string_offset = i;
      }
  }

  uLevelStrNumStrings = string_num - 1;
  if ( max_string_length > 800 )
    Error("MAX_EVENT_TEXT_LENGTH needs to be increased to %lu", max_string_length+1);

  if ( uLevelStrNumStrings > 0 )
  {
    for(uint i = 0; i <uLevelStrNumStrings ; ++i) 
    {
      if ( RemoveQuotes(&pLevelStr[pLevelStrOffsets[i]]) != &pLevelStr[pLevelStrOffsets[i]] )
        ++pLevelStrOffsets[i]; 
    }
  }
}

//----- (00443F95) --------------------------------------------------------
void  OnMapLeave()
{
 _evt_raw *test_event;
  if ( uLevelEVT_NumEvents > 0 )
  {
    for (uint i = 0; i < uLevelEVT_NumEvents; ++i)
    {
		test_event=(_evt_raw*)&pLevelEVT[pLevelEVT_Index[i].uEventOffsetInEVT];
      if ( test_event->_e_type == EVENT_OnMapLeave )
      {
        EventProcessor(pLevelEVT_Index[i].uEventID, 0, 1, pLevelEVT_Index[i].event_sequence_num);
      }
    }
  }
}

//----- (00443FDC) --------------------------------------------------------
void OnMapLoad()
{
	stru176 *v3; // esi@7
	__int16 v4; // cx@9
	__int16 v5; // di@9
	int v6; // eax@9
	signed __int64 v8; // qax@26
	unsigned int v9; // ecx@26
	signed __int64 v10; // qax@26
	signed __int64 v11; // qax@26
	int v12; // ST50_4@26
	signed __int64 v13; // qax@26
	signed __int64 v14; // qax@26
	int v15; // ST58_4@26
	signed __int64 v16; // qax@26
	int hours; // ebx@26
	unsigned __int64 v18; // [sp+Ch] [bp-44h]@12
	signed __int64 seconds; // [sp+14h] [bp-3Ch]@26
	unsigned __int64 v20; // [sp+1Ch] [bp-34h]@7
	int minutes; // [sp+2Ch] [bp-24h]@26
	int years; // [sp+34h] [bp-1Ch]@26
	int weeks; // [sp+38h] [bp-18h]@26
	int v26; // [sp+3Ch] [bp-14h]@15
	int days; // [sp+3Ch] [bp-14h]@26
	int months; // [sp+40h] [bp-10h]@26
	__int16 v29; // [sp+46h] [bp-Ah]@9
	__int16 v30; // [sp+48h] [bp-8h]@9
	__int16 v31; // [sp+4Ah] [bp-6h]@9
	__int16 v32; // [sp+4Ch] [bp-4h]@9
	__int16 v33; // [sp+4Eh] [bp-2h]@9

	for (uint i = 0; i < uLevelEVT_NumEvents; ++i)
	{
		auto pEvent = pLevelEVT_Index[i];

		auto _evt = (_evt_raw *)(&pLevelEVT[pEvent.uEventOffsetInEVT]);

		if (_evt->_e_type == EVENT_PlaySound)
		{
			pSoundList->LoadSound(EVT_DWORD(_evt->v5), 0);
		}
		else if (_evt->_e_type == EVENT_OnMapReload)
		{
			EventProcessor(pEvent.uEventID, 0, 0, pEvent.event_sequence_num);
		}
		else if (_evt->_e_type == EVENT_OnTimer || _evt->_e_type == EVENT_Initialize)
		{
			v3 = &array_5B5928_timers[dword_5B65C8_timers_count];
			v20 = pOutdoor->loc_time.uLastVisitDay;
			if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
				v20 = pIndoor->stru1.uLastVisitDay;

			v3->timer_evt_type = _evt->_e_type;
			v3->timer_evt_ID = pEvent.uEventID;
			v3->timer_evt_seq_num = pEvent.event_sequence_num;

			v3->field_10 = _evt->v5;
			v3->field_12 = _evt->v6;
			v3->field_14 = _evt->v7;
			v3->field_16 = _evt->v8;
			v3->field_18 = _evt->v9;
			v3->field_1A = _evt->v10;


			v6 = ((unsigned short)_evt->v12 << 8) + _evt->v11;

			v3->time_left_to_fire = ((unsigned short)_evt->v12 << 8) + _evt->v11;
            v3->fire_interval = ((unsigned short)_evt->v12 << 8) + _evt->v11;
			if (v3->timer_evt_type  == EVENT_Initialize && !(short)v6 )
			{
				if ( v20 )
					v18 = pParty->uTimePlayed - v20;
				else
					v18 = 0i64;
				v26 = (signed int)(signed __int64)((double)(signed __int64)v18 * 0.234375) / 60 / 60 / 24;

				if ( v26 / 7 / 4 / 12 )
				{
					if ( v3->field_10 )
					{
						++dword_5B65C8_timers_count;
                        v3->next_fire_time = 0;
						continue;
					}
				}
				if (v26 / 7 / 4 != 0 && v3->field_12 != 0 ||
					v26 / 7 != 0 && v3->field_14 != 0 ||
					v26 != 0 || !v20)
				{
					++dword_5B65C8_timers_count;
					v3->next_fire_time = 0;
					continue;
				}
			}
			else
			{
				v8 = (signed __int64)((double)(signed __int64)pParty->uTimePlayed * 0.234375);
				v9 = v8;
				v10 = (signed int)v8 / 60;
				minutes = v10 % 60;
				v11 = (signed int)(v10 / 60);
				v12 = v11 % 24;
				v13 = (signed int)(v11 / 24);
				days = v13 % 7;
				v14 = (signed int)(v13 / 7);
				v15 = v14 % 4;
				v16 = (signed int)(v14 / 4);
				years = v16 / 12;

				auto _1 = (unsigned __int64)((double)pParty->uTimePlayed * 0.234375) >> 32;
				auto _2 = ((__int64)v9 << 32) | _1;

				seconds = _2 % 60;
				//v19 = (signed __int64)__PAIR__((unsigned __int64)(signed __int64)((double)(signed __int64)pParty->uTimePlayed * 0.234375) >> 32,
				//                        v9)
				//    % 60;

				hours = v12;
				weeks = v15;
				months = v16 % 12;
				if ( v3->field_10 )
				{
					++years;
				}
				else
				{
					if ( v3->field_12 )
					{
						++months;
					}
					else
					{
						if ( v3->field_14 )
						{
							++weeks;
						}
						else
						{
							++days;
							minutes = v3->field_18;
							hours = v3->field_16;
							seconds = v3->field_1A;
						}
					}
				}
                v3->next_fire_time = (signed __int64)((double)((seconds
					+ 60 * minutes
					+ 3600 * hours
					+ 0x93A80 * weeks
					+ 0x15180 * days
					+ 0x24EA00 * (months + 12i64 * years)) << 7)
					* 0.033333335);

				++dword_5B65C8_timers_count;
			}
		}
	}
}

//----- (00444360) --------------------------------------------------------
void Level_LoadEvtAndStr(const char *pLevelName)
{
  char pContainerName[120]; // [sp+8h] [bp-98h]@1

  sprintf(pContainerName, "%s.evt", pLevelName);
  uLevelEVT_Size = LoadEventsToBuffer(pContainerName, pLevelEVT.data(), 9216);

  sprintf(pContainerName, "%s.str", pLevelName);
  uLevelStrFileSize = LoadEventsToBuffer(pContainerName, pLevelStr.data(), 9216);
  if (uLevelStrFileSize)
    LoadLevel_InitializeLevelStr();
}

//----- (00444D80) --------------------------------------------------------
int GetTravelTime()
{
  signed int v0; // esi@1

  v0 = uDefaultTravelTime_ByFoot;
  if ( CheckHiredNPCSpeciality(Guide) )
    --v0;
  if ( CheckHiredNPCSpeciality(Tracker) )
    v0 -= 2;
  if ( CheckHiredNPCSpeciality(Pathfinder) )
    v0 -= 3;
  if ( CheckHiredNPCSpeciality(Explorer) )
    --v0;
  if ( v0 < 1 )
    v0 = 1;
  return v0;
}
// 6BD07C: using guessed type int uDefaultTravelTime_ByFoot;

//----- (004451A8) --------------------------------------------------------
void __fastcall sub_4451A8_press_any_key(int a1, int a2, int a4)
{
  int v3; // esi@1
  int v4; // edi@1

  v3 = a2;
  v4 = a1;
  if ( !pGUIWindow2 )
  {
    if ( pParty->uFlags & 2 )
      pGame->Draw();
    pAudioPlayer->StopChannels(-1, -1);
    pMiscTimer->Pause();
    pEventTimer->Pause();
    dword_5C3418 = v4;
    dword_5C341C = v3;
    _591094_decoration = activeLevelDecoration;
    pGUIWindow2 = GUIWindow::Create(0, 0, 640, 480, WINDOW_GreetingNPC, a4, 0);
    pGUIWindow2->CreateButton( 61, 424, 31, 40, 2, 94, UIMSG_SelectCharacter, 1, '1', "", 0);
    pGUIWindow2->CreateButton(177, 424, 31, 40, 2, 94, UIMSG_SelectCharacter, 2, '2', "", 0);
    pGUIWindow2->CreateButton(292, 424, 31, 40, 2, 94, UIMSG_SelectCharacter, 3, '3', "", 0);
    pGUIWindow2->CreateButton(407, 424, 31, 40, 2, 94, UIMSG_SelectCharacter, 4, '4', "", 0);
  }
}

//----- (004452BB) --------------------------------------------------------
void sub_4452BB()
{
  pGUIWindow2->Release();
  pGUIWindow2 = 0;
  activeLevelDecoration = _591094_decoration;
  EventProcessor(dword_5C3418, 0, 1, dword_5C341C);
  activeLevelDecoration = NULL;
  pEventTimer->Resume();
}

//----- (004465DF) --------------------------------------------------------
int sub_4465DF_check_season(int a1)
{
  unsigned int v1; // eax@1
  unsigned int v2; // edx@1
  int v3; // ecx@2
  int v4; // ecx@3
  char v6; // zf@9

  v1 = pParty->uCurrentMonth + 1;
  v2 = pParty->uDaysPlayed + 1;
  if ( a1 )
  {
    v3 = a1 - 1;
    if ( v3 )
    {
      v4 = v3 - 1;
      if ( v4 )
      {
        if ( v4 != 1 )
          return 0;
        if ( v1 != 12 )
        {
          if ( (signed int)v1 >= 1 && (signed int)v1 <= 2 )
            return 1;
          v6 = v1 == 3;
LABEL_24:
          if ( !v6 || (signed int)v2 >= 21 )
            return 0;
          return 1;
        }
      }
      else
      {
        if ( v1 != 9 )
        {
          if ( (signed int)v1 >= 10 && (signed int)v1 <= 11 )
            return 1;
          v6 = v1 == 12;
          goto LABEL_24;
        }
      }
    }
    else
    {
      if ( v1 != 6 )
      {
        if ( (signed int)v1 >= 7 && (signed int)v1 <= 8 )
          return 1;
        v6 = v1 == 9;
        goto LABEL_24;
      }
    }
  }
  else
  {
    if ( v1 != 3 )
    {
      if ( (signed int)v1 >= 4 && (signed int)v1 <= 5 )
        return 1;
      v6 = v1 == 6;
      goto LABEL_24;
    }
  }
  if ( (signed int)v2 >= 21 )
    return 1;
  return 0;
}

//----- (0044861E) --------------------------------------------------------
void __fastcall sub_44861E_set_texture(unsigned int uFaceCog, const char *pFilename)
{
  unsigned int v2; // eax@2
  unsigned __int16 v3; // di@2
  signed int v4; // esi@5
  BLVFace *v5; // eax@7
  unsigned int *v6; // eax@8
  char *v7; // eax@9
  int v8; // edi@16
  char *v9; // esi@16
  ODMFace *v10; // eax@17
  unsigned int *v11; // eax@19
  unsigned __int16 v12; // [sp+Ch] [bp-18h]@2
  const char *Str2; // [sp+10h] [bp-14h]@1
  unsigned int v14; // [sp+14h] [bp-10h]@1
  signed int v15; // [sp+18h] [bp-Ch]@14
  int v16; // [sp+1Ch] [bp-8h]@15
  signed int v17; // [sp+20h] [bp-4h]@4
  signed int v18; // [sp+20h] [bp-4h]@16

  Str2 = pFilename;
  v14 = uFaceCog;
  if ( uFaceCog )
  {
    v2 = pBitmaps_LOD->LoadTexture(pFilename);
    v3 = v2;
    v12 = v2;
    if ( v2 != -1 ? (int)&pBitmaps_LOD->pTextures[v2] : 0 )
    {
      pBitmaps_LOD->pTextures[v2].palette_id2 = pPaletteManager->LoadPalette(pBitmaps_LOD->pTextures[v2].palette_id1);

      if ( uCurrentlyLoadedLevelType == 1 )
      {
        v17 = 1;
        if ( (signed int)pIndoor->uNumFaceExtras > 1 )
        {
          v4 = 1;
          do
          {
            if ( pIndoor->pFaceExtras[v4].sCogNumber == v14 )
            {
              v5 = &pIndoor->pFaces[pIndoor->pFaceExtras[v4].field_C];
              if ( BYTE1(v5->uAttributes) & 0x40 )
              {
                pIndoor->pFaces[pIndoor->pFaceExtras[v4].field_C].uBitmapID = pTextureFrameTable->FindTextureByName(
                                                                              Str2);
                v6 = (unsigned int *)&pIndoor->pFaces[pIndoor->pFaceExtras[v4].field_C].uBitmapID;
                if ( *(_WORD *)v6 )
                {
                  pTextureFrameTable->LoadAnimationSequenceAndPalettes(*(_WORD *)v6);
                }
                else
                {
                  *(_WORD *)v6 = v3;
                  v7 = (char *)&pIndoor->pFaces[pIndoor->pFaceExtras[v4].field_C].uAttributes;
                  v7[1] &= 0xBFu;
                }
              }
              else
              {
                v5->uBitmapID = v3;
              }
            }
            ++v17;
            ++v4;
          }
          while ( v17 < (signed int)pIndoor->uNumFaceExtras );
        }
        pParty->uFlags |= 2u;
      }
      else
      {
        v15 = 0;
        if ( (signed int)pOutdoor->uNumBModels > 0 )
        {
          v16 = 0;
          do
          {
            v8 = 0;
            v9 = (char *)&pOutdoor->pBModels[v16].pVertices;
            v18 = 0;
            if ( (signed int)pOutdoor->pBModels[v16].uNumFaces > 0 )
            {
              do
              {
                v10 = (ODMFace *)(v8 + *((_DWORD *)v9 + 4));
                if ( v10->sCogNumber == v14 )
                {
                  if ( BYTE1(v10->uAttributes) & 0x40 )
                  {
                    *(_WORD *)(*((_DWORD *)v9 + 4) + v8 + 272) = pTextureFrameTable->FindTextureByName(
                                                                   Str2);
                    v11 = (unsigned int *)(*((_DWORD *)v9 + 4) + v8 + 272);
                    if ( *(_WORD *)v11 )
                    {
                      pTextureFrameTable->LoadAnimationSequenceAndPalettes(*(_WORD *)v11);
                    }
                    else
                    {
                      *(_WORD *)v11 = v12;
                      *(_BYTE *)(*((_DWORD *)v9 + 4) + v8 + 29) &= 0xBFu;
                    }
                  }
                  else
                  {
                    v10->uTextureID = v12;
                  }
                }
                ++v18;
                v8 += 308;
              }
              while ( v18 < *((_DWORD *)v9 + 2) );
            }
            ++v15;
            ++v16;
          }
          while ( v15 < (signed int)pOutdoor->uNumBModels );
        }
      }
      pParty->uFlags |= 2u;
    }
  }
}

//----- (0044882F) --------------------------------------------------------
void __fastcall SetDecorationSprite(uint16_t uCog, bool bHide, const char *pFileName)
{
  for (size_t i = 0; i < uNumLevelDecorations; i++)
  {
    if (pLevelDecorations[i].uCog == uCog)
    {
      if (pFileName && strcmp(pFileName, "0"))
      {
        pLevelDecorations[i].uDecorationDescID = pDecorationList->GetDecorIdByName(pFileName);
        pDecorationList->InitializeDecorationSprite(pLevelDecorations[i].uDecorationDescID);
      }

      if (bHide)
        pLevelDecorations[i].uFlags &= ~LEVEL_DECORATION_INVISIBLE;
      else
        pLevelDecorations[i].uFlags |= LEVEL_DECORATION_INVISIBLE;

      pParty->uFlags |= 2u;
    }
  }
}

//----- (0044892E) --------------------------------------------------------
void __fastcall sub_44892E_set_faces_bit(int sCogNumber, int bit, int on)
{
  signed int v3; // esi@2
  signed int v4; // ecx@4
  char *v5; // eax@6
  int v6; // edi@13
  char *v7; // esi@13
  signed int v8; // ecx@13
  ODMFace *v9; // eax@14
  int v10; // [sp+0h] [bp-Ch]@1
  signed int v11; // [sp+4h] [bp-8h]@11
  int v12; // [sp+8h] [bp-4h]@12

  v10 = sCogNumber;
  if ( sCogNumber )
  {
    v3 = 1;
    if ( uCurrentlyLoadedLevelType == 1 )
    {
      if ( (signed int)pIndoor->uNumFaceExtras > 1 )
      {
        v4 = 1;
        do
        {
          if ( pIndoor->pFaceExtras[v4].sCogNumber == v10 )
          {
            v5 = (char *)&pIndoor->pFaces[pIndoor->pFaceExtras[v4].field_C].uAttributes;
            if ( on )
              *(_DWORD *)v5 |= bit;
            else
              *(_DWORD *)v5 &= ~bit;
          }
          ++v3;
          ++v4;
        }
        while ( v3 < (signed int)pIndoor->uNumFaceExtras );
      }
      pParty->uFlags |= 2u;
    }
    else
    {
      v11 = 0;
      if ( (signed int)pOutdoor->uNumBModels > 0 )
      {
        v12 = 0;
        do
        {
          v6 = 0;
          v7 = (char *)&pOutdoor->pBModels[v12].pVertices;
          v8 = 0;
          if ( (signed int)pOutdoor->pBModels[v12].uNumFaces > 0 )
          {
            do
            {
              v9 = (ODMFace *)(v6 + *((_DWORD *)v7 + 4));
              if ( v9->sCogNumber == v10 )
              {
                if ( on )
                  v9->uAttributes |= bit;
                else
                  v9->uAttributes &= ~bit;
              }
              ++v8;
              v6 += 308;
            }
            while ( v8 < *((_DWORD *)v7 + 2) );
          }
          ++v11;
          ++v12;
        }
        while ( v11 < (signed int)pOutdoor->uNumBModels );
      }
    }
    pParty->uFlags |= 2u;
  }
}

//----- (00448A98) --------------------------------------------------------
void __fastcall ToggleActorGroupFlag(unsigned int uGroupID, unsigned int uFlag, unsigned int bToggle)
{
  unsigned int v3; // ebx@1
  unsigned int v4; // ebp@1
  signed int v5; // edi@1
  Actor *v6; // esi@4
  size_t v7; // ecx@10
  Actor *v8; // eax@11
  unsigned __int16 v9; // dx@14

  v4 = uGroupID;
  v5 = Standing;
  v3 = uFlag;
  if ( uGroupID )
  {
    if ( bToggle )
    {
      if ( (signed int)uNumActors > Standing )
      {
        v6 = pActors.data();//[0].uAttributes;
        do
        {
          if ( v6->uGroup == v4 )
          {
            v6->uAttributes |= v3;
            if ( v3 == 0x10000 )
            {
              v6->uAIState = Disabled;
              v6->UpdateAnimation();
            }
          }
          ++v5;
          ++v6;
        }
        while ( v5 < (signed int)uNumActors );
      }
    }
    else
    {
      v7 = uNumActors;
      if ( (signed int)uNumActors > Standing )
      {
        v8 = pActors.data();//[0].uAIState;
        do
        {
          if ( v8->uGroup == v4 )
          {
            if ( v3 == 0x10000 )
            {
              v9 = v8->uAIState;
              if ( v8->uAIState != Dead )
              {
                if ( v9 != 4 && v9 != 11 )
                  v8->uAIState = Standing;
              }
            }
			LODWORD(v8->uAttributes) &= ~v3;
          }
          ++v8;
          --v7;
        }
        while ( v7 );
      }
    }
  }
}

//----- (00448B45) --------------------------------------------------------
void  GameUI_StatusBar_UpdateTimedString(unsigned int bForceHide)
{
  if ( bForceHide || GameUI_Footer_TimeLeft && GetTickCount() >= GameUI_Footer_TimeLeft )
    GameUI_Footer_TimeLeft = 0;
}

//----- (00448B67) --------------------------------------------------------
void OnTimer(int __unused)
{
  if (pEventTimer->bPaused)
    return;
  
  if (__unused)
    _5773C0_unused = 0;
  
  auto v13 = (signed __int64)(pParty->uTimePlayed - _5773B8_event_timer) / 128;
  if (!v13)
    return;

  //uint _v2v3 = pParty->uTimePlayed;
  //v3 = HIDWORD(pParty->uTimePlayed);
  //v2 = LODWORD(pParty->uTimePlayed);

  _5773B8_event_timer = pParty->uTimePlayed;

  for (uint i = 0; i < dword_5B65C8_timers_count; ++i)
  {
        //v4 = (char *)&array_5B5928_timers[0].field_C;
    auto timer = array_5B5928_timers + i;
        //while ( 1 )
        //{
          //v5 = *(short *)v4;
    if (timer->time_left_to_fire)
    {
      if (v13 < timer->time_left_to_fire)
        timer->time_left_to_fire -= v13;
      else
      {
        timer->time_left_to_fire = timer->fire_interval;
        EventProcessor(timer->timer_evt_ID, 0, 1, timer->timer_evt_seq_num);
      }
    }
    else
    {
      if (timer->next_fire_time < pParty->uTimePlayed)
      {
        uint next_trigger_time = 1 * 60 * 60 * 24; // 1 day
        if (timer->field_10)
          next_trigger_time = 336 * 60 * 60 * 24; // 1 year
        else if (timer->field_12)
          next_trigger_time = 28 * 60 * 60 * 24; // 1 month
        else if (timer->field_14)
          next_trigger_time = 7 * 60 * 60 * 24; // 1 week

        timer->next_fire_time += (next_trigger_time * 128) / 3.0f;
        if (timer->next_fire_time < pParty->uTimePlayed) // make sure in wont fire several times in a row if big time interval has lapsed
          timer->next_fire_time = pParty->uTimePlayed;

        EventProcessor(timer->timer_evt_ID, 0, 1, timer->timer_evt_seq_num);
      }
    }
  }
}

//----- (00481D77) --------------------------------------------------------
void _outdoor_project(RenderVertexSoft *v)
{
  double v1; // st7@1
  double v2; // st7@1

  v1 = 1.0 / (v->vWorldViewPosition.x + 0.0000001);
  v->_rhw = v1;
  v2 = v1 * (double)pODMRenderParams->int_fov_rad;
  v->vWorldViewProjX = (double)pViewport->uScreenCenterX - v2 * v->vWorldViewPosition.y;
  v->vWorldViewProjY = (double)pViewport->uScreenCenterY - v2 * v->vWorldViewPosition.z;
}

//----- (00448CF4) --------------------------------------------------------
void __fastcall sub_448CF4_spawn_monsters(__int16 typeindex, __int16 level, int count, int x, int y, int z, int group, unsigned int uUniqueName)
{
  __int16 v8; // di@1
  __int16 v9; // si@1
  unsigned int v10; // eax@1
  size_t v11; // ebx@2
  signed int v12; // esi@2
  Actor *pActor;//Actor_uYawAngle_cr *v13; // ebx@3
  AIDirection a3; // [sp+Ch] [bp-50h]@2
  AIDirection v15; // [sp+28h] [bp-34h]@2
  //SpawnPointMM7 v16; // [sp+44h] [bp-18h]@1

  v8 = typeindex;
  v9 = level;

  SpawnPointMM7 v16; // [sp+44h] [bp-18h]@1
  //SpawnPointMM7::SpawnPointMM7(&v16);

  v16.vPosition.x = x;
  v16.vPosition.y = y;
  v16.vPosition.z = z;
  v16.uGroup = group;
  v16.uRadius = 32;
  v16.uKind = 3;
  v16.uIndex = v8 + 2 * v9 + v9;
  v10 = pMapStats->GetMapInfo(pCurrentMapName);
  if ( v10 )
  {
    v11 = uNumActors;
    SpawnEncounter(&pMapStats->pInfos[v10], &v16, 0, count, 0);
    Actor::GetDirectionInfo(PID(OBJECT_Actor, v11), 4u, &v15, 1);
    v12 = v11;
    if ( (signed int)v11 < (signed int)uNumActors )
    {
      for ( pActor = &pActors[v11]; v12 < (signed int)uNumActors; ++pActor )
      {
        pActor->PrepareSprites(0);
        ++v12;
        pActor->uYawAngle = v15.uYawAngle;
        pActor->dword_000334_unique_name = uUniqueName;
      }
    }
  }
}


//----- (0044987B) --------------------------------------------------------
void sub_44987B(const char *pMapName, MapStartPoint start_point)
{
  const char *v2; // edi@1

  v2 = pMapName;
  pAudioPlayer->StopChannels(-1, -1);
  pGameLoadingUI_ProgressBar->Initialize(GUIProgressBar::TYPE_None);
  if ( _stricmp(pCurrentMapName, v2) )
    SaveGame(1, 0);

  uGameState = GAME_STATE_2;
  strcpy(pCurrentMapName, v2);
  uLevel_StartingPointType = start_point;
}
// 6BE35C: using guessed type int uLevel_StartingPointType;

//----- (004498D5) --------------------------------------------------------
void TeleportToStartingPoint(MapStartPoint point)
{
  //unsigned int v1; // ecx@2
  //int v2; // ecx@3
  //int v3; // ecx@4
  unsigned __int16 v4; // ax@11
  signed int v5; // ecx@12
  LevelDecoration *v6; // edx@13
  signed int v7; // ecx@17
  int v8; // eax@17
  int v9; // ecx@17
  const char *v10; // [sp-4h] [bp-84h]@6
  char pName[128]; // [sp+8h] [bp-78h]@11

  switch (point)
  {
    case MapStartPoint_Party: v10 = "Party Start"; break;
    case MapStartPoint_North: v10 = "North Start"; break;
    case MapStartPoint_South: v10 = "South Start"; break;
    case MapStartPoint_East: v10 = "East Start";  break;
    case MapStartPoint_West: v10 = "West Start";  break;
    default:
      Error("Invalid enum value: %u", point);
  }

  strcpy(pName, v10);
  v4 = pDecorationList->GetDecorIdByName(pName);
  if ( v4 )
  {
    v5 = 0;
    if ( (signed int)uNumLevelDecorations > 0 )
    {
      v6 = pLevelDecorations.data();
      while ( v6->uDecorationDescID != (signed __int16)v4 )
      {
        ++v5;
        ++v6;
        if ( v5 >= (signed int)uNumLevelDecorations )
          goto LABEL_20;
      }
      v7 = v5;
      pParty->vPosition.x = pLevelDecorations[v7].vPosition.x;
      pParty->vPosition.y = pLevelDecorations[v7].vPosition.y;
      pParty->vPosition.z = pLevelDecorations[v7].vPosition.z;
      pParty->uFallStartY = pParty->vPosition.z;
      v8 = (signed int)(stru_5C6E00->uIntegerHalfPi * pLevelDecorations[v7].field_1A) / 90;
      v9 = pLevelDecorations[v7].field_10_y_rot;
      pParty->sRotationY = v8;
      if ( v9 )
        pParty->sRotationY = v9;
      pParty->sRotationX = 0;
      pParty->uFallSpeed = 0;
    }
LABEL_20:
    if ( dword_5B65C0 )
    {
      if ( _5B65A8_npcdata_uflags_or_other )
        pParty->vPosition.x = _5B65A8_npcdata_uflags_or_other;
      if ( _5B65AC_npcdata_fame_or_other )
        pParty->vPosition.y = _5B65AC_npcdata_fame_or_other;
      if ( _5B65B0_npcdata_rep_or_other )
      {
        pParty->vPosition.z = _5B65B0_npcdata_rep_or_other;
        pParty->uFallStartY = _5B65B0_npcdata_rep_or_other;
      }
      if ( _5B65B4_npcdata_loword_house_or_other != -1 )
        pParty->sRotationY = _5B65B4_npcdata_loword_house_or_other;
      if ( _5B65B8_npcdata_hiword_house_or_other )
        pParty->sRotationX = _5B65B8_npcdata_hiword_house_or_other;
      if ( dword_5B65BC )
        pParty->uFallSpeed = dword_5B65BC;
    }
    _5B65B4_npcdata_loword_house_or_other = -1;
    dword_5B65C0 = 0;
    dword_5B65BC = 0;
    _5B65B8_npcdata_hiword_house_or_other = 0;
    _5B65B0_npcdata_rep_or_other = 0;
    _5B65AC_npcdata_fame_or_other = 0;
    _5B65A8_npcdata_uflags_or_other = 0;
  }
}



//----- (00449A49) --------------------------------------------------------
__int16 __fastcall sub_449A49_door_switch_animation(unsigned int uDoorID, int a2)
{
  int v2; // eax@1
  int v3; // ebx@1
  signed int v4; // esi@2
  int v5; // edx@2
  BLVDoor *v6; // ecx@8
  unsigned int v7; // edx@18
  signed int v8; // esi@19
  int v9; // eax@19
  //char Args; // [sp+Ch] [bp-78h]@6

  LOWORD(v2) = LOWORD(pIndoor->pDoors);
  v3 = a2;
  if ( !pIndoor->pDoors )
    return v2;
  v4 = 0;
  v5 = (int)&pIndoor->pDoors->uDoorID;
  do
  {
    if ( *(int *)v5 == uDoorID )
      break;
    ++v4;
    v5 += 80;
  }
  while ( v4 < 200 );
  if ( v4 >= 200 )
  {
    Error("Unable to find Door ID: %i!", uDoorID);
  }
  v6 = &pIndoor->pDoors[v4];
  if ( v3 == 2 )
  {
    LOWORD(v2) = v6->uState;
    if ( (short)v2 == 3 || (short)v2 == 1 )
      return v2;
    if ( (short)v2 )
      goto LABEL_14;
  }
  else
  {
    if ( !v3 )
    {
LABEL_14:
      LOWORD(v2) = v6->uState;
      if ( (short)v2 && (short)v2 != 3 )
      {
        v6->uState = BLVDoor::Closing;
        if ( (short)v2 == 2 )
        {
LABEL_17:
          v6->uTimeSinceTriggered = 0;
          return v2;
        }
        v7 = v6->uTimeSinceTriggered;
        v2 = 15360;
        if ( v7 != 15360 )
        {
          v8 = v6->uOpenSpeed;
          v9 = v6->uCloseSpeed;
LABEL_26:
          v2 = (v6->uMoveLength << 7) / v8 - ((signed int)(v7 * v9) / 128 << 7) / v8;
          goto LABEL_27;
        }
        goto LABEL_27;
      }
      return v2;
    }
    if ( v3 != 1 )
      return v2;
  }
  LOWORD(v2) = v6->uState;
  if ( (short)v2 != 2 && (short)v2 != 1 )
  {
    v6->uState = BLVDoor::Opening;
    if ( !(short)v2 )
      goto LABEL_17;
    v7 = v6->uTimeSinceTriggered;
    v2 = 15360;
    if ( v7 != 15360 )
    {
      v8 = v6->uCloseSpeed;
      v9 = v6->uOpenSpeed;
      goto LABEL_26;
    }
LABEL_27:
    v6->uTimeSinceTriggered = v2;
  }
  return v2;
}

//----- (00449B57) --------------------------------------------------------
bool _449B57_test_bit( unsigned __int8 *a1, __int16 a2 )
{
  return (a1[(a2 - 1) >> 3] & (0x80u >> (a2 - 1) % 8)) != 0;
}

//----- (00449B7E) --------------------------------------------------------
void _449B7E_toggle_bit(unsigned char *pArray, __int16 a2, unsigned __int16 bToggle)
{
  signed int v3; // esi@1
  unsigned char set_bit; // edx@1

  v3 = a2 - 1;
  set_bit = 0x80 >> v3 % 8;
  if ( bToggle )
    pArray[v3 / 8] |=  set_bit;
  else
    pArray[v3 / 8] &= ~set_bit;
}

//----- (0044C175) --------------------------------------------------------
void ShowStatusBarString( const char *pString, unsigned int uNumSeconds )
{
  strcpy(GameUI_Footer_TimedString.data(), pString);
  GameUI_Footer_TimeLeft = 1000 * uNumSeconds + GetTickCount();

  for (int i = pFontLucida->GetLineWidth(GameUI_Footer_TimedString.data());
        i > 450;
        i = pFontLucida->GetLineWidth(GameUI_Footer_TimedString.data()) )
    GameUI_Footer_TimedString[strlen(GameUI_Footer_TimedString.data()) - 1] = 0;
}

//----- (0044C1D0) --------------------------------------------------------
void ShowNothingHereStatus()
{
  if ( !GameUI_Footer_TimeLeft )
    ShowStatusBarString(pGlobalTXT_LocalizationStrings[521], 2);// Nothing here
}

//----- (0044C28B) --------------------------------------------------------
int const_2()
{
  return 2;
}

//----- (0044C28F) --------------------------------------------------------
bool TeleportToNWCDungeon()
{
  if (!_stricmp("nwc.blv", pCurrentMapName))
    return false;

  _5B65A8_npcdata_uflags_or_other = 0;
  _5B65AC_npcdata_fame_or_other = 0;
  _5B65B0_npcdata_rep_or_other = 0;
  _5B65B4_npcdata_loword_house_or_other = 0;
  _5B65B8_npcdata_hiword_house_or_other = 0;
  dword_5B65BC = 0;
  dword_5B65C0 = 0;

  pGameLoadingUI_ProgressBar->uType = GUIProgressBar::TYPE_Fullscreen;
  sub_44987B("nwc.blv", MapStartPoint_Party);
  pCurrentScreen = SCREEN_GAME;
  return true;
}

//----- (00401000) --------------------------------------------------------
void mm7__vector_constructor(void *a1, int objSize, int numObjs, int ( *constructor)(int))
{
  void *v4; // esi@2
  int v5; // edi@2

  if ( numObjs - 1 >= 0 )
  {
    v4 = a1;
    v5 = numObjs;
    do
    {
      constructor((int)v4);
      v4 = (char *)v4 + objSize;
      --v5;
    }
    while ( v5 );
  }
}

//----- (0040261D) --------------------------------------------------------
void stru298::Add(__int16 uID, __int16 a3, __int16 x, __int16 y, __int16 z, char a7, char a8)
{
  if (count < 100)
  {
    pIDs[count] = uID;
    pXs[count] = x;
    pYs[count] = y;
    pZs[count] = z;
    field_324[count] = a3;
    field_3EC[count] = a8;
    field_450[count++] = a7;
  }
}

//----- (00402CAE) --------------------------------------------------------
int stru193_math::Cos(int angle)
{
  int v2; // eax@1

  //a2: (angle - uIntegerHalfPi)    for  sin(angle)
  //    (angle)                     for  cos(angle)

  v2 = uDoublePiMask & angle;
  
  if ( v2 > uIntegerPi )
    v2 = uIntegerDoublePi - v2;
  if ( v2 >= uIntegerHalfPi )
    return -pCosTable[uIntegerPi - v2];
  else
    return pCosTable[v2];
}