diff Render.cpp @ 2464:104fdbea0386

cleaning project part 2
author zipi
date Sun, 17 Aug 2014 17:49:34 +0100
parents 0f17a30149ec
children b054ea5daf45
line wrap: on
line diff
--- a/Render.cpp	Sun Aug 17 15:13:18 2014 +0100
+++ b/Render.cpp	Sun Aug 17 17:49:34 2014 +0100
@@ -3,7 +3,8 @@
 #include <crtdbg.h>
 
 #define _CRT_SECURE_NO_WARNINGS
-#include "mm7_unsorted_subs.h"
+#include "VectorTypes.h"
+
 #include "ZlibWrapper.h"
 #include "ErrorHandling.h"
 
@@ -38,6 +39,8 @@
 #include "Level/Decoration.h"
 #include "Vis.h"
 #include "Registry.h"
+#include "Weather.h"
+
 
 //#pragma comment(lib, "lib\\legacy_dx\\lib\\ddraw.lib")
 //#pragma comment(lib, "lib\\legacy_dx\\lib\\dxguid.lib")
@@ -9524,3 +9527,2079 @@
 		+ (__PAIR__(v10, (unsigned __int16)a4 >> 2) & 0x1C00));
 }
 
+//----- (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;
+
+//----- (0043F55F) --------------------------------------------------------
+int __fastcall _43F55F_get_billboard_light_level(RenderBillboard *a1, int uBaseLightLevel)
+{
+	signed int v3; // ecx@2
+
+	if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
+		v3 = pIndoor->pSectors[a1->uIndoorSectorID].uMinAmbientLightLevel;
+	else
+	{
+		if (uBaseLightLevel == -1)
+			v3 = a1->dimming_level;
+		else
+			v3 = uBaseLightLevel;
+	}
+	return _43F5C8_get_point_light_level_with_respect_to_lights(v3, a1->uIndoorSectorID, a1->world_x, a1->world_y, a1->world_z);
+}
+
+//----- (0043F5C8) --------------------------------------------------------
+int __fastcall _43F5C8_get_point_light_level_with_respect_to_lights(unsigned int uBaseLightLevel, int uSectorID, float x, float y, float z)
+{
+	//  int v5; // esi@1
+	signed int v6; // edi@1
+	int v8; // eax@6
+	int v9; // ebx@6
+	unsigned int v10; // ecx@6
+	unsigned int v11; // edx@9
+	unsigned int v12; // edx@11
+	signed int v13; // ecx@12
+	BLVLightMM7 *v16; // esi@20
+	int v17; // ebx@21
+	//  int v18; // eax@24
+	//  int v19; // ebx@24
+	//  unsigned int v20; // ecx@24
+	//  int v21; // edx@25
+	//  unsigned int v22; // edx@27
+	//  unsigned int v23; // edx@29
+	signed int v24; // ecx@30
+	int v26; // ebx@35
+	//  int v27; // eax@38
+	//  int v28; // ebx@38
+	//  unsigned int v29; // ecx@38
+	//  int v30; // edx@39
+	//  unsigned int v31; // edx@41
+	//  unsigned int v32; // edx@43
+	//signed int v33; // ecx@44
+	int v37; // [sp+Ch] [bp-18h]@37
+	//  int v38; // [sp+10h] [bp-14h]@5
+	int v39; // [sp+10h] [bp-14h]@23
+	int v40; // [sp+10h] [bp-14h]@36
+	int v42; // [sp+14h] [bp-10h]@22
+	unsigned int v43; // [sp+18h] [bp-Ch]@12
+	unsigned int v44; // [sp+18h] [bp-Ch]@30
+	unsigned int v45; // [sp+18h] [bp-Ch]@44
+
+	v6 = uBaseLightLevel;
+	for (uint i = 0; i < pMobileLightsStack->uNumLightsActive; ++i)
+	{
+		MobileLight* p = &pMobileLightsStack->pLights[i];
+
+		float distX = abs(p->vPosition.x - x);
+		if (distX <= p->uRadius)
+		{
+			float distY = abs(p->vPosition.y - y);
+			if (distY <= p->uRadius)
+			{
+				float distZ = abs(p->vPosition.z - z);
+				if (distZ <= p->uRadius)
+				{
+					v8 = distX;
+					v9 = distY;
+					v10 = distZ;
+					if (distX < distY)
+					{
+						v8 = distY;
+						v9 = distX;
+					}
+					if (v8 < distZ)
+					{
+						v11 = v8;
+						v8 = distZ;
+						v10 = v11;
+					}
+					if (v9 < (signed int)v10)
+					{
+						v12 = v10;
+						v10 = v9;
+						v9 = v12;
+					}
+					v43 = ((unsigned int)(11 * v9) / 32) + (v10 / 4) + v8;
+					v13 = p->uRadius;
+					if ((signed int)v43 < v13)
+						v6 += ((unsigned __int64)(30i64 * (signed int)(v43 << 16) / v13) >> 16) - 30;
+				}
+			}
+		}
+	}
+
+	if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
+	{
+		BLVSector* pSector = &pIndoor->pSectors[uSectorID];
+
+		for (uint i = 0; i < pSector->uNumLights; ++i)
+		{
+			v16 = pIndoor->pLights + pSector->pLights[i];
+			if (~v16->uAtributes & 8)
+			{
+				v17 = abs(v16->vPosition.x - x);
+				if (v17 <= v16->uRadius)
+				{
+					v42 = abs(v16->vPosition.y - y);
+					if (v42 <= v16->uRadius)
+					{
+						v39 = abs(v16->vPosition.z - z);
+						if (v39 <= v16->uRadius)
+						{
+							v44 = int_get_vector_length(v17, v42, v39);
+							v24 = v16->uRadius;
+							if ((signed int)v44 < v24)
+								v6 += ((unsigned __int64)(30i64 * (signed int)(v44 << 16) / v24) >> 16) - 30;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	for (uint i = 0; i < pStationaryLightsStack->uNumLightsActive; ++i)
+	{
+		//StationaryLight* p = &pStationaryLightsStack->pLights[i];
+		v26 = abs(pStationaryLightsStack->pLights[i].vPosition.x - x);
+		if (v26 <= pStationaryLightsStack->pLights[i].uRadius)
+		{
+			v40 = abs(pStationaryLightsStack->pLights[i].vPosition.y - y);
+			if (v40 <= pStationaryLightsStack->pLights[i].uRadius)
+			{
+				v37 = abs(pStationaryLightsStack->pLights[i].vPosition.z - z);
+				if (v37 <= pStationaryLightsStack->pLights[i].uRadius)
+				{
+					v45 = int_get_vector_length(v26, v40, v37);
+					//v33 = pStationaryLightsStack->pLights[i].uRadius;
+					if ((signed int)v45 < pStationaryLightsStack->pLights[i].uRadius)
+						v6 += ((unsigned __int64)(30i64 * (signed int)(v45 << 16) / pStationaryLightsStack->pLights[i].uRadius) >> 16) - 30;
+				}
+			}
+		}
+	}
+
+	if (v6 <= 31)
+	{
+		if (v6 < 0)
+			v6 = 0;
+	}
+	else
+		v6 = 31;
+	return v6;
+}
+
+//----- (0049D700) --------------------------------------------------------
+unsigned int __fastcall GetMaxMipLevels(unsigned int uDim)
+{
+	int v2; // ecx@1
+	unsigned int v3; // eax@1
+
+	v2 = 0;
+	v3 = uDim - 1;
+	while (v3 & 1)
+	{
+		v3 >>= 1;
+		++v2;
+	}
+	return v3 == 0 ? v2 : 0;
+}
+
+//----- (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
+	//int v10; // ecx@15
+	int pFloor; // eax@16
+	int v15; // eax@24
+	int v16; // edx@25
+	int v17; // eax@29
+	unsigned int v18; // eax@33
+	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 v32; // [sp+2Ch] [bp-2Ch]@15
+	int pSectorsArray[10]; // [sp+30h] [bp-28h]@1
+
+	pSector = &pIndoor->pSectors[stru_721530.uSectorID];
+	i = 1;
+	a10 = b1;
+	pSectorsArray[0] = stru_721530.uSectorID;
+	for (v2 = 0; 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;
+	for (v29 = 0; v29 < i; v29++)
+	{
+		pSector = &pIndoor->pSectors[pSectorsArray[v29]];
+		v32 = pSector->uNumFloors + pSector->uNumWalls + pSector->uNumCeilings;
+		for (v26 = 0; v26 < v32; v26++)
+		{
+			pFloor = pSector->pFloors[v26];
+			pFace = &pIndoor->pFaces[pSector->pFloors[v26]];
+			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)
+			{
+				v15 = (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;
+				if (v15 > 0)
+				{
+					v16 = (pFace->pFacePlane_old.dist + stru_721530.normal2.x * pFace->pFacePlane_old.vNormal.x
+						+ stru_721530.normal2.y * pFace->pFacePlane_old.vNormal.y
+						+ stru_721530.normal2.z * pFace->pFacePlane_old.vNormal.z) >> 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)
+					|| (v21 = (pFace->pFacePlane_old.dist + stru_721530.position.x * pFace->pFacePlane_old.vNormal.x
+					+ stru_721530.position.y * pFace->pFacePlane_old.vNormal.y
+					+ stru_721530.position.z * pFace->pFacePlane_old.vNormal.z) >> 16, v21 <= 0)
+					|| (v22 = (pFace->pFacePlane_old.dist + stru_721530.field_4C * pFace->pFacePlane_old.vNormal.x
+					+ stru_721530.field_50 * pFace->pFacePlane_old.vNormal.y
+					+ stru_721530.field_54 * pFace->pFacePlane_old.vNormal.z) >> 16, v21 > stru_721530.prolly_normal_d)
+					&& v22 > stru_721530.prolly_normal_d || v22 > v21)
+					continue;
+				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;
+					}
+				}
+			}
+		}
+		result = v29 + 1;
+	}
+	return result;
+}
+// 46E44E: using guessed type int var_28[10];
+
+//----- (0046E889) --------------------------------------------------------
+int __fastcall _46E889_collide_against_bmodels(unsigned int ecx0)
+{
+	int result; // eax@1
+	//int v3; // ebx@9
+	int v8; // eax@19
+	int v9; // ecx@20
+	int v10; // eax@24
+	unsigned int v14; // eax@28
+	int v15; // eax@30
+	int v16; // ecx@31
+	unsigned int v17; // eax@36
+	int v21; // eax@42
+	unsigned int v22; // eax@43
+	//int a11; // [sp+70h] [bp-18h]@1
+	//int a10; // [sp+80h] [bp-8h]@1
+	int a2; // [sp+84h] [bp-4h]@23
+
+	//a11 = ecx0;
+
+	BLVFace face; // [sp+Ch] [bp-7Ch]@1
+
+	result = 0;
+	for (uint i = 0; i < (signed int)pOutdoor->uNumBModels; ++i)
+	{
+		if (stru_721530.sMaxX <= pOutdoor->pBModels[i].sMaxX && stru_721530.sMinX >= pOutdoor->pBModels[i].sMinX
+			&& stru_721530.sMaxY <= pOutdoor->pBModels[i].sMaxY && stru_721530.sMinY >= pOutdoor->pBModels[i].sMinY
+			&& stru_721530.sMaxZ <= pOutdoor->pBModels[i].sMaxZ && stru_721530.sMinZ >= pOutdoor->pBModels[i].sMinZ)
+		{
+			for (uint j = 0; j < pOutdoor->pBModels[i].uNumFaces; ++j)
+			{
+				if (stru_721530.sMaxX <= pOutdoor->pBModels[i].pFaces[j].pBoundingBox.x2 && stru_721530.sMinX >= pOutdoor->pBModels[i].pFaces[j].pBoundingBox.x1
+					&& stru_721530.sMaxY <= pOutdoor->pBModels[i].pFaces[j].pBoundingBox.y2 && stru_721530.sMinY >= pOutdoor->pBModels[i].pFaces[j].pBoundingBox.y1
+					&& stru_721530.sMaxZ <= pOutdoor->pBModels[i].pFaces[j].pBoundingBox.z2 && stru_721530.sMinZ >= pOutdoor->pBModels[i].pFaces[j].pBoundingBox.z1)
+				{
+					face.pFacePlane_old.vNormal.x = pOutdoor->pBModels[i].pFaces[j].pFacePlane.vNormal.x;
+					face.pFacePlane_old.vNormal.y = pOutdoor->pBModels[i].pFaces[j].pFacePlane.vNormal.y;
+					face.pFacePlane_old.vNormal.z = pOutdoor->pBModels[i].pFaces[j].pFacePlane.vNormal.z;
+
+					face.pFacePlane_old.dist = pOutdoor->pBModels[i].pFaces[j].pFacePlane.dist; //incorrect
+
+					face.uAttributes = pOutdoor->pBModels[i].pFaces[j].uAttributes;
+
+					face.pBounding.x1 = pOutdoor->pBModels[i].pFaces[j].pBoundingBox.x1;
+					face.pBounding.y1 = pOutdoor->pBModels[i].pFaces[j].pBoundingBox.y1;
+					face.pBounding.z1 = pOutdoor->pBModels[i].pFaces[j].pBoundingBox.z1;
+
+					face.pBounding.x2 = pOutdoor->pBModels[i].pFaces[j].pBoundingBox.x2;
+					face.pBounding.y2 = pOutdoor->pBModels[i].pFaces[j].pBoundingBox.y2;
+					face.pBounding.z2 = pOutdoor->pBModels[i].pFaces[j].pBoundingBox.z2;
+
+					face.zCalc1 = pOutdoor->pBModels[i].pFaces[j].zCalc1;
+					face.zCalc2 = pOutdoor->pBModels[i].pFaces[j].zCalc2;
+					face.zCalc3 = pOutdoor->pBModels[i].pFaces[j].zCalc3;
+
+					face.pXInterceptDisplacements = pOutdoor->pBModels[i].pFaces[j].pXInterceptDisplacements;
+					face.pYInterceptDisplacements = pOutdoor->pBModels[i].pFaces[j].pYInterceptDisplacements;
+					face.pZInterceptDisplacements = pOutdoor->pBModels[i].pFaces[j].pZInterceptDisplacements;
+
+					face.uPolygonType = (PolygonType)pOutdoor->pBModels[i].pFaces[j].uPolygonType;
+
+					face.uNumVertices = pOutdoor->pBModels[i].pFaces[j].uNumVertices;
+
+					face.uBitmapID = pOutdoor->pBModels[i].pFaces[j].uTextureID;
+
+					face.pVertexIDs = pOutdoor->pBModels[i].pFaces[j].pVertexIDs;
+
+					if (!face.Ethereal() && !face.Portal())
+					{
+						v8 = (face.pFacePlane_old.dist + face.pFacePlane_old.vNormal.x * stru_721530.normal.x
+							+ face.pFacePlane_old.vNormal.y * stru_721530.normal.y
+							+ face.pFacePlane_old.vNormal.z * stru_721530.normal.z) >> 16;
+						if (v8 > 0)
+						{
+							v9 = (face.pFacePlane_old.dist + face.pFacePlane_old.vNormal.x * stru_721530.normal2.x
+								+ face.pFacePlane_old.vNormal.y * stru_721530.normal2.y
+								+ face.pFacePlane_old.vNormal.z * stru_721530.normal2.z) >> 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, &face, i, ecx0))
+									{
+										v10 = a2;
+									}
+									else
+									{
+										a2 = stru_721530.prolly_normal_d + stru_721530.field_6C;
+										if (!sub_475F30(&a2, &face, stru_721530.normal.x, stru_721530.normal.y, stru_721530.normal.z,
+											stru_721530.direction.x, stru_721530.direction.y, stru_721530.direction.z, i))
+											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 * (j | (i << 6));
+										LOBYTE(v14) = v14 | 6;
+										stru_721530.uFaceID = v14;
+									}
+								}
+							}
+						}
+					LABEL_29:
+						if (stru_721530.field_0 & 1)
+						{
+							v15 = (face.pFacePlane_old.dist + face.pFacePlane_old.vNormal.x * stru_721530.position.x
+								+ face.pFacePlane_old.vNormal.y * stru_721530.position.y
+								+ face.pFacePlane_old.vNormal.z * stru_721530.position.z) >> 16;
+							if (v15 > 0)
+							{
+								v16 = (face.pFacePlane_old.dist + face.pFacePlane_old.vNormal.x * stru_721530.field_4C
+									+ face.pFacePlane_old.vNormal.y * stru_721530.field_50
+									+ face.pFacePlane_old.vNormal.z * stru_721530.field_54) >> 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, &face, i, ecx0))
+										{
+											if (a2 < stru_721530.field_7C)
+											{
+												stru_721530.field_7C = a2;
+												v17 = 8 * (j | (i << 6));
+												LOBYTE(v17) = v17 | 6;
+												stru_721530.uFaceID = v17;
+											}
+										}
+										else
+										{
+											a2 = stru_721530.field_6C + stru_721530.field_8_radius;
+											if (sub_475F30(&a2, &face, stru_721530.position.x, stru_721530.position.y, stru_721530.position.z,
+												stru_721530.direction.x, stru_721530.direction.y, stru_721530.direction.z, i))
+											{
+												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 * (j | (i << 6));
+													LOBYTE(v22) = v22 | 6;
+													stru_721530.uFaceID = v22;
+												}
+											}
+										}
+									}
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+		result = i;
+	}
+	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)
+{
+	ObjectDesc *object; // edx@4
+	int v10; // ecx@12
+	int v11; // esi@13
+
+	for (uint i = 0; i < uNumSpriteObjects; ++i)
+	{
+		if (pSpriteObjects[i].uObjectDescID)
+		{
+			object = &pObjectList->pObjects[pSpriteObjects[i].uObjectDescID];
+			if (!(object->uFlags & OBJECT_DESC_NO_COLLISION))
+			{
+				if (stru_721530.sMaxX <= pSpriteObjects[i].vPosition.x + object->uRadius && stru_721530.sMinX >= pSpriteObjects[i].vPosition.x - object->uRadius
+					&& stru_721530.sMaxY <= pSpriteObjects[i].vPosition.y + object->uRadius && stru_721530.sMinY >= pSpriteObjects[i].vPosition.y - object->uRadius
+					&& stru_721530.sMaxZ <= pSpriteObjects[i].vPosition.z + object->uHeight && stru_721530.sMinZ >= pSpriteObjects[i].vPosition.z)
+				{
+					if (abs(((pSpriteObjects[i].vPosition.x - stru_721530.normal.x) * stru_721530.direction.y
+						- (pSpriteObjects[i].vPosition.y - stru_721530.normal.y) * stru_721530.direction.x) >> 16)
+						<= object->uHeight + stru_721530.prolly_normal_d)
+					{
+						v10 = ((pSpriteObjects[i].vPosition.x - stru_721530.normal.x) * stru_721530.direction.x
+							+ (pSpriteObjects[i].vPosition.y - stru_721530.normal.y) * 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 >= pSpriteObjects[i].vPosition.z - stru_721530.prolly_normal_d)
+							{
+								if (v11 <= object->uHeight + stru_721530.prolly_normal_d + pSpriteObjects[i].vPosition.z)
+								{
+									if (v10 < stru_721530.field_7C)
+										sub_46DEF2(_this, i);
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+//----- (0046EF01) --------------------------------------------------------
+int _46EF01_collision_chech_player(int a1)
+{
+	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 v10; // [sp+14h] [bp-8h]@7
+	int v11; // [sp+18h] [bp-4h]@7
+
+	result = pParty->vPosition.x;
+	//v9 = pParty->uPartyHeight;
+	if (stru_721530.sMaxX <= pParty->vPosition.x + (2 * pParty->field_14_radius) && stru_721530.sMinX >= pParty->vPosition.x - (2 * pParty->field_14_radius)
+		&& stru_721530.sMaxY <= pParty->vPosition.y + (2 * pParty->field_14_radius) && stru_721530.sMinY >= pParty->vPosition.y - (2 * pParty->field_14_radius)
+		&& stru_721530.sMaxZ <= pParty->vPosition.z + pParty->uPartyHeight && stru_721530.sMinZ >= pParty->vPosition.z)
+	{
+		v3 = stru_721530.prolly_normal_d + (2 * pParty->field_14_radius);
+		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 <= stru_721530.prolly_normal_d + (2 * pParty->field_14_radius))
+		{
+			result = v10 * stru_721530.direction.y;
+			v5 = (v10 * stru_721530.direction.y + v11 * stru_721530.direction.x) >> 16;
+			if (v5 > 0)
+			{
+				v6 = fixpoint_mul(stru_721530.direction.z, v5) + stru_721530.normal.z;
+				result = pParty->vPosition.z;
+				if (v6 >= pParty->vPosition.z)
+				{
+					result = pParty->uPartyHeight + pParty->vPosition.z;
+					if (v6 <= (signed int)(pParty->uPartyHeight + pParty->vPosition.z) || a1)
+					{
+						result = integer_sqrt(v3 * v3 - v4 * v4);
+						v7 = v5 - integer_sqrt(v3 * v3 - v4 * v4);
+						if (v7 < 0)
+							v7 = 0;
+						if (v7 < stru_721530.field_7C)
+						{
+							stru_721530.field_7C = v7;
+							stru_721530.uFaceID = 4;
+						}
+					}
+				}
+			}
+		}
+	}
+	return result;
+}
+
+//----- (0046E0B2) --------------------------------------------------------
+void  _46E0B2_collide_against_decorations()
+{
+	BLVSector *sector; // ebp@1
+	LevelDecoration *decor; // edi@2
+	DecorationDesc *decor_desc; // esi@3
+	int v8; // ebx@10
+	int v9; // esi@11
+	int v11; // eax@12
+	int v12; // esi@14
+	unsigned int v13; // eax@17
+	signed int i; // [sp+4h] [bp-14h]@1
+	int v15; // [sp+8h] [bp-10h]@10
+	int v16; // [sp+Ch] [bp-Ch]@10
+	int v17; // [sp+10h] [bp-8h]@10
+
+	sector = &pIndoor->pSectors[stru_721530.uSectorID];
+	for (i = 0; i < sector->uNumDecorations; ++i)
+	{
+		decor = &pLevelDecorations[sector->pDecorationIDs[i]];
+		if (!(decor->uFlags & LEVEL_DECORATION_INVISIBLE))
+		{
+			decor_desc = &pDecorationList->pDecorations[decor->uDecorationDescID];
+			if (!decor_desc->CanMoveThrough())
+			{
+				if (stru_721530.sMaxX <= decor->vPosition.x + decor_desc->uRadius && stru_721530.sMinX >= decor->vPosition.x - decor_desc->uRadius
+					&& stru_721530.sMaxY <= decor->vPosition.y + decor_desc->uRadius && stru_721530.sMinY >= decor->vPosition.y - decor_desc->uRadius
+					&& stru_721530.sMaxZ <= decor->vPosition.z + decor_desc->uDecorationHeight && stru_721530.sMinZ >= decor->vPosition.z)
+				{
+					v16 = decor->vPosition.x - stru_721530.normal.x;
+					v15 = decor->vPosition.y - stru_721530.normal.y;
+					v8 = stru_721530.prolly_normal_d + decor_desc->uRadius;
+					v17 = ((decor->vPosition.x - stru_721530.normal.x) * stru_721530.direction.y
+						- (decor->vPosition.y - stru_721530.normal.y) * stru_721530.direction.x) >> 16;
+					if (abs(v17) <= stru_721530.prolly_normal_d + decor_desc->uRadius)
+					{
+						v9 = (v16 * stru_721530.direction.x + v15 * stru_721530.direction.y) >> 16;
+						if (v9 > 0)
+						{
+							v11 = stru_721530.normal.z + fixpoint_mul(stru_721530.direction.z, v9);
+							if (v11 >= decor->vPosition.z)
+							{
+								if (v11 <= decor_desc->uDecorationHeight + decor->vPosition.z)
+								{
+									v12 = v9 - integer_sqrt(v8 * v8 - v17 * v17);
+									if (v12 < 0)
+										v12 = 0;
+									if (v12 < stru_721530.field_7C)
+									{
+										stru_721530.field_7C = v12;
+										v13 = 8 * sector->pDecorationIDs[i];
+										LOBYTE(v13) = v13 | 5;
+										stru_721530.uFaceID = v13;
+									}
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+//----- (0046F04E) --------------------------------------------------------
+int _46F04E_collide_against_portals()
+{
+	unsigned int v1; // eax@1
+	BLVFace *face; // eax@3
+	int v4; // ecx@9
+	int v5; // edx@9
+	signed int result; // eax@21
+	unsigned int v10; // [sp+8h] [bp-Ch]@1
+	int a3; // [sp+Ch] [bp-8h]@13
+	int v12; // [sp+10h] [bp-4h]@15
+
+	v1 = 0xFFFFFFu;
+	v10 = 0xFFFFFFu;
+	for (uint i = 0; i < pIndoor->pSectors[stru_721530.uSectorID].uNumPortals; ++i)
+	{
+		if (pIndoor->pSectors[stru_721530.uSectorID].pPortals[i] != stru_721530.field_80)
+		{
+			face = &pIndoor->pFaces[pIndoor->pSectors[stru_721530.uSectorID].pPortals[i]];
+			if (stru_721530.sMaxX <= face->pBounding.x2 && stru_721530.sMinX >= face->pBounding.x1
+				&& stru_721530.sMaxY <= face->pBounding.y2 && stru_721530.sMinY >= face->pBounding.y1
+				&& stru_721530.sMaxZ <= face->pBounding.z2 && stru_721530.sMinZ >= face->pBounding.z1)
+			{
+				v4 = (stru_721530.normal.x * face->pFacePlane_old.vNormal.x + face->pFacePlane_old.dist
+					+ stru_721530.normal.y * face->pFacePlane_old.vNormal.y
+					+ stru_721530.normal.z * face->pFacePlane_old.vNormal.z) >> 16;
+				v5 = (stru_721530.normal2.z * face->pFacePlane_old.vNormal.z + face->pFacePlane_old.dist
+					+ stru_721530.normal2.x * face->pFacePlane_old.vNormal.x
+					+ stru_721530.normal2.y * face->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, face))
+					&& a3 < (signed int)v10)
+				{
+					v10 = a3;
+					v12 = pIndoor->pSectors[stru_721530.uSectorID].pPortals[i];
+				}
+			}
+		}
+	}
+	v1 = v10;
+	if (stru_721530.field_7C >= (signed int)v1 && (signed int)v1 <= stru_721530.field_6C)
+	{
+		stru_721530.field_80 = v12;
+		if (pIndoor->pFaces[v12].uSectorID == stru_721530.uSectorID)
+			stru_721530.uSectorID = pIndoor->pFaces[v12].uBackSectorID;
+		else
+			stru_721530.uSectorID = pIndoor->pFaces[v12].uSectorID;
+		stru_721530.field_7C = 268435455;
+		result = 0;
+	}
+	else
+		result = 1;
+	return result;
+}
+
+//----- (0046DEF2) --------------------------------------------------------
+unsigned int __fastcall sub_46DEF2(signed int a2, unsigned int uLayingItemID)
+{
+	unsigned int result; // eax@1
+
+	result = uLayingItemID;
+	if (pObjectList->pObjects[pSpriteObjects[uLayingItemID].uObjectDescID].uFlags & 0x10)
+		result = _46BFFA_check_object_intercept(uLayingItemID, a2);
+	return result;
+}
+
+//----- (0047253E) --------------------------------------------------------
+void UpdateObjects()
+{
+	ObjectDesc *object; // eax@5
+	int v5; // ecx@6
+	signed int v7; // eax@9
+	signed int v11; // eax@17
+	int v12; // edi@27
+	int v18; // [sp+4h] [bp-10h]@27
+	int v19; // [sp+8h] [bp-Ch]@27
+
+	for (uint i = 0; i < uNumSpriteObjects; ++i)
+	{
+		if (pSpriteObjects[i].uAttributes & OBJECT_40)
+			pSpriteObjects[i].uAttributes &= ~OBJECT_40;
+		else
+		{
+			object = &pObjectList->pObjects[pSpriteObjects[i].uObjectDescID];
+			if (pSpriteObjects[i].AttachedToActor())
+			{
+				v5 = PID_ID(pSpriteObjects[i].spell_target_pid);
+				pSpriteObjects[i].vPosition.x = pActors[v5].vPosition.x;
+				pSpriteObjects[i].vPosition.y = pActors[v5].vPosition.y;
+				pSpriteObjects[i].vPosition.z = pActors[v5].vPosition.z + pActors[v5].uActorHeight;
+				if (!pSpriteObjects[i].uObjectDescID)
+					continue;
+				pSpriteObjects[i].uSpriteFrameID += pEventTimer->uTimeElapsed;
+				if (!(object->uFlags & OBJECT_DESC_TEMPORARY))
+					continue;
+				if (pSpriteObjects[i].uSpriteFrameID >= 0)
+				{
+					v7 = object->uLifetime;
+					if (pSpriteObjects[i].uAttributes & ITEM_BROKEN)
+						v7 = pSpriteObjects[i].field_20;
+					if (pSpriteObjects[i].uSpriteFrameID < v7)
+						continue;
+				}
+				SpriteObject::OnInteraction(i);
+				continue;
+			}
+			if (pSpriteObjects[i].uObjectDescID)
+			{
+				pSpriteObjects[i].uSpriteFrameID += pEventTimer->uTimeElapsed;
+				if (object->uFlags & OBJECT_DESC_TEMPORARY)
+				{
+					if (pSpriteObjects[i].uSpriteFrameID < 0)
+					{
+						SpriteObject::OnInteraction(i);
+						continue;
+					}
+					v11 = object->uLifetime;
+					if (pSpriteObjects[i].uAttributes & ITEM_BROKEN)
+						v11 = pSpriteObjects[i].field_20;
+				}
+				if (!(object->uFlags & OBJECT_DESC_TEMPORARY) || pSpriteObjects[i].uSpriteFrameID < v11)
+				{
+					if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
+						SpriteObject::UpdateObject_fn0_BLV(i);
+					else
+						SpriteObject::UpdateObject_fn0_ODM(i);
+					if (pParty->bTurnBasedModeOn != 1 || !(pSpriteObjects[i].uSectorID & 4))
+						continue;
+					v12 = abs(pParty->vPosition.x - pSpriteObjects[i].vPosition.x);
+					v18 = abs(pParty->vPosition.y - pSpriteObjects[i].vPosition.y);
+					v19 = abs(pParty->vPosition.z - pSpriteObjects[i].vPosition.z);
+					if (int_get_vector_length(v12, v18, v19) <= 5120)
+						continue;
+					SpriteObject::OnInteraction(i);
+					continue;
+				}
+				if (!(object->uFlags & OBJECT_DESC_INTERACTABLE))
+				{
+					SpriteObject::OnInteraction(i);
+					continue;
+				}
+				_46BFFA_check_object_intercept(i, PID(OBJECT_Item, i));
+			}
+		}
+	}
+}
+
+//----- (0047531C) --------------------------------------------------------
+bool sub_47531C(int a1, int *a2, int pos_x, int pos_y, int pos_z, int dir_x, int dir_y, int dir_z, BLVFace *face, int a10)
+{
+	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 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
+
+	if (a10 && face->Ethereal())
+		return 0;
+	v11 = fixpoint_mul(dir_x, face->pFacePlane_old.vNormal.x);
+	a10b = fixpoint_mul(dir_y, face->pFacePlane_old.vNormal.y);
+	a9b = fixpoint_mul(dir_z, face->pFacePlane_old.vNormal.z);
+	v12 = v11 + a9b + a10b;
+	a9a = v11 + a9b + a10b;
+	v13 = (a1 << 16)
+		- pos_x * face->pFacePlane_old.vNormal.x
+		- pos_y * face->pFacePlane_old.vNormal.y
+		- pos_z * face->pFacePlane_old.vNormal.z
+		- face->pFacePlane_old.dist;
+	if (abs((a1 << 16)
+		- pos_x * face->pFacePlane_old.vNormal.x
+		- pos_y * face->pFacePlane_old.vNormal.y
+		- pos_z * face->pFacePlane_old.vNormal.z - face->pFacePlane_old.dist) >= a1 << 16)
+	{
+		a10c = abs(v13) >> 14;
+		if (a10c > abs(v12))
+			return 0;
+		LODWORD(v15) = v13 << 16;
+		HIDWORD(v15) = v13 >> 16;
+		v14 = a1;
+		a10a = v15 / a9a;
+	}
+	else
+	{
+		a10a = 0;
+		v14 = abs(v13) >> 16;
+	}
+	//v16 = pos_y + ((unsigned int)fixpoint_mul(a10a, dir_y) >> 16);
+	LOWORD(a7a) = (short)pos_x + ((unsigned int)fixpoint_mul(a10a, dir_x) >> 16) - fixpoint_mul(v14, face->pFacePlane_old.vNormal.x);
+	HIWORD(a7a) = pos_y + ((unsigned int)fixpoint_mul(a10a, dir_y) >> 16) - fixpoint_mul(v14, face->pFacePlane_old.vNormal.y);
+	if (!sub_475665(face, a7a, (short)pos_z + ((unsigned int)fixpoint_mul(a10a, dir_z) >> 16) - fixpoint_mul(v14, face->pFacePlane_old.vNormal.z)))
+		return 0;
+	*a2 = a10a >> 16;
+	if (a10a >> 16 < 0)
+		*a2 = 0;
+	return 1;
+}
+
+
+//----- (004754BF) --------------------------------------------------------
+bool sub_4754BF(int a1, int *a2, int X, int Y, int Z, int dir_x, int dir_y, int dir_z, BLVFace *face, int a10, int a11)
+{
+	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 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
+
+	if (a11 && face->Ethereal())
+		return false;
+	v12 = fixpoint_mul(dir_x, face->pFacePlane_old.vNormal.x);
+	a11b = fixpoint_mul(dir_y, face->pFacePlane_old.vNormal.y);
+	a1b = fixpoint_mul(dir_z, face->pFacePlane_old.vNormal.z);
+	v13 = v12 + a1b + a11b;
+	a1a = v12 + a1b + a11b;
+	v14 = (a1 << 16)
+		- X * face->pFacePlane_old.vNormal.x
+		- Y * face->pFacePlane_old.vNormal.y
+		- Z * face->pFacePlane_old.vNormal.z
+		- face->pFacePlane_old.dist;
+	if (abs((a1 << 16)
+		- X * face->pFacePlane_old.vNormal.x
+		- Y * face->pFacePlane_old.vNormal.y
+		- Z * face->pFacePlane_old.vNormal.z - face->pFacePlane_old.dist) >= a1 << 16)
+	{
+		a11c = abs(v14) >> 14;
+		if (a11c > abs(v13))
+			return false;
+		LODWORD(v16) = v14 << 16;
+		HIDWORD(v16) = v14 >> 16;
+		v15 = a1;
+		a11a = v16 / a1a;
+	}
+	else
+	{
+		a11a = 0;
+		v15 = abs(v14) >> 16;
+	}
+	//v17 = Y + ((unsigned int)fixpoint_mul(a11a, dir_y) >> 16);
+	LOWORD(a7a) = (short)X + ((unsigned int)fixpoint_mul(a11a, dir_x) >> 16) - fixpoint_mul(v15, face->pFacePlane_old.vNormal.x);
+	HIWORD(a7a) = Y + ((unsigned int)fixpoint_mul(a11a, dir_y) >> 16) - fixpoint_mul(v15, face->pFacePlane_old.vNormal.y);
+	if (!sub_4759C9(face, a10, a7a, (short)Z + ((unsigned int)fixpoint_mul(a11a, dir_z) >> 16) - fixpoint_mul(v15, face->pFacePlane_old.vNormal.z)))
+		return false;
+	*a2 = a11a >> 16;
+	if (a11a >> 16 < 0)
+		*a2 = 0;
+	return true;
+}
+
+//----- (00475665) --------------------------------------------------------
+int sub_475665(BLVFace *face, int a2, __int16 a3)
+{
+	bool v16; // edi@14
+	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
+
+	if (face->uAttributes & FACE_XY_PLANE)
+	{
+		v26 = (signed __int16)a2;
+		v27 = SHIWORD(a2);
+		if (face->uNumVertices)
+		{
+			for (v28 = 0; v28 < face->uNumVertices; v28++)
+			{
+				word_720C10_intercepts_xs[2 * v28] = face->pXInterceptDisplacements[v28] + pIndoor->pVertices[face->pVertexIDs[v28]].x;
+				word_720B40_intercepts_zs[2 * v28] = face->pYInterceptDisplacements[v28] + pIndoor->pVertices[face->pVertexIDs[v28]].y;
+				word_720C10_intercepts_xs[2 * v28 + 1] = face->pXInterceptDisplacements[v28 + 1] + pIndoor->pVertices[face->pVertexIDs[v28 + 1]].x;
+				word_720B40_intercepts_zs[2 * v28 + 1] = face->pYInterceptDisplacements[v28 + 1] + pIndoor->pVertices[face->pVertexIDs[v28 + 1]].y;
+			}
+		}
+	}
+	else
+	{
+		if (face->uAttributes & FACE_XZ_PLANE)
+		{
+			v26 = (signed __int16)a2;
+			v27 = a3;
+			if (face->uNumVertices)
+			{
+				for (v29 = 0; v29 < face->uNumVertices; v29++)
+				{
+					word_720C10_intercepts_xs[2 * v29] = face->pXInterceptDisplacements[v29] + pIndoor->pVertices[face->pVertexIDs[v29]].x;
+					word_720B40_intercepts_zs[2 * v29] = face->pZInterceptDisplacements[v29] + pIndoor->pVertices[face->pVertexIDs[v29]].z;
+					word_720C10_intercepts_xs[2 * v29 + 1] = face->pXInterceptDisplacements[v29 + 1] + pIndoor->pVertices[face->pVertexIDs[v29 + 1]].x;
+					word_720B40_intercepts_zs[2 * v29 + 1] = face->pZInterceptDisplacements[v29 + 1] + pIndoor->pVertices[face->pVertexIDs[v29 + 1]].z;
+				}
+			}
+		}
+		else
+		{
+			v26 = SHIWORD(a2);
+			v27 = a3;
+			if (face->uNumVertices)
+			{
+				for (v30 = 0; v30 < face->uNumVertices; v30++)
+				{
+					word_720C10_intercepts_xs[2 * v30] = face->pYInterceptDisplacements[v30] + pIndoor->pVertices[face->pVertexIDs[v30]].y;
+					word_720B40_intercepts_zs[2 * v30] = face->pZInterceptDisplacements[v30] + pIndoor->pVertices[face->pVertexIDs[v30]].z;
+					word_720C10_intercepts_xs[2 * v30 + 1] = face->pYInterceptDisplacements[v30 + 1] + pIndoor->pVertices[face->pVertexIDs[v30 + 1]].y;
+					word_720B40_intercepts_zs[2 * v30 + 1] = face->pZInterceptDisplacements[v30 + 1] + pIndoor->pVertices[face->pVertexIDs[v30 + 1]].z;
+				}
+			}
+		}
+	}
+	v31 = 0;
+	word_720C10_intercepts_xs[2 * face->uNumVertices] = word_720C10_intercepts_xs[0];
+	word_720B40_intercepts_zs[2 * face->uNumVertices] = word_720B40_intercepts_zs[0];
+	v16 = word_720B40_intercepts_zs[0] >= v27;
+	if (2 * face->uNumVertices <= 0)
+		return 0;
+	for (v25 = 0; v25 < 2 * face->uNumVertices; ++v25)
+	{
+		if (v31 >= 2)
+			break;
+		if (v16 ^ (word_720B40_intercepts_zs[v25 + 1] >= v27))
+		{
+			if (word_720C10_intercepts_xs[v25 + 1] >= v26)
+				v20 = 0;
+			else
+				v20 = 2;
+			v21 = v20 | (word_720C10_intercepts_xs[v25] < v26);
+			if (v21 != 3)
+			{
+				v22 = word_720C10_intercepts_xs[v25 + 1] - word_720C10_intercepts_xs[v25];
+				LODWORD(v23) = v22 << 16;
+				HIDWORD(v23) = v22 >> 16;
+				if (!v21
+					|| (word_720C10_intercepts_xs[v25] + ((signed int)(((unsigned __int64)(v23
+					/ (word_720B40_intercepts_zs[v25 + 1] - word_720B40_intercepts_zs[v25])
+					* ((v27 - (signed int)word_720B40_intercepts_zs[v25]) << 16)) >> 16)
+					+ 32768) >> 16) >= v26))
+					++v31;
+			}
+		}
+		v16 = word_720B40_intercepts_zs[v25 + 1] >= v27;
+	}
+	result = 1;
+	if (v31 != 1)
+		result = 0;
+	return result;
+}
+
+//----- (004759C9) --------------------------------------------------------
+bool __fastcall sub_4759C9(BLVFace *face, int a2, int a3, __int16 a4)
+{
+	bool v12; // edi@14
+	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
+	signed int a4d; // [sp+30h] [bp+Ch]@14
+
+	if (face->uAttributes & FACE_XY_PLANE)
+	{
+		v23 = (signed __int16)a3;
+		v24 = SHIWORD(a3);
+		if (face->uNumVertices)
+		{
+			for (v22 = 0; v22 < face->uNumVertices; ++v22)
+			{
+				word_720A70_intercepts_xs_plus_xs[2 * v22] = face->pXInterceptDisplacements[v22] + LOWORD(pOutdoor->pBModels[a2].pVertices.pVertices[face->pVertexIDs[v22]].x);
+				word_7209A0_intercepts_ys_plus_ys[2 * v22] = face->pYInterceptDisplacements[v22] + LOWORD(pOutdoor->pBModels[a2].pVertices.pVertices[face->pVertexIDs[v22]].y);
+				word_720A70_intercepts_xs_plus_xs[2 * v22 + 1] = face->pXInterceptDisplacements[v22 + 1] + LOWORD(pOutdoor->pBModels[a2].pVertices.pVertices[face->pVertexIDs[v22 + 1]].x);
+				word_7209A0_intercepts_ys_plus_ys[2 * v22 + 1] = face->pYInterceptDisplacements[v22 + 1] + LOWORD(pOutdoor->pBModels[a2].pVertices.pVertices[face->pVertexIDs[v22 + 1]].y);
+			}
+		}
+	}
+	else
+	{
+		if (face->uAttributes & FACE_XZ_PLANE)
+		{
+			v23 = (signed __int16)a3;
+			v24 = a4;
+			if (face->uNumVertices)
+			{
+				for (v22 = 0; v22 < face->uNumVertices; ++v22)
+				{
+					word_720A70_intercepts_xs_plus_xs[2 * v22] = face->pXInterceptDisplacements[v22] + LOWORD(pOutdoor->pBModels[a2].pVertices.pVertices[face->pVertexIDs[v22]].x);
+					word_7209A0_intercepts_ys_plus_ys[2 * v22] = face->pZInterceptDisplacements[v22] + LOWORD(pOutdoor->pBModels[a2].pVertices.pVertices[face->pVertexIDs[v22]].z);
+					word_720A70_intercepts_xs_plus_xs[2 * v22 + 1] = face->pXInterceptDisplacements[v22 + 1] + LOWORD(pOutdoor->pBModels[a2].pVertices.pVertices[face->pVertexIDs[v22 + 1]].x);
+					word_7209A0_intercepts_ys_plus_ys[2 * v22 + 1] = face->pZInterceptDisplacements[v22 + 1] + LOWORD(pOutdoor->pBModels[a2].pVertices.pVertices[face->pVertexIDs[v22 + 1]].z);
+				}
+			}
+		}
+		else
+		{
+			v23 = SHIWORD(a3);
+			v24 = a4;
+			if (face->uNumVertices)
+			{
+				for (v22 = 0; v22 < face->uNumVertices; ++v22)
+				{
+					word_720A70_intercepts_xs_plus_xs[2 * v22] = face->pYInterceptDisplacements[v22] + LOWORD(pOutdoor->pBModels[a2].pVertices.pVertices[face->pVertexIDs[v22]].y);
+					word_7209A0_intercepts_ys_plus_ys[2 * v22] = face->pZInterceptDisplacements[v22] + LOWORD(pOutdoor->pBModels[a2].pVertices.pVertices[face->pVertexIDs[v22]].z);
+					word_720A70_intercepts_xs_plus_xs[2 * v22 + 1] = face->pYInterceptDisplacements[v22 + 1] + LOWORD(pOutdoor->pBModels[a2].pVertices.pVertices[face->pVertexIDs[v22 + 1]].y);
+					word_7209A0_intercepts_ys_plus_ys[2 * v22 + 1] = face->pZInterceptDisplacements[v22 + 1] + LOWORD(pOutdoor->pBModels[a2].pVertices.pVertices[face->pVertexIDs[v22 + 1]].z);
+				}
+			}
+		}
+	}
+	a4d = 0;
+	word_720A70_intercepts_xs_plus_xs[2 * face->uNumVertices] = word_720A70_intercepts_xs_plus_xs[0];
+	word_7209A0_intercepts_ys_plus_ys[2 * face->uNumVertices] = word_7209A0_intercepts_ys_plus_ys[0];
+	v12 = word_7209A0_intercepts_ys_plus_ys[0] >= v24;
+	if (2 * face->uNumVertices <= 0)
+		return 0;
+	for (v21 = 0; v21 < 2 * face->uNumVertices; ++v21)
+	{
+		if (a4d >= 2)
+			break;
+		if (v12 ^ (word_7209A0_intercepts_ys_plus_ys[v21 + 1] >= v24))
+		{
+			if (word_720A70_intercepts_xs_plus_xs[v21 + 1] >= v23)
+				v16 = 0;
+			else
+				v16 = 2;
+			v17 = v16 | (word_720A70_intercepts_xs_plus_xs[v21] < v23);
+			if (v17 != 3)
+			{
+				v18 = word_720A70_intercepts_xs_plus_xs[v21 + 1] - word_720A70_intercepts_xs_plus_xs[v21];
+				LODWORD(v19) = v18 << 16;
+				HIDWORD(v19) = v18 >> 16;
+				if (!v17
+					|| (word_720A70_intercepts_xs_plus_xs[v21] + ((signed int)(((unsigned __int64)(v19
+					/ (word_7209A0_intercepts_ys_plus_ys[v21 + 1] - word_7209A0_intercepts_ys_plus_ys[v21])
+					* ((v24 - (signed int)word_7209A0_intercepts_ys_plus_ys[v21]) << 16)) >> 16)
+					+ 0x8000) >> 16) >= v23))
+					++a4d;
+			}
+		}
+		v12 = word_7209A0_intercepts_ys_plus_ys[v21 + 1] >= v24;
+	}
+	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;
+	v5 = fixpoint_mul(a2->x, a4->pFacePlane_old.vNormal.x);
+	a4b = fixpoint_mul(a2->y, a4->pFacePlane_old.vNormal.y);
+	v6 = fixpoint_mul(a2->z, v4->pFacePlane_old.vNormal.z);
+	v7 = v5 + v6 + a4b;
+	//(v16 = v5 + v6 + a4b) == 0;
+	if (a4->uAttributes & 0x20000000 || !v7 || 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;
+	v11 = v14;
+	LODWORD(v10) = v9 << 16;
+	HIDWORD(v10) = v9 >> 16;
+	a4a = v10 / v7;
+	v17 = v10 / v7;
+	LOWORD(v12) = LOWORD(v14->x) + (((unsigned int)fixpoint_mul(v17, v15->x) + 0x8000) >> 16);
+	HIWORD(v12) = LOWORD(v11->y) + (((unsigned int)fixpoint_mul(v17, v15->y) + 0x8000) >> 16);
+	if (a4c > abs(v7) || (v17 > *a3 << 16) || !sub_475665(v4, v12, LOWORD(v11->z) + (((unsigned int)fixpoint_mul(v17, v15->z) + 0x8000) >> 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)
+{
+	int v10; // ST20_4@2
+	int v11; // ST28_4@2
+	int v12; // ST24_4@2
+	int v13; // zf@2
+	int v14; // edi@2
+	signed int v16; // esi@5
+	int v17; // ST20_4@9
+	signed __int64 v18; // qtt@10
+	int v19; // ST14_4@11
+	int v22; // [sp+1Ch] [bp-8h]@2
+	int v23; // [sp+1Ch] [bp-8h]@10
+	signed int v24; // [sp+20h] [bp-4h]@10
+
+	v10 = fixpoint_mul(a6, a2->pFacePlane_old.vNormal.x);
+	v11 = fixpoint_mul(a7, a2->pFacePlane_old.vNormal.y);
+	v12 = fixpoint_mul(a8, a2->pFacePlane_old.vNormal.z);
+	v13 = v10 + v12 + v11;
+	v14 = v10 + v12 + v11;
+	v22 = v10 + v12 + v11;
+	if (a2->Ethereal() || !v13 || v14 > 0 && !a2->Portal())
+		return 0;
+	v16 = -(a2->pFacePlane_old.dist + a4 * a2->pFacePlane_old.vNormal.y + a3 * a2->pFacePlane_old.vNormal.x + a5 * a2->pFacePlane_old.vNormal.z);
+	if (v14 <= 0)
+	{
+		if (a2->pFacePlane_old.dist + a4 * a2->pFacePlane_old.vNormal.y + 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 + a4 * a2->pFacePlane_old.vNormal.y + a3 * a2->pFacePlane_old.vNormal.x + a5 * a2->pFacePlane_old.vNormal.z)) >> 14;
+	LODWORD(v18) = v16 << 16;
+	HIDWORD(v18) = v16 >> 16;
+	v24 = v18 / v22;
+	v23 = v18 / v22;
+	LOWORD(v19) = a3 + (((unsigned int)fixpoint_mul(v23, a6) + 0x8000) >> 16);
+	HIWORD(v19) = a4 + (((unsigned int)fixpoint_mul(v23, a7) + 0x8000) >> 16);
+	if (v17 > abs(v14) || v23 > *a1 << 16 || !sub_4759C9(a2, a9, v19, a5 + (((unsigned int)fixpoint_mul(v23, a8) + 0x8000) >> 16)))
+		return 0;
+	*a1 = v24 >> 16;
+	return 1;
+}
+
+//----- (00479089) --------------------------------------------------------
+bool __fastcall IsBModelVisible(unsigned int uModelID, int *reachable)
+{
+	int v3; // edi@1
+	int v4; // ebx@1
+	int v9; // eax@3
+	signed int v11; // esi@6
+	int v12; // esi@8
+	bool result; // eax@9
+	int v17; // [sp+1Ch] [bp-10h]@1
+	int v19; // [sp+20h] [bp-Ch]@3
+	int angle; // [sp+24h] [bp-8h]@1
+
+	angle = (signed int)(pODMRenderParams->uCameraFovInDegrees << 11) / 360 / 2;
+	v3 = pOutdoor->pBModels[uModelID].vBoundingCenter.x - pGame->pIndoorCameraD3D->vPartyPos.x;
+	v4 = pOutdoor->pBModels[uModelID].vBoundingCenter.y - pGame->pIndoorCameraD3D->vPartyPos.y;
+	stru_5C6E00->Sin(pGame->pIndoorCameraD3D->sRotationX);
+	v17 = v3 * stru_5C6E00->Cos(pGame->pIndoorCameraD3D->sRotationY) + v4 * stru_5C6E00->Sin(pGame->pIndoorCameraD3D->sRotationY);
+	if (pGame->pIndoorCameraD3D->sRotationX)
+		v17 = fixpoint_mul(v17, stru_5C6E00->Cos(pGame->pIndoorCameraD3D->sRotationX));
+	v19 = v4 * stru_5C6E00->Cos(pGame->pIndoorCameraD3D->sRotationY) - v3 * stru_5C6E00->Sin(pGame->pIndoorCameraD3D->sRotationY);
+	v9 = int_get_vector_length(abs(v3), abs(v4), 0);
+	//v10 = v14 * 188;
+	//v22 = v9;
+	*reachable = false;
+	if (v9 < pOutdoor->pBModels[uModelID].sBoundingRadius + 256)
+		*reachable = true;
+	if (v19 >= 0)
+		v11 = fixpoint_mul(stru_5C6E00->Sin(angle), v17) - fixpoint_mul(stru_5C6E00->Cos(angle), v19);
+	else
+		v11 = fixpoint_mul(stru_5C6E00->Cos(angle), v19) + fixpoint_mul(stru_5C6E00->Sin(angle), v17);
+	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()
+{
+	int v3; // ecx@4
+	int v4; // eax@4
+	int v5; // edx@4
+	//  int v6; // ST14_4@5
+	Vec3_int_ thisa; // [sp+Ch] [bp-10h]@8
+	int v11; // [sp+18h] [bp-4h]@4
+
+	if (!this->pODMFace->pFacePlane.vNormal.z)
+	{
+		v3 = this->pODMFace->pFacePlane.vNormal.x;
+		v4 = -this->pODMFace->pFacePlane.vNormal.y;
+		v5 = 0;
+		v11 = 65536;
+	}
+	else if ((this->pODMFace->pFacePlane.vNormal.x || this->pODMFace->pFacePlane.vNormal.y)
+		&& abs(this->pODMFace->pFacePlane.vNormal.z) < 59082)
+	{
+		thisa.x = -this->pODMFace->pFacePlane.vNormal.y;
+		thisa.y = this->pODMFace->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;
+	}
+	sTextureDeltaU = this->pODMFace->sTextureDeltaU;
+	sTextureDeltaV = this->pODMFace->sTextureDeltaV;
+	ptr_38->_48616B_frustum_odm(v4, v3, 0, 0, v5, v11);
+	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;
+	void*  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;
+	unsigned char* 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;
+
+	unsigned short* 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;
+		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;
+		delete[] skybox_xp;
+		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;
+		delete[] skybox_xp;
+		delete[] skybox_yn;
+		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;
+		delete[] skybox_xp;
+		delete[] skybox_yn;
+		delete[] skybox_yp;
+		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;
+		delete[] skybox_xp;
+		delete[] skybox_yn;
+		delete[] skybox_yp;
+		delete[] skybox_zn;
+		delete[] skybox_zp;
+		return false;
+	}
+
+	skybox_width = xn_width;
+	skybox_height = xn_height;
+
+	__debugbreak();
+	//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 = -1;
+		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 = -1;
+		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 = -1;
+		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 = -1;
+		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));
+
+		__debugbreak();
+		/*
+		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);
+		*/
+		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;
+}
+
+//----- (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
+
+	// v2 = (double)this->v_18.x;
+	//v3 = (double)this->v_18.y;
+	// v5 = (double)this->v_18.z;
+	float len = sqrt((double)this->v_18.z * (double)this->v_18.z + (double)this->v_18.y * (double)this->v_18.y + (double)this->v_18.x * (double)this->v_18.x);
+	if (fabsf(len) < 1e-6f)
+	{
+		v_18.x = 0;
+		v_18.y = 0;
+		v_18.z = 65536;
+	}
+	else
+	{
+		v_18.x = round_to_int((double)this->v_18.x / len * 65536.0);
+		v_18.y = round_to_int((double)this->v_18.y / len * 65536.0);
+		v_18.y = round_to_int((double)this->v_18.z / 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 v9; // edi@1
+	int v11; // edx@1
+	int v17; // ST0C_4@6
+	int v19; // ST0C_4@9
+	int v24; // [sp+14h] [bp-14h]@1
+	int v25; // [sp+18h] [bp-10h]@1
+	int v27; // [sp+24h] [bp-4h]@1
+
+	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);
+}
+