diff Outdoor.cpp @ 2043:2ccf638342d6

int max_flight_height and GetCeilingHeight function
author Ritor1
date Tue, 26 Nov 2013 17:49:42 +0600
parents 7a9477135943
children 28cb79ae2f6f
line wrap: on
line diff
--- a/Outdoor.cpp	Mon Nov 25 17:09:39 2013 +0600
+++ b/Outdoor.cpp	Tue Nov 26 17:49:42 2013 +0600
@@ -25,6 +25,7 @@
 #include "Viewport.h"
 #include "Events.h"
 #include "ParticleEngine.h"
+#include "TurnEngine.h"
 
 #include "mm7_data.h"
 #include "MM7.h"
@@ -3648,3 +3649,1211 @@
   //sr_6BE060[1] = 1;
   //RotationToInts();
 }
+//----- (00473893) --------------------------------------------------------
+void ODM_ProcessPartyActions()
+{
+  int v1; // edi@1
+  int v2; // ebx@1
+  int v3; // eax@14
+  int v6; // esi@45
+  ODMFace *face; // 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 high_fall_flag; // [sp+1Ch] [bp-78h]@33
+  int v102; // [sp+20h] [bp-74h]@1
+  int v103; // [sp+24h] [bp-70h]@1
+  bool bFeatherFall; // [sp+28h] [bp-6Ch]@4
+  int v105; // [sp+2Ch] [bp-68h]@24
+  bool 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
+  bool hovering; // [sp+48h] [bp-4Ch]@1
+  int v113; // [sp+4Ch] [bp-48h]@1
+  bool party_running_flag; // [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
+  bool party_walking_flag; // [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
+
+  v1 = 0;
+  v103 = 0;
+  v2 = 0;
+  //*(float *)&v128 = 0.0;
+  v128 = 0;
+  v129 = 0;
+  pX = pParty->vPosition.x;
+  pY = pParty->vPosition.y;
+  pZ = pParty->vPosition.z;
+  v113 = pParty->field_6F0;
+  hovering = false;
+  bool partyAtHighSlope = IsTerrainSlopeTooHigh(pParty->vPosition.x, pParty->vPosition.y);
+  party_running_flag = false;
+  party_walking_flag = false;
+  v102 = 0;
+  pModel = 0;
+  bWaterWalk = false;
+
+  if (!pParty->FeatherFallActive())//Проверка падение пера
+  {
+    bFeatherFall = false;
+    for (int i = 0; i < 4; ++i)
+      if (pParty->pPlayers[i].WearsItemAnyWhere(ITEM_ARTIFACT_LADYS_ESCORT))  // seems like flying boots
+      {
+        bFeatherFall = true;
+        break;
+      }
+  }
+  else
+    bFeatherFall = true;
+
+  pParty->uFlags &= ~PARTY_FLAGS_1_STANDING_ON_WATER;
+  if (pParty->WaterWalkActive())//Проверка хождения по воде
+  {
+    //LOBYTE(pParty->uFlags) &= 0x7Fu;
+    bWaterWalk = true;
+    *(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 = false;
+  }
+
+  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
+    {
+      if ( !pParty->pPlayers[i].HasEnchantedItemEquipped(72) && !pParty->pPlayers[i].WearsItem(ITEM_ARTIFACT_HERMES_SANDALS, EQUIP_BOOTS) )
+      {
+        pParty->pPlayers[i].ReceiveDamage(
+            (signed int)((pParty->uFallStartY - pZ) * (unsigned __int64)(pParty->pPlayers[i].GetMaxHealth() / 10)) / 256, DMGT_PHISYCAL);
+        v105 = 20 - pParty->pPlayers[i].GetParameterBonus(pParty->pPlayers[i].GetActualEndurance());
+        pParty->pPlayers[i].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 = GetCeilingHeight(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
+    hovering = true;
+  high_fall_flag = pZ - v111 <= 32;
+
+  if ( bWalkSound && pParty->walk_sound_timer)//timer update
+  {
+    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 (!hovering)
+  {
+    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 )
+        {
+          face = 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(face[v6].uAttributes) & 4 )
+          {
+            pParty->floor_face_pid = PID(OBJECT_BModel, bmodel_standing_on_pid);
+            v103 = face[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 )
+          {
+            extern int max_flight_height;
+            if ( pParty->vPosition.z < max_flight_height || hovering )
+            {
+              pZ += 30;
+              v113 += 30;
+              pParty->bFlying = true;
+              if ( pZ > max_flight_height )
+              {
+                pZ = max_flight_height;
+                v113 = max_flight_height;
+              }
+              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 = false;
+                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 = false;
+          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 = true;
+            pModel = (BSPModel *)1;
+            if ( pZ <= v111 )
+            {
+              pParty->bFlying = false;
+              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;
+        party_walking_flag = true;
+      }
+      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;
+        party_walking_flag = true;
+      }
+      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;
+        int dy = sin_y * pParty->uWalkSpeed * fWalkSpeedMultiplier;
+
+        extern bool new_speed;
+        if ( new_speed )
+        {
+          v2 += dx * 12;
+          v1 += dy * 12;
+        }
+        else
+        {
+          v2 += dx;
+          v1 += dy;
+        }
+
+        v128 = v1;
+        party_walking_flag = true;
+      }
+      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;
+          party_walking_flag = true;
+        }
+        else
+        {
+          v2 += 2 * dx;
+          v1 += 2 * dy;
+          
+          v128 = v1;
+          party_running_flag = true;
+        }
+      }
+      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;
+        party_walking_flag = true;
+      }
+      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;
+          party_walking_flag = true;
+        }
+      }
+      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) && !hovering && pParty->field_24 && !(pParty->uFlags & 4) && !(BYTE1(pParty->uFlags) & 2) )
+        {
+          v126 = pParty->field_24 << 6;
+          hovering = true;
+          pParty->uFallSpeed = (signed __int64)((double)(pParty->field_24 << 6) * 1.5 + (double)pParty->uFallSpeed);
+        }
+      break;
+
+      case PARTY_Land:
+        if (pParty->bFlying)
+        {
+          pParty->uFlags |= PARTY_FLAGS_1_LANDING;
+          pParty->uFallSpeed = 0;
+        }
+        pParty->bFlying = false;
+        pPartyActionQueue->uNumActions = 0;
+      break;
+
+      default:
+        assert(false);
+
+
+    }
+  }
+
+//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 (hovering && !pParty->bFlying)//расчёт скорости падения
+  {
+    v33 = -(pEventTimer->uTimeElapsed * GetGravityStrength());
+    v34 = pParty->uFallSpeed + 2 * v33;
+    pParty->uFallSpeed += 2 * v33;
+  }
+  else if (!partyAtHighSlope)
+  {
+    v34 = pParty->uFallSpeed;
+  }
+  else if (!hovering)
+  {
+    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 ( hovering )
+  {
+	  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)
+		  {
+            if (!pParty->pPlayers[i].HasEnchantedItemEquipped(72) && !pParty->pPlayers[i].WearsItem(ITEM_ARTIFACT_HERMES_SANDALS, EQUIP_BOOTS) && pParty->pPlayers[i].CanAct())
+              pParty->pPlayers[i].PlaySound(SPEECH_Falling_scream, 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);
+    int 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 = true;
+		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 = false;
+        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 )
+    {
+      if ( party_running_flag && (!hovering || !high_fall_flag) )
+      {
+        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_RunAlong3DModel, 804, 1, -1, 0, 0, 0, 0);//бег на 3D Modelи
+        else
+        {
+          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 ( party_walking_flag && (!hovering || !high_fall_flag) )
+      {
+        if ( is_not_on_bmodel
+          || BYTE1(pOutdoor->pBModels[pParty->floor_face_pid >> 9].pFaces[(pParty->floor_face_pid >> 3) & 0x3F].uAttributes) & 0x20 )
+        {
+          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_WalkAlong3DModel, 804, 1, -1, 0, 0, 0, 0);// хождение на 3D Modelи
+      }
+    }
+    else
+    {
+      pAudioPlayer->_4AA258(804);
+      pParty->walk_sound_timer = 64;
+    }
+  }
+
+  if ( !hovering || !high_fall_flag )
+    pParty->uFlags &= ~PARTY_FLAGS_1_FALLING;
+  else
+    pParty->uFlags |= PARTY_FLAGS_1_FALLING;
+  v126 = WorldPosToGridCellX(pParty->vPosition.x);
+  v65 = WorldPosToGridCellZ(pParty->vPosition.y) - 1;
+  unsigned int v114_a = WorldPosToGridCellX(pX);
+  v66 = WorldPosToGridCellZ(pY) - 1;
+  pModel = (BSPModel *)((~(unsigned int)pOutdoor->ActuallyGetSomeOtherTileInfo(v126, v65) >> 1) & 1);
+  v122 = (~(unsigned int)pOutdoor->ActuallyGetSomeOtherTileInfo(v114_a, v65) >> 1) & 1;
+  v67 = pOutdoor->ActuallyGetSomeOtherTileInfo(v126, v66);
+  v68 = 0;
+  v69 = (~(unsigned int)v67 >> 1) & 1;
+  if ( v114_a == 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 || !high_fall_flag || bWaterWalk || !pModel )
+    v77 = 1;
+  else
+    v77 = v122 != 0;
+  bool party_drowning_flag = false;
+  if ( !pParty->bFlying && high_fall_flag && !bWaterWalk )
+  {
+    if ( pModel )
+    {
+      v78 = v69 != 0;
+    }
+	else
+	{
+		party_drowning_flag = true;
+		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 ( !pParty->bFlying )
+        {
+          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 ( party_drowning_flag )
+  {
+    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;
+    }
+  }
+}
+//----- (0046D8E3) --------------------------------------------------------
+int GetCeilingHeight(int Party_X, signed int Party_Y, int Party_ZHeight, int pFaceID)
+{
+  signed int v13; // eax@25
+  int v14; // edx@27
+  int v16; // ST18_4@29
+  signed int v17; // edx@29
+  signed __int64 v18; // qtt@29
+  int v19; // eax@35
+  signed int v20; // ecx@37
+  signed int v22; // ebx@42
+  int v24; // edx@44
+  int v25; // eax@44
+  int v27; // [sp+10h] [bp-34h]@21
+  bool v34; // [sp+30h] [bp-14h]@21
+  bool v35; // [sp+34h] [bp-10h]@23
+  signed int v37; // [sp+38h] [bp-Ch]@21
+  signed int v38; // [sp+38h] [bp-Ch]@42
+  signed int v39; // [sp+3Ch] [bp-8h]@1
+
+  dword_720ED0[0] = -1;
+  dword_720E80[0] = -1;
+  v39 = 1;
+  ceiling_height_level[0] = 10000;//нет потолка
+  for ( uint i = 0; i < (signed int)pOutdoor->uNumBModels; ++i )
+  {
+    if ( Party_X <= pOutdoor->pBModels[i].sMaxX && Party_X >= pOutdoor->pBModels[i].sMinX
+      && Party_Y <= pOutdoor->pBModels[i].sMaxY && Party_Y >= pOutdoor->pBModels[i].sMinY )
+    {
+      for ( uint j = 0; j < pOutdoor->pBModels[i].uNumFaces; ++j )
+      {
+        if ( (pOutdoor->pBModels[i].pFaces[j].uPolygonType == POLYGON_Ceiling
+           || pOutdoor->pBModels[i].pFaces[j].uPolygonType == POLYGON_InBetweenCeilingAndWall)
+           && !(BYTE3(pOutdoor->pBModels[i].pFaces[j].uAttributes) & 0x20)
+           && Party_X <= pOutdoor->pBModels[i].pFaces[j].pBoundingBox.x2 && Party_X >= pOutdoor->pBModels[i].pFaces[j].pBoundingBox.x1
+           && Party_Y <= pOutdoor->pBModels[i].pFaces[j].pBoundingBox.y2 && Party_Y >= pOutdoor->pBModels[i].pFaces[j].pBoundingBox.y1 )
+        {
+          for ( uint v = 0; v < pOutdoor->pBModels[i].pFaces[j].uNumVertices; v++ )
+          {
+            word_720DB0_xs[2 * v] = pOutdoor->pBModels[i].pFaces[j].pXInterceptDisplacements[v] + LOWORD(pOutdoor->pBModels[i].pVertices.pVertices[pOutdoor->pBModels[i].pFaces[j].pVertexIDs[v]].x);
+            word_720CE0_ys[2 * v] = pOutdoor->pBModels[i].pFaces[j].pXInterceptDisplacements[v] + LOWORD(pOutdoor->pBModels[i].pVertices.pVertices[pOutdoor->pBModels[i].pFaces[j].pVertexIDs[v]].y);
+            word_720DB0_xs[2 * v + 1] = pOutdoor->pBModels[i].pFaces[j].pXInterceptDisplacements[v] + LOWORD(pOutdoor->pBModels[i].pVertices.pVertices[pOutdoor->pBModels[i].pFaces[j].pVertexIDs[v + 1]].x);
+            word_720CE0_ys[2 * v + 1] = pOutdoor->pBModels[i].pFaces[j].pXInterceptDisplacements[v] + LOWORD(pOutdoor->pBModels[i].pVertices.pVertices[pOutdoor->pBModels[i].pFaces[j].pVertexIDs[v + 1]].y);
+          }
+          v27 = 2 * pOutdoor->pBModels[i].pFaces[j].uNumVertices;
+          word_720DB0_xs[2 * pOutdoor->pBModels[i].pFaces[j].uNumVertices] = word_720DB0_xs[0];
+          word_720CE0_ys[2 * pOutdoor->pBModels[i].pFaces[j].uNumVertices] = word_720CE0_ys[0];
+          v34 = word_720CE0_ys[0] >= Party_Y;
+          v37 = 0;
+          for ( uint v = 0; v < v27; ++v )
+          {
+            if ( v37 >= 2 )
+              break;
+            v35 = word_720CE0_ys[v + 1] >= Party_Y;
+            if ( v34 != v35 )
+            {
+              v13 = word_720DB0_xs[v + 1] >= Party_X ? 0 : 2;
+              v14 = v13 | (word_720DB0_xs[v] < Party_X);
+              if ( v14 != 3 )
+              {
+                if ( !v14 || ( v16 = word_720CE0_ys[v + 1] - word_720CE0_ys[v],
+                  v17 = Party_Y - word_720CE0_ys[v],
+                  LODWORD(v18) = v17 << 16,
+                  HIDWORD(v18) = v17 >> 16,
+                  (signed int)(((unsigned __int64)(((signed int)word_720DB0_xs[v + 1]
+                  - (signed int)word_720DB0_xs[v]) * v18 / v16) >> 16) + word_720DB0_xs[v]) >= Party_X) )
+                  ++v37;
+              }
+            }
+            v34 = v35;
+          }
+          if ( v37 == 1 )
+          {
+            if ( v39 >= 20 )
+              break;
+            if ( pOutdoor->pBModels[i].pFaces[j].uPolygonType == POLYGON_Ceiling )
+              v19 = pOutdoor->pBModels[i].pVertices.pVertices[pOutdoor->pBModels[i].pFaces[j].pVertexIDs[0]].z;
+            else
+              v19 = ((unsigned __int64)(pOutdoor->pBModels[i].pFaces[j].zCalc1 * (signed __int64)Party_X) >> 16)
+                  + ((unsigned __int64)(pOutdoor->pBModels[i].pFaces[j].zCalc2 * (signed __int64)Party_Y) >> 16)
+                  + HIWORD(pOutdoor->pBModels[i].pFaces[j].zCalc3);
+            v20 = v39++;
+            ceiling_height_level[v20] = v19;
+            dword_720ED0[v20] = i;
+            dword_720E80[v20] = j;
+          }
+        }
+      }
+    }
+  }
+  if ( !v39 )
+  {
+    pFaceID = 0;
+    return ceiling_height_level[0];
+  }
+  v22 = 0;
+  for ( v38 = 0; v38 < v39; ++v38 )
+  {
+    if ( ceiling_height_level[v38] == ceiling_height_level[0] )
+      v22 = v38;
+    else if ( ceiling_height_level[v38] < ceiling_height_level[0] && ceiling_height_level[0] > Party_ZHeight + 15 )
+      v22 = v38;
+    else if ( ceiling_height_level[v38] > ceiling_height_level[0] && ceiling_height_level[v38] <= Party_ZHeight + 15 )
+      v22 = v38;
+  }
+  if ( v22 )
+  {
+    *(int *)pFaceID = dword_720E80[v22] | (dword_720ED0[v22] << 6);
+    return ceiling_height_level[v22];//если есть преграда
+  }
+  pFaceID = 0;
+  return ceiling_height_level[v22];// нет никакой преграды
+}
\ No newline at end of file