view Engine/Engine.cpp @ 2542:bacf9809126a

.
author a.parshin
date Sun, 10 May 2015 02:04:52 +0200
parents a902abdfc7f2
children b6140dfeac27
line wrap: on
line source



#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

#define _CRT_SECURE_NO_WARNINGS

#include "Engine/Engine.h"

#include "Arcomage\Arcomage.h"

#include "Engine/Graphics/Vis.h"
#include "Engine/Graphics/Weather.h"
#include "Engine/Graphics/LightmapBuilder.h"
#include "Engine/Graphics/DecalBuilder.h"
#include "Engine/Graphics/ParticleEngine.h"
#include "IO/Mouse.h"
#include "IO/Keyboard.h"
#include "Engine/Graphics/GammaControl.h"
#include "stru6.h"
#include "Engine/Graphics/stru9.h"
#include "Engine/Graphics/stru10.h"

#include "Engine/Party.h"
#include "Engine/Graphics/Viewport.h"
#include "Engine/Timer.h"
#include "Engine/Graphics/Outdoor.h"
#include "Engine/Graphics/Overlays.h"
#include "Media/Audio/AudioPlayer.h"
#include "Engine/LOD.h"
#include "GUI/GUIWindow.h"
#include "Engine/TurnEngine/TurnEngine.h"
#include "Media/Video/Bink_Smacker.h"
#include "Engine/Events.h"
#include "Engine/OurMath.h"
#include "Engine/texts.h"
#include "GUI/GUIFont.h"
#include "Engine/Graphics/Lights.h"
#include "Engine/Spells/CastSpellInfo.h"
#include "Engine/Tables/FrameTableInc.h"
#include "Engine/Objects/Actor.h"
#include "GUI/GUIProgressBar.h"
#include "Engine/Objects/ObjectList.h"
#include "Engine/Graphics/Level/Decoration.h"
#include "Engine/Graphics/PaletteManager.h"
#include "GUI/UI/UIHouses.h"
#include "GUI/UI/UIShops.h"
#include "GUI/UI/UIPartyCreation.h"
#include "Engine/SaveLoad.h"
#include "Engine/Objects/SpriteObject.h"
#include "Engine/Graphics/Sprites.h"
#include "Engine/Registry.h"
#include "Engine/Objects/Chest.h"

#include "GUI/UI/UIGame.h"

#include "Engine/Graphics/DecorationList.h"
#include "Engine/Tables/IconFrameTable.h"
#include "Engine/Tables/PlayerFrameTable.h"
#include "Engine/MapsLongTimer.h"
#include "Engine/Tables/StorylineTextTable.h"
#include "Engine/Tables/FactionTable.h"
#include "Engine/stru123.h"
#include "Engine/LuaVM.h"
#include "Engine/Graphics/RenderD3D11.h"
#include "Engine/MMT.h"
#include "GUI/NewUI\MainMenu.h"

#include "Game/Game.h"

#include <direct.h>




Engine *pEngine = nullptr;







//----- (00466C40) --------------------------------------------------------
const wchar_t *MENU_STATE_to_string(MENU_STATE m)
{
    switch (m)
    {
    case -1:                return L"-1";
    case MENU_MAIN:         return L"MENU_MAIN";
    case MENU_NEWGAME:      return L"MENU_NEWGAME";
    case MENU_CREDITS:      return L"MENU_CREDITS";
    case MENU_SAVELOAD:     return L"MENU_SAVELOAD";
    case MENU_EXIT_GAME:    return L"MENU_EXIT_GAME";
    case MENU_5:            return L"MENU_5";
    case MENU_CREATEPARTY:  return L"MENU_CREATEPARTY";
    case MENU_NAMEPANELESC: return L"MENU_NAMEPANELESC";
    case MENU_CREDITSPROC:  return L"MENU_CREDITSPROC";
    case MENU_LoadingProcInMainMenu: return L"MENU_LoadingProcInMainMenu";
    case MENU_DebugBLVLevel:         return L"MENU_DebugBLVLevel";
    case MENU_CREDITSCLOSE: return L"MENU_CREDITSCLOSE";
    case MENU_MMT_MAIN_MENU: return L"MENU_MMT_MAIN_MENU";
    default:                return L"unk";
    };
};


void SetCurrentMenuID(MENU_STATE uMenu)
{
    sCurrentMenuID = uMenu;
    Log::Warning(L"CurrentMenu = %s \n", MENU_STATE_to_string(uMenu));
}

//----- (00466CA0) --------------------------------------------------------
MENU_STATE GetCurrentMenuID()
{
    return sCurrentMenuID;
}



//----- (00464761) --------------------------------------------------------
void Engine_DeinitializeAndTerminate(int exitCode)
{
    SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
    ResetCursor_Palettes_LODs_Level_Audio_SFT_Windows();
    pEngine->Deinitialize();
    pRenderer->Release();
    delete window;
    //if ( !DestroyWindow(hWnd) )
    //  GetLastError();
    exit(exitCode);
}











//----- (00435694) --------------------------------------------------------
void Engine::ToggleFlags2(unsigned int uFlag)
{
    unsigned int v2; // eax@1

    v2 = this->uFlags2;
    if (v2 & uFlag)
        this->uFlags2 = v2 & ~uFlag;
    else
        this->uFlags2 = uFlag | v2;
}

//----- (0044103C) --------------------------------------------------------
void Engine::Draw()
{
    int v4; // edi@26

    uFlags2 &= ~0x02;
    if (pParty->_497FC5_check_party_perception_against_level())
        uFlags2 |= 2;

    pEngine->pIndoorCameraD3D->sRotationX = pParty->sRotationX;
    pEngine->pIndoorCameraD3D->sRotationY = pParty->sRotationY;
    pEngine->pIndoorCameraD3D->vPartyPos.x = pParty->vPosition.x - pParty->y_rotation_granularity * cosf(2 * pi_double * pParty->sRotationY / 2048.0);
    pEngine->pIndoorCameraD3D->vPartyPos.y = pParty->vPosition.y - pParty->y_rotation_granularity * sinf(2 * pi_double * pParty->sRotationY / 2048.0);
    pEngine->pIndoorCameraD3D->vPartyPos.z = pParty->vPosition.z + pParty->sEyelevel;//193, but real 353

    //pIndoorCamera->Initialize2();
    pIndoorCameraD3D->CalculateRotations(pParty->sRotationX, pParty->sRotationY);
    pIndoorCameraD3D->CreateWorldMatrixAndSomeStuff();
    pIndoorCameraD3D->_4374E8_ProllyBuildFrustrum();

    if (pMovie_Track)
    {
        /*if ( !pRenderer->pRenderD3D )
        {
        pRenderer->BeginSceneD3D();
        pMouse->DrawCursorToTarget();
        pRenderer->DrawBillboards_And_MaybeRenderSpecialEffects_And_EndScene();
        }*/
    }
    else
    {
        if (pParty->vPosition.x != pParty->vPrevPosition.x || pParty->sRotationY != pParty->sPrevRotationY || pParty->vPosition.y != pParty->vPrevPosition.y
            || pParty->sRotationX != pParty->sPrevRotationX || pParty->vPosition.z != pParty->vPrevPosition.z || pParty->sEyelevel != pParty->sPrevEyelevel)
            pParty->uFlags |= 2u;
        pParty->vPrevPosition.x = pParty->vPosition.x;
        pParty->vPrevPosition.y = pParty->vPosition.y;
        pParty->vPrevPosition.z = pParty->vPosition.z;
        //v0 = &pRenderer;
        pParty->sPrevRotationY = pParty->sRotationY;
        pParty->sPrevRotationX = pParty->sRotationX;

        pParty->sPrevEyelevel = pParty->sEyelevel;
        pRenderer->BeginSceneD3D();

        //if ( !pRenderer->pRenderD3D )
        //pMouse->DrawCursorToTarget();
        if (!PauseGameDrawing() || viewparams->field_48 == 1)
        {
            //if ( pRenderer->pRenderD3D )
            {
                float v2 = (double)(((signed int)pMiscTimer->uTotalGameTimeElapsed >> 2) & 0x1F) * 0.032258064 * 6.0;
                //v3 = v2 + 6.7553994e15;
                //pRenderer->field_1036A8_bitmapid = LODWORD(v3);
                pRenderer->hd_water_current_frame = floorf(v2 + 0.5f);
            }

            if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
                pIndoor->Draw();
            else if (uCurrentlyLoadedLevelType == LEVEL_Outdoor)
                pOutdoor->Draw();
            else
                Error("Invalid level type: %u", uCurrentlyLoadedLevelType);

            //if (pRenderer->pRenderD3D)
            {
                pDecalBuilder->DrawBloodsplats();
                pEngine->pLightmapBuilder->DrawLightmapsType(2);
            }
        }
        pRenderer->DrawBillboards_And_MaybeRenderSpecialEffects_And_EndScene();
    }

    //DEBUG: force redraw gui
    viewparams->bRedrawGameUI = true;


    pRenderer->BeginScene();
    //if (pRenderer->pRenderD3D)
    pMouse->DrawCursorToTarget();
    if (pOtherOverlayList->bRedraw)
        viewparams->bRedrawGameUI = true;
    v4 = viewparams->bRedrawGameUI;
    GameUI_Footer();
    if (!viewparams->bRedrawGameUI)
        GameUI_DrawRightPanelItems();
    else
    {
        GameUI_DrawRightPanelFrames();
        GameUI_Footer_2();
        viewparams->bRedrawGameUI = false;
    }
    if (!pMovie_Track)//!pVideoPlayer->pSmackerMovie)
    {
        GameUI_DrawMinimap(488, 16, 625, 133, viewparams->uMinimapZoom, true);//redraw = pParty->uFlags & 2);
        if (v4)
        {
            if (!PauseGameDrawing() /*&& pRenderer->pRenderD3D*/) // clear game viewport with transparent color
                pRenderer->FillRectFast(pViewport->uViewportTL_X, pViewport->uViewportTL_Y, pViewport->uViewportBR_X - pViewport->uViewportTL_X,
                pViewport->uViewportBR_Y - pViewport->uViewportTL_Y + 1,
                0x7FF);
            viewparams->field_48 = 0;
        }
    }

    viewparams->bRedrawGameUI = pOtherOverlayList->bRedraw;
    pOtherOverlayList->bRedraw = 0;

    GameUI_DrawPartySpells();
    if (v4 || pParty->pHirelings[0].evt_C || pParty->pHirelings[1].evt_C)
        GameUI_DrawHiredNPCs();
    GameUI_DrawPortraits(v4);
    GameUI_DrawLifeManaBars();
    GameUI_DrawCharacterSelectionFrame();
    if (_44100D_should_alter_right_panel())
        GameUI_DrawRightPanel();
    if (!pMovie_Track)
    {
        pStru6Instance->DrawPlayerBuffAnims();
        pOtherOverlayList->DrawTurnBasedIcon(v4);
        GameUI_DrawTorchlightAndWizardEye();
    }


    static bool render_framerate = false;
    static float framerate = 0.0f;
    static uint frames_this_second = 0;
    static uint last_frame_time = GetTickCount();
    static uint framerate_time_elapsed = 0;

    if (current_screen_type == SCREEN_GAME && uCurrentlyLoadedLevelType == LEVEL_Outdoor)
        pWeather->Draw();//Ritor1: my include

    //while(GetTickCount() - last_frame_time < 33 );//FPS control 
    uint frame_dt = GetTickCount() - last_frame_time;
    last_frame_time = GetTickCount();

    framerate_time_elapsed += frame_dt;
    if (framerate_time_elapsed >= 1000)
    {
        framerate = frames_this_second *  (1000.0f / framerate_time_elapsed);

        framerate_time_elapsed = 0;
        frames_this_second = 0;
        render_framerate = true;
    }

    ++frames_this_second;

    if (debug_information)
    {
        if (render_framerate)
        {
            sprintf(pTmpBuf.data(), "FPS: % .4f", framerate);
            pPrimaryWindow->DrawText(pFontArrus, 494, 0, Color16(0, 0, 0), pTmpBuf.data(), 0, 0, 0);
        }

        if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
        {
            int sector_id = pIndoor->GetSector(pParty->vPosition.x, pParty->vPosition.y, pParty->vPosition.z);
            sprintf(pTmpBuf.data(), "Party Sector ID:        %u/%u\n", sector_id, pIndoor->uNumSectors);
            pPrimaryWindow->DrawText(pFontArrus, 16, 16, Color16(255, 255, 255), pTmpBuf.data(), 0, 0, Color16(255, 255, 255));
        }
        sprintf(pTmpBuf.data(), "Party Position:         % d % d % d", pParty->vPosition.x, pParty->vPosition.y, pParty->vPosition.z);
        pPrimaryWindow->DrawText(pFontArrus, 16, 16 + 16, Color16(255, 255, 255), pTmpBuf.data(), 0, 0, Color16(255, 255, 255));

        if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
        {
            uint uFaceID;
            int sector_id = pIndoor->GetSector(pParty->vPosition.x, pParty->vPosition.y, pParty->vPosition.z);
            int floor_level = BLV_GetFloorLevel(pParty->vPosition.x, pParty->vPosition.y, pParty->vPosition.z + 40, sector_id, &uFaceID);
            sprintf(pTmpBuf.data(), "BLV_GetFloorLevel: %d   face_id %d\n", floor_level, uFaceID);
        }
        else
        {
            int on_water, _a6;
            int floor_level = ODM_GetFloorLevel(pParty->vPosition.x, pParty->vPosition.y, pParty->vPosition.z, 0, &on_water, &_a6, false);
            sprintf(pTmpBuf.data(), "ODM_GetFloorLevel: %d   on_water: %s    a6 = %d\n", floor_level, on_water ? "true" : "false", _a6);
        }
        pPrimaryWindow->DrawText(pFontArrus, 16, 16 + 16 + 16, Color16(255, 255, 255), pTmpBuf.data(), 0, 0, Color16(255, 255, 255));
    }

    GUI_UpdateWindows();
    pParty->UpdatePlayersAndHirelingsEmotions();

    _unused_5B5924_is_travel_ui_drawn = false;
    if (v4)
        pMouse->bRedraw = true;
    pMouse->ReadCursorWithItem();
    pMouse->DrawCursor();
    pMouse->Activate();
    pRenderer->EndScene();
    pRenderer->Present();
    pParty->uFlags &= ~2;
}

//----- (0047A815) --------------------------------------------------------
void Engine::DrawParticles()
{
    pParticleEngine->Draw();
}


//----- (0044F192) --------------------------------------------------------
void Engine::PrepareBloodsplats()
{
    for (uint i = 0; i < uNumBloodsplats; ++i)
    {
        pBloodsplatContainer->AddBloodsplat(pBloodsplats[i].x, pBloodsplats[i].y, pBloodsplats[i].z,
            pBloodsplats[i].radius, pBloodsplats[i].r, pBloodsplats[i].g, pBloodsplats[i].b);
    }
}


//----- (0044F120) --------------------------------------------------------
void Engine::PushStationaryLights(int a2)
{
    Game__StationaryLight* pLight;

    for (int i = 0; i < uNumStationaryLights; ++i)
    {
        pLight = &pStationaryLights[i];
        pStationaryLightsStack->AddLight(pLight->vPosition.x, pLight->vPosition.y, pLight->vPosition.z,
            pLight->flt_18, pLight->vRGBColor.x, pLight->vRGBColor.y, pLight->vRGBColor.z, _4E94D0_light_type);
    }
}
// 4E94D0: using guessed type char _4E94D0_light_type;

//----- (0044F0FD) --------------------------------------------------------
void Engine::_44F0FD()
{
    ToggleFlags(0x40u);

    if (!(uFlags & 0x40))
    {
        uNumBloodsplats = 0;
        field_E0C = 0;
    }
}

//----- (0044F0D8) --------------------------------------------------------
void Engine::ToggleFlags(uint uMask)
{
    if (uFlags & uMask)
        uFlags &= ~uMask;
    else
        uFlags |= uMask;
}


//----- (0044F07B) --------------------------------------------------------
bool Engine::_44F07B()
{
    if (!pKeyboardInstance->IsKeyBeingHeld(VK_SHIFT) && !pKeyboardInstance->IsKeyBeingHeld(VK_LSHIFT) &&
        !pKeyboardInstance->IsKeyBeingHeld(VK_LSHIFT) || (pKeyboardInstance->WasKeyPressed(VK_F11) == 0 &&
        pKeyboardInstance->WasKeyPressed(VK_F11)))
        return true;
    return false;
}

//----- (0044EEA7) --------------------------------------------------------
bool Engine::_44EEA7()
{
    //Game *v1; // esi@1
    //double v2; // st7@2
    float depth; // ST00_4@9
    //bool result; // eax@9
    //unsigned int v5; // eax@14
    __int64 v6; // kr00_8@21
    //unsigned int y; // [sp+4h] [bp-24h]@2
    //unsigned int x; // [sp+8h] [bp-20h]@2
    Vis_SelectionFilter *v10; // [sp+10h] [bp-18h]@2
    Vis_SelectionFilter *v11; // [sp+14h] [bp-14h]@2
    POINT cursor; // [sp+20h] [bp-8h]@1

    //v1 = this;
    ++qword_5C6DF0;
    pParticleEngine->UpdateParticles();
    pMouseInstance->GetCursorPos(&cursor);

    //x = cursor.y;
    //y = cursor.x;
    if (sub_4637E0_is_there_popup_onscreen())
    {
        v11 = &vis_face_filter;
        v10 = &vis_sprite_filter_2;
        depth = pEngine->pIndoorCameraD3D->GetPickDepth();
    }
    else
    {
        if (uFlags2 & GAME_FLAGS_2_TARGETING_MODE)
        {
            v11 = &vis_face_filter;
            v10 = &vis_sprite_filter_1;
        }
        else
        {
            v11 = &vis_face_filter;
            v10 = &vis_sprite_filter_4;
        }
        depth = 5120.0;
    }
    //depth = v2;

    PickMouse(depth, cursor.x, cursor.y, false, v10, v11);
    pLightmapBuilder->std__vector_000004_size = 0;
    pLightmapBuilder->std__vector_183808_size = 0;
    pDecalBuilder->std__vector_pDecals_size = 0;
    pDecalBuilder->field_308008 = 0;
    if (!_44F07B())
        return false;

    if (uFlags & GAME_FLAGS_1_DRAW_BLV_DEBUGS)
        pStru10Instance->bDoNotDrawPortalFrustum = false;
    if ( /*pRenderer->pRenderD3D &&*/ uCurrentlyLoadedLevelType == LEVEL_Outdoor)
        pRenderer->uFogColor = GetLevelFogColor() & 0xFFFFFF;
    if (uFlags & 0x0400)
        uFlags2 |= 0x01;
    /*if ( !pRenderer->pRenderD3D && uCurrentlyLoadedLevelType == LEVEL_Outdoor && pMobileLightsStack->uNumLightsActive )
    {
    uFlags2 |= 0x01;
    field_E10 = qword_5C6DF0;
    }*/
    v6 = qword_5C6DF0 - field_E10;
    if (qword_5C6DF0 - field_E10 == 1)
        uFlags2 |= v6;
    if (uNumStationaryLights_in_pStationaryLightsStack != pStationaryLightsStack->uNumLightsActive)
    {
        uFlags2 |= 1;
        uNumStationaryLights_in_pStationaryLightsStack = pStationaryLightsStack->uNumLightsActive;
    }
    return true;
}


//----- (0044EDE4) --------------------------------------------------------
bool Engine::AlterGamma_BLV(BLVFace *pFace, signed int *pColor)
{
    if (uFlags2 & GAME_FLAGS_2_SATURATE_LIGHTMAPS &&
        pFace->uAttributes & FACE_CAN_SATURATE_COLOR)
    {
        *pColor = ReplaceHSV(*pColor, 1.0, fSaturation, -1.0);
        return true;
    }
    else
        return false;
}

//----- (0044EE30) --------------------------------------------------------
bool Engine::AlterGamma_ODM(ODMFace *pFace, signed int *pColor)
{
    if (uFlags2 & GAME_FLAGS_2_SATURATE_LIGHTMAPS &&
        pFace->uAttributes & FACE_CAN_SATURATE_COLOR)
    {
        *pColor = ReplaceHSV(*pColor, 1.0, fSaturation, -1.0);
        return true;
    }
    else
        return false;
}


//----- (004645FA) --------------------------------------------------------
void Engine::Deinitialize()
{
    WriteWindowsRegistryInt("startinwindow", 1);//pRenderer->bWindowMode);
    //if (pRenderer->bWindowMode)
    {
        WriteWindowsRegistryInt("window X", window->GetX());
        WriteWindowsRegistryInt("window Y", window->GetY());
    }
    WriteWindowsRegistryInt("valAlwaysRun", bAlwaysRun);
    pItemsTable->Release();
    pNPCStats->Release();

    if (pMouse)
        pMouse->Deactivate();

    delete pRenderer;
    pAudioPlayer->Release();//error
    pNew_LOD->FreeSubIndexAndIO();
    pGames_LOD->FreeSubIndexAndIO();
    ClipCursor(0);
    Engine::Destroy();
    delete pEventTimer;
}

//----- (0044EE7C) --------------------------------------------------------
bool Engine::draw_debug_outlines()
{
    if (uFlags & 0x04)
    {
        pLightmapBuilder->DrawDebugOutlines(-1);
        pDecalBuilder->DrawDecalDebugOutlines();
    }
    return true;
}

//----- (0044EC23) --------------------------------------------------------
int Engine::_44EC23(struct Polygon *a2, int *a3, signed int a4)
{
    double v4; // st7@4
    //double v5; // ST00_8@4
    signed int v6; // eax@5
    //double v7; // ST00_8@6
    signed int result; // eax@8
    //double v9; // ST00_8@9
    //double v10; // ST00_8@11
    float a2a; // [sp+14h] [bp+8h]@4
    float a3a; // [sp+18h] [bp+Ch]@4
    float a3b; // [sp+18h] [bp+Ch]@6
    float a4a; // [sp+1Ch] [bp+10h]@9
    float a4b; // [sp+1Ch] [bp+10h]@11

    if (this->uFlags2 & 2 && a2->field_59 == 5 && a2->pODMFace->uAttributes & 2)
    {
        v4 = (double)a4;
        a2a = v4;
        *a3 |= 2u;
        a3a = (1.0 - this->fSaturation) * v4;
        //v5 = a3a + 6.7553994e15;
        //if ( SLODWORD(v5) >= 0 )
        if (floorf(a3a + 0.5f) >= 0)
        {
            a3b = (1.0 - this->fSaturation) * a2a;
            //v7 = a3b + 6.7553994e15;
            //v6 = LODWORD(v7);
            v6 = floorf(a3b + 0.5f);
        }
        else
            v6 = 0;
        if (a4 >= v6)
        {
            a4a = (1.0 - fSaturation) * a2a;
            //v9 = a4a + 6.7553994e15;
            //if ( SLODWORD(v9) >= 0 )
            if (floorf(a4a + 0.5f) >= 0)
            {
                a4b = (1.0 - fSaturation) * a2a;
                //v10 = a4b + 6.7553994e15;
                //result = LODWORD(v10);
                result = floorf(a4b + 0.5f);
            }
            else
                result = 0;
        }
        else
            result = a4;
    }
    else
        result = -1;
    return result;
}



//----- (00465C8B) --------------------------------------------------------
Engine *Engine::Create()
{
    return new Engine;
}

//----- (00465CF3) --------------------------------------------------------
void Engine::Destroy()
{
    delete pEngine;
    pEngine = nullptr;
}

//----- (0044ED0A) --------------------------------------------------------
signed int Engine::_44ED0A(BLVFace *a2, int *a3, signed int a4)
{
    double v4; // st7@3
    //double v5; // ST00_8@3
    signed int v6; // eax@4
    //double v7; // ST00_8@5
    signed int result; // eax@7
    //double v9; // ST00_8@8
    //double v10; // ST00_8@10
    float v11; // [sp+14h] [bp+8h]@3
    float v12; // [sp+18h] [bp+Ch]@3
    float v13; // [sp+18h] [bp+Ch]@5
    float v14; // [sp+1Ch] [bp+10h]@8
    float v15; // [sp+1Ch] [bp+10h]@10

    if (this->uFlags2 & 2 && a2->uAttributes & 2)
    {
        v4 = (double)a4;
        v11 = v4;
        *a3 |= 2u;
        v12 = (1.0 - this->fSaturation) * v4;
        //v5 = v12 + 6.7553994e15;
        if (floorf(v12 + 0.5f)/* SLODWORD(v5)*/ >= 0)
        {
            v13 = (1.0 - this->fSaturation) * v11;
            //v7 = v13 + 6.7553994e15;
            //v6 = LODWORD(v7);
            v6 = floorf(v13 + 0.5f);
        }
        else
            v6 = 0;
        if (a4 >= v6)
        {
            v14 = (1.0 - fSaturation) * v11;
            //v9 = v14 + 6.7553994e15;
            if (floorf(v14 + 0.5f)/* SLODWORD(v9)*/ >= 0)
            {
                v15 = (1.0 - fSaturation) * v11;
                //v10 = v15 + 6.7553994e15;
                //result = LODWORD(v10);
                result = floorf(v15 + 0.5f);
            }
            else
                result = 0;
        }
        else
            result = a4;
    }
    else
        result = -1;
    return result;
}


//----- (0044E4B7) --------------------------------------------------------
Engine::Engine()
{
    uNumStationaryLights = 0;
    uNumBloodsplats = 0;
    field_E0C = 0;
    field_E10 = 0;
    uNumStationaryLights_in_pStationaryLightsStack = 0;
    uFlags = 0;
    uFlags2 = 0;

    //pThreadWardInstance = new ThreadWard;
    pThreadWardInstance = nullptr;
    pParticleEngine = new ParticleEngine;
    pMouse = pMouseInstance = new Mouse;
    pLightmapBuilder = new LightmapBuilder;
    pVisInstance = new Vis;
    pStru6Instance = new stru6;
    pIndoorCameraD3D = new IndoorCameraD3D;
    pStru9Instance = new stru9;
    pStru10Instance = new stru10;
    //pStru11Instance = new stru11;
    pStru11Instance = nullptr;
    //pStru12Instance = new stru12(pStru11Instance);
    pStru12Instance = nullptr;
    //pCShow = new CShow;
    pCShow = nullptr;
    pKeyboardInstance = new Keyboard;
    //pGammaController = new GammaController;

    uFlags |= 0x0800;
    uFlags2 |= 0x24;

    _44F0FD();
}

//----- (0044E7F3) --------------------------------------------------------
Engine::~Engine()
{
    //delete pGammaController;
    delete pKeyboardInstance;
    /*delete pCShow;
    delete pStru12Instance;
    delete pStru11Instance;*/
    delete pStru10Instance;
    delete pStru9Instance;
    delete pIndoorCameraD3D;
    delete pStru6Instance;
    delete pVisInstance;
    delete pLightmapBuilder;
    delete pMouseInstance;
    delete pParticleEngine;
    //delete pThreadWardInstance;
}

//----- (0044EA5E) --------------------------------------------------------
bool Engine::PickMouse(float fPickDepth, unsigned int uMouseX, unsigned int uMouseY, bool bOutline, Vis_SelectionFilter *sprite_filter, Vis_SelectionFilter *face_filter)
{
    /*if (current_screen_type != SCREEN_GAME|| !pRenderer->pRenderD3D)
    return false;*/

    if (!pVisInstance)
    {
        MessageBoxW(nullptr, L"The 'Vis' object pointer has not been instatiated, but CGame::Pick() is trying to call through it.", nullptr, 0);
        return false;
    }

    if (uMouseX >= (signed int)pViewport->uScreen_TL_X &&
        uMouseX <= (signed int)pViewport->uScreen_BR_X &&
        uMouseY >= (signed int)pViewport->uScreen_TL_Y &&
        uMouseY <= (signed int)pViewport->uScreen_BR_Y)
    {
        pVisInstance->PickMouse(fPickDepth, uMouseX, uMouseY, sprite_filter, face_filter);

        if (bOutline)
            OutlineSelection();
    }

    return true;
}
// 4E28F8: using guessed type int current_screen_type;

//----- (0044EB12) --------------------------------------------------------
bool Engine::PickKeyboard(bool bOutline, Vis_SelectionFilter *sprite_filter, Vis_SelectionFilter *face_filter)
{
    if (current_screen_type == SCREEN_GAME && pVisInstance /*&& pRenderer->pRenderD3D*/)
    {
        bool r = pVisInstance->PickKeyboard(&pVisInstance->default_list, sprite_filter, face_filter);

        if (bOutline)
            OutlineSelection();
        return r;
    }
    return false;
}
/*
Result::Code Game::PickKeyboard(bool bOutline, struct unnamed_F93E6C *a3, struct unnamed_F93E6C *a4)
{
if (dword_4E28F8_PartyCantJumpIfTrue)
return Result::Generic;

pVis->PickKeyboard(a3, a4);
if (bOutline)
Game_outline_selection((int)this);
return Result::Success;
}
*/
// 4E28F8: using guessed type int current_screen_type;

//----- (0044EB5A) --------------------------------------------------------
void Engine::OutlineSelection()
{
    if (!pVisInstance)
        return;

    if (!pVisInstance->default_list.uNumPointers)
        return;

    Vis_ObjectInfo* object_info = pVisInstance->default_list.object_pointers[0];
    if (object_info)
        switch (object_info->object_type)
    {
        case VisObjectType_Sprite:
        {
            Log::Warning(L"Sprite outline currently unsupported");
            return;
        }

        case VisObjectType_Face:
        {
            if (uCurrentlyLoadedLevelType == LEVEL_Outdoor)
            {
                ODMFace* face = (ODMFace *)object_info->object;
                if (face->uAttributes & FACE_OUTLINED)
                    face->uAttributes &= ~FACE_OUTLINED;
                else
                    face->uAttributes |= FACE_OUTLINED;
            }
            else if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
            {
                BLVFace* face = (BLVFace *)object_info->object;
                if (face->uAttributes & FACE_OUTLINED)
                    face->uAttributes &= ~FACE_OUTLINED;
                else
                    face->uAttributes |= FACE_OUTLINED;
            }
            else
                Error("Invalid level type", uCurrentlyLoadedLevelType);
        }
            break;

        default:
        {
            MessageBoxW(nullptr, L"Undefined CObjectInfo type requested in CGame::outline_selection()", nullptr, 0);
            ExitProcess(0);
        }
    }
}





//----- (0042FBDD) --------------------------------------------------------
void  sub_42FBDD()
{
    pAudioPlayer->PlaySound(SOUND_StartMainChoice02, 0, 0, -1, 0, 0, 0, 0);
    pRenderer->DrawTextureIndexedAlpha(pBtn_YES->uX, pBtn_YES->uY, pBtn_YES->pTextures[0]);
    pRenderer->Present();
}

//----- (0042FC15) --------------------------------------------------------
void CloseWindowBackground()
{
    pAudioPlayer->PlaySound(SOUND_StartMainChoice02, -2, 0, -1, 0, 0, 0, 0);
    pRenderer->DrawTextureIndexedAlpha(pBtn_ExitCancel->uX, pBtn_ExitCancel->uY, pBtn_ExitCancel->pTextures[0]);
    pRenderer->Present();
}


//----- (0046BDC0) --------------------------------------------------------
void  UpdateUserInput_and_MapSpecificStuff()
{
    if (dword_6BE364_game_settings_1 & GAME_SETTINGS_0080_SKIP_USER_INPUT_THIS_FRAME)
    {
        dword_6BE364_game_settings_1 &= ~GAME_SETTINGS_0080_SKIP_USER_INPUT_THIS_FRAME;
        return;
    }

    if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
        BLV_UpdateUserInputAndOther();
    else if (uCurrentlyLoadedLevelType == LEVEL_Outdoor)
        ODM_UpdateUserInputAndOther();

    area_of_effect__damage_evaluate();
}

//----- (004646F0) --------------------------------------------------------
void PrepareWorld(unsigned int _0_box_loading_1_fullscreen)
{
    //if ( pRenderer->pRenderD3D )
    pEngine->pVisInstance->_4C1A02();
    pEventTimer->Pause();
    pMiscTimer->Pause();
    pParty->uFlags = 2;
    CastSpellInfoHelpers::_427D48();
    ResetCursor_Palettes_LODs_Level_Audio_SFT_Windows();
    DoPrepareWorld(0, (_0_box_loading_1_fullscreen == 0) + 1);
    pMiscTimer->Resume();
    pEventTimer->Resume();
}

//----- (00464866) --------------------------------------------------------
void DoPrepareWorld(unsigned int bLoading, int _1_fullscreen_loading_2_box)
{
    char *v3; // eax@1
    unsigned int v5; // eax@3
    char Str1[20]; // [sp+Ch] [bp-18h]@1
    unsigned int v9; // [sp+20h] [bp-4h]@1

    v9 = bLoading;
    ResetCursor_Palettes_LODs_Level_Audio_SFT_Windows();
    pDecalBuilder->Reset(0);
    pGameLoadingUI_ProgressBar->Initialize(_1_fullscreen_loading_2_box == 1 ? GUIProgressBar::TYPE_Fullscreen :
        GUIProgressBar::TYPE_Box);
    strcpy(Str1, pCurrentMapName);
    v3 = strtok(Str1, ".");
    strcpy(Str1, v3);
    Level_LoadEvtAndStr(Str1);
    LoadLevel_InitializeLevelEvt();
    strcpy(Str1, pCurrentMapName);
    _strrev(Str1);
    strtok(Str1, ".");
    _strrev(Str1);

    for (uint i = 0; i < 1000; ++i)
        pSpriteObjects[i].uObjectDescID = 0;

    v5 = pMapStats->GetMapInfo(pCurrentMapName);
    bUnderwater = false;
    uLevelMapStatsID = v5;
    pEngine->uFlags2 &= 0xFFFFFFF7u;
    if (!_stricmp(pCurrentMapName, "out15.odm"))
    {
        bUnderwater = true;
        pEngine->uFlags2 |= GAME_FLAGS_2_ALTER_GRAVITY;
    }
    pParty->floor_face_pid = 0;
    if (_stricmp(Str1, "blv"))
        PrepareToLoadODM(v9, 0);
    else
        PrepareToLoadBLV(v9);
    pAudioPlayer->SetMapEAX();
    _461103_load_level_sub();
    if (!_stricmp(pCurrentMapName, "d11.blv") || !_stricmp(pCurrentMapName, "d10.blv"))
    {
        //spawning grounds & walls of mist - no loot & exp from monsters

        for (uint i = 0; i < uNumActors; ++i)
        {
            pActors[i].pMonsterInfo.uTreasureType = 0;
            pActors[i].pMonsterInfo.uTreasureDiceRolls = 0;
            pActors[i].pMonsterInfo.uExp = 0;
        }
    }
    bDialogueUI_InitializeActor_NPC_ID = 0;
    OnMapLoad();
    pGameLoadingUI_ProgressBar->Progress();
    memset(&pRenderer->pBillboardRenderListD3D, 0, sizeof(pRenderer->pBillboardRenderListD3D));
    pGameLoadingUI_ProgressBar->Release();
    _flushall();
}

void IntegrityTest()
{
    static_assert(sizeof(MovieHeader) == 44, "Wrong type size");
    static_assert(sizeof(SoundDesc_mm6) == 112, "Wrong type size");
    static_assert(sizeof(SoundDesc) == 120, "Wrong type size");
    static_assert(sizeof(OverlayDesc) == 8, "Wrong type size");
    static_assert(sizeof(ChestDesc) == 36, "Wrong type size");
    static_assert(sizeof(ObjectDesc_mm6) == 52, "Wrong type size");
    static_assert(sizeof(ObjectDesc) == 56, "Wrong type size");
    static_assert(sizeof(DecorationDesc) == 84, "Wrong type size");
    static_assert(sizeof(IconFrame) == 32, "Wrong type size");
    static_assert(sizeof(PlayerFrame) == 10, "Wrong type size");
    static_assert(sizeof(TextureFrame) == 20, "Wrong type size");
    static_assert(sizeof(SpriteFrame) == 60, "Wrong type size");
    static_assert(sizeof(RenderVertexSoft) == 0x30, "Wrong type size");
    static_assert(sizeof(RenderBillboard) == 0x34, "Wrong type size");
    static_assert(sizeof(Texture) == 0x48, "Wrong type size");
    //static_assert(sizeof(RGBTexture) == 0x28, "Wrong type size");
    //static_assert(sizeof(LODFile_IconsBitmaps) == 0x11BB8 + 4, "Wrong type size"); // + virtual dtor ptr
    static_assert(sizeof(AudioPlayer) == 0xC84, "Wrong type size");
    static_assert(sizeof(SoundDesc) == 0x78, "Wrong type size");
    static_assert(sizeof(stru339_spell_sound) == 0xAFD8, "Wrong type size");
    //static_assert(sizeof(VideoPlayer) == 0x108 + 4, "Wrong type size");
    static_assert(sizeof(MovieHeader) == 0x2C, "Wrong type size");
    static_assert(sizeof(DecorationDesc) == 0x54, "Wrong type size");
    static_assert(sizeof(ObjectDesc) == 0x38, "Wrong type size");
    static_assert(sizeof(OverlayDesc) == 0x8, "Wrong type size");
    static_assert(sizeof(ChestDesc) == 0x24, "Wrong type size");
    static_assert(sizeof(TileDesc) == 0x1A, "Wrong type size");
    static_assert(sizeof(MonsterDesc_mm6) == 148, "Wrong type size");
    static_assert(sizeof(MonsterDesc) == 152, "Wrong type size");
    static_assert(sizeof(Timer) == 0x28, "Wrong type size");
    static_assert(sizeof(OtherOverlay) == 0x14, "Wrong type size");
    static_assert(sizeof(ItemGen) == 0x24, "Wrong type size");
    static_assert(sizeof(SpriteObject) == 0x70, "Wrong type size");
    static_assert(sizeof(ItemDesc) == 0x30, "Wrong type size");
    static_assert(sizeof(ItemsTable) == 0x117A0, "Wrong type size");
    static_assert(sizeof(Chest) == 0x14CC, "Wrong type size");
    static_assert(sizeof(MapInfo) == 0x44, "Wrong type size");
    static_assert(sizeof(SpellInfo) == 0x24, "Wrong type size");
    static_assert(sizeof(SpellData) == 0x14, "Wrong type size");
    static_assert(sizeof(SpellBuff) == 0x10, "Wrong type size");
    static_assert(sizeof(AIDirection) == 0x1C, "Wrong type size");
    static_assert(sizeof(ActorJob) == 0xC, "Wrong type size");
    static_assert(sizeof(Actor) == 0x344, "Wrong type size");
    static_assert(sizeof(LevelDecoration) == 0x20, "Wrong type size");
    static_assert(sizeof(KeyboardActionMapping) == 0x20C, "Wrong type size");
    static_assert(sizeof(UIAnimation) == 0xD, "Wrong type size");
    static_assert(sizeof(SpawnPointMM7) == 0x18, "Wrong type size");
    static_assert(sizeof(ODMFace) == 0x134, "Wrong type size");
    static_assert(sizeof(BSPNode) == 0x8, "Wrong type size");
    static_assert(sizeof(BSPModel) == 0xBC, "Wrong type size");
    static_assert(sizeof(OutdoorLocation) == 0x1C28C, "Wrong type size");
    static_assert(sizeof(BLVFace) == 0x60, "Wrong type size");
    static_assert(sizeof(BLVFaceExtra) == 0x24, "Wrong type size");
    static_assert(sizeof(BLVSector) == 0x74, "Wrong type size");
    static_assert(sizeof(BLVLightMM7) == 0x10, "Wrong type size");
    static_assert(sizeof(BLVDoor) == 0x50, "Wrong type size");
    static_assert(sizeof(IndoorLocation) == 0x690, "Wrong type size");
    //static_assert(sizeof(ODMRenderParams) == 0x74, "Wrong type size");
    static_assert(sizeof(Mouse) == 0x114, "Wrong type size");
    static_assert(sizeof(Particle_sw) == 0x68, "Wrong type size");
    static_assert(sizeof(Particle) == 0x68, "Wrong type size");
    static_assert(sizeof(ParticleEngine) == 0xE430, "Wrong type size");
    static_assert(sizeof(Lightmap) == 0xC1C, "Wrong type size");
    static_assert(sizeof(LightmapBuilder) == 0x3CBC38, "Wrong type size");
    static_assert(sizeof(Vis_SelectionList) == 0x2008, "Wrong type size");
    static_assert(sizeof(Vis) == 0x20D0, "Wrong type size");
    static_assert(sizeof(PlayerBuffAnim) == 0x10, "Wrong type size");
    static_assert(sizeof(ProjectileAnim) == 0x1C, "Wrong type size");
    static_assert(sizeof(stru6) == 0x5F8, "Wrong type size");
    static_assert(sizeof(IndoorCameraD3D_Vec3) == 0x10, "Wrong type size");
    static_assert(sizeof(IndoorCameraD3D_Vec4) == 0x18, "Wrong type size"); //should be 14 (10 vec3 + 4 vdtor)  but 18 coz of his +4 from own vdtor, but it is odd since vdtor already present from vec3
    //static_assert(sizeof(IndoorCameraD3D) == 0x1A1384, "Wrong type size");
    static_assert(sizeof(StationaryLight) == 0xC, "Wrong type size");
    static_assert(sizeof(LightsStack_StationaryLight_) == 0x12C8, "Wrong type size");
    static_assert(sizeof(MobileLight) == 0x12, "Wrong type size");
    static_assert(sizeof(LightsStack_MobileLight_) == 0x1C28, "Wrong type size");
    static_assert(sizeof(Engine) == 0xE78, "Wrong type size");
    static_assert(sizeof(stru141_actor_collision_object) == 0xA8, "Wrong type size");
    static_assert(sizeof(ActionQueue) == 0x7C, "Wrong type size");
    static_assert(sizeof(NPCData) == 0x4C, "Wrong type size");
    static_assert(sizeof(NPCStats) == 0x17FFC, "Wrong type size");
    static_assert(sizeof(BspRenderer) == 0x53740, "Wrong type size");
    static_assert(sizeof(PaletteManager) == 0x267AF0, "Wrong type size");
    static_assert(sizeof(ViewingParams) == 0x26C, "Wrong type size");
    //static_assert(sizeof(IndoorCamera) == 0x50, "Wrong type size");
    static_assert(sizeof(Bloodsplat) == 0x28, "Wrong type size");
    static_assert(sizeof(BloodsplatContainer) == 0xA0C, "Wrong type size");
    static_assert(sizeof(TrailParticle) == 0x18, "Wrong type size");
    static_assert(sizeof(EventIndex) == 0xC, "Wrong type size");
    static_assert(sizeof(_2devent) == 0x34, "Wrong type size");
    static_assert(sizeof(MapsLongTimer) == 0x20, "Wrong type size");
    static_assert(sizeof(SavegameHeader) == 0x64, "Wrong type size");
    static_assert(sizeof(SavegameList) == 0x3138, "Wrong type size");
    static_assert(sizeof(StorylineText) == 0x160, "Wrong type size");
    static_assert(sizeof(FactionTable) == 0x1EF1, "Wrong type size");
    static_assert(sizeof(Decal) == 0xC20, "Wrong type size");
    static_assert(sizeof(DecalBuilder) == 0x30C038, "Wrong type size");
    static_assert(sizeof(MonsterInfo) == 0x58, "Wrong type size");
    static_assert(sizeof(MonsterStats) == 0x5BA0, "Wrong type size");
    static_assert(sizeof(RenderD3D) == 0x148, "Wrong type size");
    //  static_assert(sizeof(Render) == 0x129844, "Wrong type size");
    static_assert(sizeof(Player) == 0x1B3C, "Wrong type size");
    static_assert(sizeof(PartyTimeStruct) == 0x678, "Wrong type size");
    static_assert(sizeof(Party) == 0x16238, "Wrong type size");
    static_assert(sizeof(GUIButton) == 0xBC, "Wrong type size");
    static_assert(sizeof(GUIWindow) == 0x54, "Wrong type size");
    //static_assert(sizeof(GUIProgressBar) == 0x1B8, "Wrong type size");
    static_assert(sizeof(GUIFont) == 0x1020, "Wrong type size");
    // static_assert(sizeof(stru262_TurnBased) == 0x40, "Wrong type size");
    //static_assert(sizeof(ArcomageGame) == 0xFB, "Wrong type size");
    static_assert(sizeof(CastSpellInfo) == 0x14, "Wrong type size");
    static_assert(sizeof(ArcomageCard) == 0x6C, "Wrong type size");
    static_assert(sizeof(stru320) == 0x3FC, "Wrong type size");
    static_assert(sizeof(TravelInfo) == 0x20, "Wrong type size");
    static_assert(sizeof(stru336) == 0x798, "Wrong type size");
    static_assert(sizeof(Vec3_short_) == 6, "Wrong type size");
    static_assert(sizeof(BLVFace) == 96, "Wrong type size");
    static_assert(sizeof(BLVFaceExtra) == 36, "Wrong type size");
    static_assert(sizeof(BLVSector) == 116, "Wrong type size");
    static_assert(sizeof(LevelDecoration) == 32, "Wrong type size");
    static_assert(sizeof(BLVLightMM7) == 16, "Wrong type size");
    static_assert(sizeof(BSPNode) == 8, "Wrong type size");
    static_assert(sizeof(SpawnPointMM7) == 24, "Wrong type size");
    static_assert(sizeof(DDM_DLV_Header) == 40, "Wrong type size");
    static_assert(sizeof(Actor) == 836, "Wrong type size");
    static_assert(sizeof(SpriteObject) == 112, "Wrong type size");
    static_assert(sizeof(Chest) == 5324, "Wrong type size");
    static_assert(sizeof(stru123) == 0xC8, "Wrong type size");
    static_assert(sizeof(BLVMapOutline) == 12, "Wrong type size");
    static_assert(sizeof(LODSprite) == 0x28, "Wrong type size");
}


//----- (004647AB) --------------------------------------------------------
void FinalInitialization()
{
    pViewport->SetScreen(viewparams->uSomeX, viewparams->uSomeY, viewparams->uSomeZ, viewparams->uSomeW);
    pViewport->SetFOV(flt_6BE3A0 * 65536.0f);

    //pIndoorCamera = new IndoorCamera;
    //pIndoorCamera->Initialize(65, viewparams->uScreen_BttmR_X - viewparams->uScreen_topL_X + 1,
    //                              viewparams->uScreen_BttmR_Y - viewparams->uScreen_topL_Y + 1);

    InitializeTurnBasedAnimations(&stru_50C198);
    pBitmaps_LOD->_inlined_sub1();
    pSprites_LOD->_inlined_sub1();
    pIcons_LOD->_inlined_sub1();
}
// 6BE3A0: using guessed type float flt_6BE3A0;



//----- (00464E17) --------------------------------------------------------
bool __fastcall CheckMM7CD(char c)
{
    char DstBuf[256] = { 0 };
    char strCommand[256] = { 0 }; // [sp+10Ch] [bp-118h]@1
    char Filename[20] = { 0 }; // [sp+20Ch] [bp-18h]@1

    wchar_t pMagicPath[1024];
    swprintf(pMagicPath, wcslen(L"%C:\\anims\\magic7.vid"), L"%C:\\anims\\magic7.vid", c);
    if (GetFileAttributesW(pMagicPath) == -1)
        return false;

    //Open CD audio
    wsprintfA(strCommand, "open %c: type cdaudio alias CD", c);
    if (!mciSendStringA(strCommand, DstBuf, 255, 0))
    {
        wsprintfA(strCommand, "info CD UPC wait");
        mciSendStringA(strCommand, DstBuf, 255, 0);
        wsprintfA(strCommand, "close CD");
        mciSendStringA(strCommand, DstBuf, 255, 0);
    }

    memcpy(Filename, "X:\\anims\\magic7.vid", sizeof(Filename));
    *Filename = c;

    FILE* f = fopen(Filename, "rb");
    if (!f)
        return false;

    if (!fseek(f, 0, SEEK_END))
    {
        if (!fseek(f, -100, SEEK_CUR))
            fread(DstBuf, 1, 0x64u, f);

        fclose(f);
        return true;
    }
    fclose(f);
    return false;
}

//----- (00464F1B) --------------------------------------------------------
signed int __stdcall InsertMM7CDDialogFunc(HWND hDlg, int a2, __int16 a3, int a4)
{
    char v4; // zf@3
    int v6; // eax@10
    int v7; // eax@11
    int v8; // eax@12
    int v9; // eax@13
    BOOL(__stdcall *v10)(HWND, int, LPCSTR); // edi@15
    const CHAR *v11; // [sp-Ch] [bp-Ch]@15
    INT_PTR v12; // [sp-4h] [bp-4h]@5

    if (a2 == 272)
    {
        hInsertCDWindow = hDlg;
        v6 = (GetUserDefaultLangID() & 0x3FF) - 7;
        if (v6)
        {
            v7 = v6 - 3;
            if (v7)
            {
                v8 = v7 - 2;
                if (v8)
                {
                    v9 = v8 - 4;
                    if (v9)
                    {
                        if (v9 != 5)
                            return 0;
                        SetWindowTextA(hDlg, "Wloz CD-ROM numer 2");
                        v10 = SetDlgItemTextA;
                        SetDlgItemTextA(hDlg, 1010, "Wloz CD-ROM numer 2 Might and Magic® VII.");
                        v11 = "Odwolaj";
                    }
                    else
                    {
                        SetWindowTextA(hDlg, "Inserire il secondo CD");
                        v10 = SetDlgItemTextA;
                        SetDlgItemTextA(hDlg, 1010, "Inserire il secondo CD di Might and Magic® VII.");
                        v11 = "Annulla";
                    }
                }
                else
                {
                    SetWindowTextA(hDlg, "Insйrez le CD 2");
                    v10 = SetDlgItemTextA;
                    SetDlgItemTextA(hDlg, 1010, "Insйrez Might & Magic® VII CD 2.");
                    v11 = "Supprimer";
                }
            }
            else
            {
                SetWindowTextA(hDlg, "Por favor, inserte disco 2");
                v10 = SetDlgItemTextA;
                SetDlgItemTextA(hDlg, 1010, "Por favor, inserte disco 2 de Might & Magic® VII.");
                v11 = "Cancelar";
            }
        }
        else
        {
            SetWindowTextA(hDlg, "Bitte CD 2 einlegen");
            v10 = SetDlgItemTextA;
            SetDlgItemTextA(hDlg, 1010, "Bitte CD 2 von Might and Magic® VII einlegen.");
            v11 = "Abbrechen";
        }
        v10(hDlg, 2, v11);
        return 0;
    }
    if (a2 == 273)
    {
        if (a3 == 2)
        {
            v12 = 0;
            EndDialog(hDlg, v12);
            return 1;
        }
        v4 = a3 == 1;
    }
    else
    {
        v4 = a2 == 1025;
    }
    if (v4)
    {
        v12 = 1;
        EndDialog(hDlg, v12);
        return 1;
    }
    return 0;
}

//----- (00465061) --------------------------------------------------------
bool __fastcall FindMM7CD(HWND hWnd, char *pCDDrive)
{
    char drive[4] = { 'X', ':', '\\', 0 };

    bool bGotCDFromRegistry = false;

    HKEY hSoftware = nullptr,
        hNWC = nullptr,
        hMM7 = nullptr,
        hVersion = nullptr;
    if (!RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ | KEY_WOW64_32KEY, &hSoftware))
    {
        if (!RegOpenKeyExA(hSoftware, "New World Computing", 0, KEY_READ | KEY_WOW64_32KEY, &hNWC))
        {
            if (!RegOpenKeyExA(hNWC, "Might and Magic VII", 0, KEY_READ | KEY_WOW64_32KEY, &hMM7))
            {
                if (!RegOpenKeyExA(hMM7, "1.0", 0, KEY_READ | KEY_WOW64_32KEY, &hVersion))
                {
                    DWORD cbData = 3;
                    if (!RegQueryValueExA(hVersion, "CDDrive", 0, 0, (BYTE *)drive, &cbData))
                        bGotCDFromRegistry = true;
                }
                RegCloseKey(hVersion);
            }
            RegCloseKey(hMM7);
        }
        RegCloseKey(hNWC);
    }
    RegCloseKey(hSoftware);

    if (bGotCDFromRegistry)
        if (CheckMM7CD(*drive))
        {
        cMM7GameCDDriveLetter = *drive;
        return true;
        }

    while (true)
    {
        for (uint i = 0; i < 26; ++i)
        {
            drive[0] = 'A' + i;

            if (GetDriveTypeA(drive) == DRIVE_CDROM)
                if (CheckMM7CD(*drive))
                {
                cMM7GameCDDriveLetter = *drive;
                WriteWindowsRegistryString("CDDrive", drive);
                return true;
                }
        }

        if (DialogBoxParamA(GetModuleHandleW(nullptr), "InsertCD", hWnd, (DLGPROC)InsertMM7CDDialogFunc, 0))
            continue;
        return false;
    }
}

//----- (004651F4) --------------------------------------------------------
bool MM7_Initialize(int game_width, int game_height)
{
    wchar_t pCurrentDir[1024];
    _wgetcwd(pCurrentDir, 1024);

    wchar_t pMM6IniFile[1024];
    wsprintfW(pMM6IniFile, L"%s\\mm6.ini", pCurrentDir);

    bCanLoadFromCD = GetPrivateProfileIntW(L"settings", L"use_cd", 1, pMM6IniFile);
    if (bNoCD)
        bCanLoadFromCD = false;
    if (bCanLoadFromCD)
    {
        Log::Warning(L"Checking for CD...");
        if (!FindMM7CD(nullptr, &cMM7GameCDDriveLetter))
            return false;
        Log::Warning(L"...done.");
    }


    srand(GetTickCount());

    pEventTimer = Timer::Create();
    pEventTimer->Initialize();
    window = OSWindow::Create(L"Might and Magic® Trilogy", game_width, game_height);//Create  game window

    bool use_d3d11 = false;
    if (use_d3d11)
        pRenderer = RenderD3D11::Create();
    else
        pRenderer = Render::Create();//Create DirectX
    if (!pRenderer)
    {
        Log::Warning(L"Render creation failed");
        return false;
    }
    else
    {
        //bool bWindowMode = ReadWindowsRegistryInt("startinwindow", false);
        //uint uDefaultDevice = ReadWindowsRegistryInt("D3D Device", 1);

        if (!pRenderer->Initialize(window/*, bColoredLights, uLevelOfDetail, bTinting*/))
        {
            Log::Warning(L"Render failed to initialize");
            return false;
        }
    }

    game_starting_year = 1168;

    pParty = new Party;
    memset(&pParty->pHirelings, 0, sizeof(pParty->pHirelings));
    pParty->uWalkSpeed = GetPrivateProfileIntW(L"debug", L"walkspeed", 384, pMM6IniFile);
    pParty->uDefaultEyelevel = GetPrivateProfileIntW(L"party", L"eyelevel", 160, pMM6IniFile);
    pParty->sEyelevel = pParty->uDefaultEyelevel;
    pParty->uDefaultPartyHeight = GetPrivateProfileIntW(L"party", L"height", 192, pMM6IniFile);
    pParty->uPartyHeight = pParty->uDefaultPartyHeight;

    MM6_Initialize(pMM6IniFile);

    pKeyActionMap = new KeyboardActionMapping;

    OnTimer(1);
    GameUI_StatusBar_UpdateTimedString(1);
    pEngine = Engine::Create();
    pMouse = pEngine->pMouseInstance;


    pIcons_LOD = new LODFile_IconsBitmaps;
    if (!pIcons_LOD->Load("data\\icons.lod", "icons"))
    {
        MessageBoxW(nullptr, L"Some files are missing\n\nPlease Reinstall.",
            L"Files Missing", MB_ICONEXCLAMATION);
        return false;
    }
    pIcons_LOD->dword_011BA4 = 0;

    pEvents_LOD = new LODFile_IconsBitmaps;
    if (!pEvents_LOD->Load("data\\events.lod", "icons"))
    {
        MessageBoxW(nullptr, L"Some files are missing\n\nPlease Reinstall.",
            L"Files Missing", MB_ICONEXCLAMATION);
        return false;
    }

    InitializeGameText();

    pBitmaps_LOD = new LODFile_IconsBitmaps;
    if (!pBitmaps_LOD->Load("data\\bitmaps.lod", "bitmaps"))
    {
        MessageBoxA(nullptr, pGlobalTXT_LocalizationStrings[63],
            pGlobalTXT_LocalizationStrings[184], MB_ICONEXCLAMATION);
        return false;
    }

    pSprites_LOD = new LODFile_Sprites;
    if (!pSprites_LOD->LoadSprites("data\\sprites.lod"))
    {
        MessageBoxA(nullptr,
            pGlobalTXT_LocalizationStrings[63],
            pGlobalTXT_LocalizationStrings[184], MB_ICONEXCLAMATION);
        return false;
    }


#if 0
    if (_access("../MM_VI/data/icons.lod", 0) == 0)
    {
        pIcons_LOD_mm6 = new LODFile_IconsBitmaps;
        if (!pIcons_LOD_mm6->Load("../MM_VI/data/icons.lod", "icons"))
        {
            delete pIcons_LOD_mm6;
            pIcons_LOD_mm6 = nullptr;
            Log::Warning(L"Unable to load mm6:icons.lod");
        }
    }
    else
        Log::Warning(L"Unable to find mm6:icons.lod");

    if (_access("../MM_VI/data/bitmaps.lod", 0) == 0)
    {
        pBitmaps_LOD_mm6 = new LODFile_IconsBitmaps;
        if (!pBitmaps_LOD_mm6->Load("../MM_VI/data/bitmaps.lod", "bitmaps"))
        {
            delete pBitmaps_LOD_mm6;
            pBitmaps_LOD_mm6 = nullptr;
            Log::Warning(L"Unable to load mm6:bitmaps.lod");
        }
    }
    else
        Log::Warning(L"Unable to find mm6:bitmaps.lod");

    auto mm6_sprite_container_name = bUseLoResSprites ? "../MM_VI/data/spriteLO.lod"
        : "../MM_VI/data/sprites.lod";
    if (_access(mm6_sprite_container_name, 0) == 0)
    {
        pSprites_LOD_mm6 = new LODFile_Sprites;
        if (!pSprites_LOD_mm6->LoadSprites(mm6_sprite_container_name))
        {
            delete pSprites_LOD_mm6;
            pSprites_LOD_mm6 = nullptr;
            Log::Warning(L"Unable to load mm6:sprites.lod");
        }
    }
    else
        Log::Warning(L"Unable to find mm6:sprites.lod");


    if (_access("../mm8/data/icons.lod", 0) == 0)
    {
        pIcons_LOD_mm8 = new LODFile_IconsBitmaps;
        if (!pIcons_LOD_mm8->Load("../mm8/data/icons.lod", "icons"))
        {
            delete pIcons_LOD_mm8;
            pIcons_LOD_mm8 = nullptr;
            Log::Warning(L"Unable to load mm8:icons.lod");
        }
    }
    else
        Log::Warning(L"Unable to find mm8:icons.lod");


    if (_access("../mm8/data/bitmaps.lod", 0) == 0)
    {
        pBitmaps_LOD_mm8 = new LODFile_IconsBitmaps;
        if (!pBitmaps_LOD_mm8->Load("../mm8/data/bitmaps.lod", "bitmaps"))
        {
            delete pBitmaps_LOD_mm8;
            pBitmaps_LOD_mm8 = nullptr;
            Log::Warning(L"Unable to load mm8:bitmaps.lod");
        }
    }
    else
        Log::Warning(L"Unable to find mm8:bitmaps.lod");


    if (_access("../mm8/data/sprites.lod", 0) == 0)
    {
        pSprites_LOD_mm8 = new LODFile_Sprites;
        if (!pSprites_LOD_mm8->LoadSprites("../mm8/data/sprites.lod"))
        {
            delete pSprites_LOD_mm8;
            pSprites_LOD_mm8 = nullptr;
            Log::Warning(L"Unable to load mm8:sprites.lod");
        }
    }
    else
        Log::Warning(L"Unable to find mm8:sprites.lod");
#endif

    {
        void *sft_mm6 = pIcons_LOD_mm6 ? pIcons_LOD_mm6->LoadRaw("dsft.bin", 1) : nullptr,
            *sft_mm8 = nullptr;
        void *sft_mm7 = pEvents_LOD->LoadRaw("dsft.bin", 1);
        pSpriteFrameTable = new SpriteFrameTable;
        pSpriteFrameTable->FromFile(sft_mm6, sft_mm7, sft_mm8);
        free(sft_mm6);
        free(sft_mm7);
        free(sft_mm8);

        void *tft_mm6 = pIcons_LOD_mm6 ? pIcons_LOD_mm6->LoadRaw("dtft.bin", 1) : nullptr,
            *tft_mm8 = nullptr;
        void *tft_mm7 = pEvents_LOD->LoadRaw("dtft.bin", 1);
        pTextureFrameTable = new TextureFrameTable;
        pTextureFrameTable->FromFile(tft_mm6, tft_mm7, tft_mm8);
        free(tft_mm6);
        free(tft_mm7);
        free(tft_mm8);

        void *tiles_mm6 = pIcons_LOD_mm6 ? pIcons_LOD_mm6->LoadRaw("dtile.bin", 1) : nullptr,
            *tiles_mm8 = nullptr;
        void *tiles_mm7 = pEvents_LOD->LoadRaw("dtile.bin", 1);
        pTileTable = new TileTable;
        pTileTable->FromFile(tiles_mm6, tiles_mm7, tiles_mm8);
        free(tiles_mm6);
        free(tiles_mm7);
        free(tiles_mm8);

        void *pft_mm6 = pIcons_LOD_mm6 ? pIcons_LOD_mm6->LoadRaw("dpft.bin", 1) : nullptr,
            *pft_mm8 = nullptr;
        void *pft_mm7 = pEvents_LOD->LoadRaw("dpft.bin", 1);
        pPlayerFrameTable = new PlayerFrameTable;
        pPlayerFrameTable->FromFile(pft_mm6, pft_mm7, pft_mm8);
        free(pft_mm6);
        free(pft_mm7);
        free(pft_mm8);

        void *ift_mm6 = pIcons_LOD_mm6 ? pIcons_LOD_mm6->LoadRaw("dift.bin", 1) : nullptr,
            *ift_mm8 = nullptr;
        void *ift_mm7 = pEvents_LOD->LoadRaw("dift.bin", 1);
        pIconsFrameTable = new IconFrameTable;
        pIconsFrameTable->FromFile(ift_mm6, ift_mm7, ift_mm8);
        free(ift_mm6);
        free(ift_mm7);
        free(ift_mm8);

        void *decs_mm6 = pIcons_LOD_mm6 ? pIcons_LOD_mm6->LoadRaw("ddeclist.bin", 1) : nullptr,
            *decs_mm8 = nullptr;
        void *decs_mm7 = pEvents_LOD->LoadRaw("ddeclist.bin", 1);
        pDecorationList = new DecorationList;
        pDecorationList->FromFile(decs_mm6, decs_mm7, decs_mm8);
        free(decs_mm6);
        free(decs_mm7);
        free(decs_mm8);

        void *objs_mm6 = pIcons_LOD_mm6 ? pIcons_LOD_mm6->LoadRaw("dobjlist.bin", 1) : nullptr,
            *objs_mm8 = nullptr;
        void *objs_mm7 = pEvents_LOD->LoadRaw("dobjlist.bin", 1);
        pObjectList = new ObjectList;
        pObjectList->FromFile(objs_mm6, objs_mm7, objs_mm8);
        free(objs_mm6);
        free(objs_mm7);
        free(objs_mm8);

        void *mons_mm6 = pIcons_LOD_mm6 ? pIcons_LOD_mm6->LoadRaw("dmonlist.bin", 1) : nullptr,
            *mons_mm8 = nullptr;
        void *mons_mm7 = pEvents_LOD->LoadRaw("dmonlist.bin", 1);
        pMonsterList = new MonsterList;
        pMonsterList->FromFile(mons_mm6, mons_mm7, mons_mm8);
        free(mons_mm6);
        free(mons_mm7);
        free(mons_mm8);

        void *chests_mm6 = pIcons_LOD_mm6 ? pIcons_LOD_mm6->LoadRaw("dchest.bin", 1) : nullptr,
            *chests_mm8 = nullptr;
        void *chests_mm7 = pEvents_LOD->LoadRaw("dchest.bin", 1);
        pChestList = new ChestList;
        pChestList->FromFile(chests_mm6, chests_mm7, chests_mm8);
        free(chests_mm6);
        free(chests_mm7);
        free(chests_mm8);

        void *overlays_mm6 = pIcons_LOD_mm6 ? pIcons_LOD_mm6->LoadRaw("doverlay.bin", 1) : nullptr,
            *overlays_mm8 = nullptr;
        void *overlays_mm7 = pEvents_LOD->LoadRaw("doverlay.bin", 1);
        pOverlayList = new OverlayList;
        pOverlayList->FromFile(overlays_mm6, overlays_mm7, overlays_mm8);
        free(overlays_mm6);
        free(overlays_mm7);
        free(overlays_mm8);

        void *sounds_mm6 = pIcons_LOD_mm6 ? pIcons_LOD_mm6->LoadRaw("dsounds.bin", 1) : nullptr,
            *sounds_mm8 = nullptr;
        void *sounds_mm7 = pEvents_LOD->LoadRaw("dsounds.bin", 1);
        pSoundList = new SoundList;
        pSoundList->FromFile(sounds_mm6, sounds_mm7, sounds_mm8);
        free(sounds_mm6);
        free(sounds_mm7);
        free(sounds_mm8);
    }




    if (dword_6BE368_debug_settings_2 & DEBUG_SETTINGS_RUN_IN_WIDOW)
    {
        //window->SetWindowedMode(game_width, game_height);
        pRenderer->SwitchToWindow();
    }
    else
    {
        __debugbreak(); // Nomad
        window->SetFullscreenMode();
        pRenderer->InitializeFullscreen();
    }

    uSoundVolumeMultiplier = min(9, ReadWindowsRegistryInt("soundflag", 9));
    uMusicVolimeMultiplier = min(9, ReadWindowsRegistryInt("musicflag", 9));
    uVoicesVolumeMultiplier = min(9, ReadWindowsRegistryInt("CharVoices", 9));
    bShowDamage = ReadWindowsRegistryInt("ShowDamage", 1) != 0;

    uGammaPos = min(4, ReadWindowsRegistryInt("GammaPos", 4));
    //pEngine->pGammaController->Initialize(uGammaPos * 0.1 + 0.6);

    if (ReadWindowsRegistryInt("Bloodsplats", 1))
        pEngine->uFlags2 |= GAME_FLAGS_2_DRAW_BLOODSPLATS;
    else
        pEngine->uFlags2 &= ~GAME_FLAGS_2_DRAW_BLOODSPLATS;

    uTurnSpeed = ReadWindowsRegistryInt("TurnDelta", 3);

    if (!bNoSound)
        pAudioPlayer->Initialize();

    pMediaPlayer = new Media::MPlayer();
    pMediaPlayer->Initialize(window);

    dword_6BE364_game_settings_1 |= GAME_SETTINGS_4000;

    switch (uTurnSpeed)
    {
    case 0: // undefined turn option
        __debugbreak(); // really shouldn't use this mode
        uTurnSpeed = 64; //(unsigned int)uCPUSpeed < 199/*MHz*/ ? 128 : 64; // adjust turn speed to estimated fps
        break;

    case 1:             // 16x
        Log::Warning(L"x16 Turn Speed"); // really shouldn't use this mode
        uTurnSpeed = 128;
        break;

    case 2:             // 32x
        Log::Warning(L"x32 Turn Speed"); // really shouldn't use this mode
        uTurnSpeed = 64;
        break;

    case 3:             // smooth
        uTurnSpeed = 0;
        break;
    }

    return true;
}

//----- (00465D0B) --------------------------------------------------------
void SecondaryInitialization()
{
    pMouse->Initialize(window);

    pItemsTable = new ItemsTable;
    pItemsTable->Initialize();

    //pBitmaps_LOD->can_load_hardware_sprites = 1;
    //pBitmaps_LOD->SetupPalettes(pRenderer->uTargetRBits, pRenderer->uTargetGBits, pRenderer->uTargetBBits);
    pBitmaps_LOD->SetupPalettes(5, 6, 5);
    //pIcons_LOD->SetupPalettes(pRenderer->uTargetRBits, pRenderer->uTargetGBits, pRenderer->uTargetBBits);
    pIcons_LOD->SetupPalettes(5, 6, 5);
    //pPaletteManager->SetColorChannelInfo(pRenderer->uTargetRBits, pRenderer->uTargetGBits, pRenderer->uTargetBBits);
    pPaletteManager->SetColorChannelInfo(5, 6, 5);

    pPaletteManager->SetMistColor(128, 128, 128);
    pPaletteManager->RecalculateAll();
    //pSprites_LOD->can_load_hardware_sprites = 1;
    pObjectList->InitializeSprites();
    pOverlayList->InitializeSprites();

    if (!bNoSound)
        pSoundList->Initialize();


    for (uint i = 0; i < 4; ++i)
    {
        static const char *pUIAnimNames[4] =
        {
            "glow03", "glow05",
            "torchA", "wizeyeA"
        };
        static unsigned short _4E98D0[4][4] =
        {
            { 479, 0, 329, 0 },
            { 585, 0, 332, 0 },
            { 468, 0, 0, 0 },
            { 606, 0, 0, 0 }
        };

        pUIAnims[i]->uIconID = pIconsFrameTable->FindIcon(pUIAnimNames[i]);
        pIconsFrameTable->InitializeAnimation(pUIAnims[i]->uIconID);

        pUIAnims[i]->uAnimLength = 0;
        pUIAnims[i]->uAnimTime = 0;
        pUIAnims[i]->x = _4E98D0[i][0];
        pUIAnims[i]->y = _4E98D0[i][2];
    }

    for (unsigned int i = 0; i < pObjectList->uNumObjects; ++i)
    {
        pObjectList->pObjects[i].uParticleTrailColor = pObjectList->pObjects[i].uParticleTrailColorB |
            ((unsigned int)pObjectList->pObjects[i].uParticleTrailColorG << 8) |
            ((unsigned int)pObjectList->pObjects[i].uParticleTrailColorR << 16);
    }

    MainMenuUI_Create();
    pEngine->pStru6Instance->LoadAnimations();

    for (uint i = 0; i < 7; ++i)
    {
        char container_name[64];
        sprintf(container_name, "HDWTR%03u", i);
        pRenderer->pHDWaterBitmapIDs[i] = pBitmaps_LOD->LoadTexture(container_name);
    }

    pNPCStats = new NPCStats;
    memset(pNPCStats->pNPCData, 0, 0x94BCu);
    pNPCStats->Initialize();

    Initialize_GlobalEVT();
    pBitmaps_LOD->_inlined_sub0();
    pSprites_LOD->_inlined_sub0();
    pPaletteManager->LockAll();

    _mkdir("Saves");
    for (uint i = 0; i < 5; ++i)
        for (uint j = 0; j < 6; ++j)
        {
        sprintf(pTmpBuf.data(), "data\\lloyd%d%d.pcx", i, j);
        remove(pTmpBuf.data());
        }

    Initialize_GamesLOD_NewLOD();
    _576E2C_current_minimap_zoom = 512;
    dword_576E28 = 9;
}

int max_flight_height = 4000;    //maximum altitude
bool use_MMT = false;
bool use_music_folder = true;
bool for_refactoring = false;

//----- (00462C94) --------------------------------------------------------
bool MM_Main(const wchar_t *pCmdLine)
{
    IntegrityTest();

    lua = new LuaVM;
    lua->Initialize();

    bool bNoMargareth = false;
    if (pCmdLine && *pCmdLine)
    {
        //if (wcsstr(pCmdLine, L"-usedefs"))
        //  bDebugResouces = 1;
        if (wcsstr(pCmdLine, L"-window"))
            dword_6BE368_debug_settings_2 |= DEBUG_SETTINGS_RUN_IN_WIDOW;

        if (wcsstr(pCmdLine, L"-nointro"))
            bNoIntro = true;//dword_6BE364_game_settings_1 |= 4;
        if (wcsstr(pCmdLine, L"-nologo"))
            bNoLogo = true;//dword_6BE364_game_settings_1 |= 8;
        if (wcsstr(pCmdLine, L"-nosound"))
            bNoSound = true; //dword_6BE364_game_settings_1 |= 0x10;

        bWalkSound = ReadWindowsRegistryInt("WalkSound", 1) != 0;
        if (wcsstr(pCmdLine, L"-nowalksound"))
            bWalkSound = false;//dword_6BE364_game_settings_1 |= 0x20;
        if (wcsstr(pCmdLine, L"-novideo"))
        {
            dword_6BE364_game_settings_1 |= GAME_SETTINGS_NO_HOUSE_ANIM;
            bNoVideo = true;
        }
        if (wcsstr(pCmdLine, L"-nocd"))
            bNoCD = true;
        if (wcsstr(pCmdLine, L"-nomarg"))
            bNoMargareth = true;
    }

    //_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_ALWAYS_DF );//Ritor1: for memory test

    if (!MM7_Initialize(640, 480))
    {
        Log::Warning(L"MM init: failed");
        pEngine->Deinitialize();
        return 1;
    }

    pEventTimer->Pause();

    SetUserInterface(PartyAlignment_Neutral, false);

    ShowLogoVideo();
    //ShowIntroVideo_and_LoadingScreen();
    WriteWindowsRegistryInt("Ran once", 1);
    dword_6BE364_game_settings_1 |= GAME_SETTINGS_4000;
    SecondaryInitialization();
    //pRenderer->SetRasterClipRect(0, 0, window->GetWidth() - 1, window->GetHeight() - 1);
    FinalInitialization();

    //Ritor1: include
    if (use_MMT)
        MMT_MainMenu_Loop();

    Log::Warning(L"MM: entering main loop");
    while (1)
    {
        //MainMenuWindow* main_menu_window = MainMenuWindow::Create();
        //window->AddControl(main_menu_window);
        MainMenu_Loop();
        uGameState = GAME_STATE_PLAYING;
        while (1)
        {
            if (uGameState == GAME_FINISHED || GetCurrentMenuID() == MENU_EXIT_GAME)
            {
                pEngine->Deinitialize();
                return true;
            }

            if (GetCurrentMenuID() == MENU_NEWGAME)
            {
                if (use_music_folder)
                    alSourceStop(mSourceID);
                else
                {
                    if (pAudioPlayer->hAILRedbook)
                        AIL_redbook_stop(pAudioPlayer->hAILRedbook);
                }
                pParty->Reset();
                pOtherOverlayList->Reset();
                strcpy(pCurrentMapName, pStartingMapName);
                pParty->CreateDefaultParty(0);
                PlayerCreationUI_Initialize();
                if (PlayerCreationUI_Loop())
                {
                    DeleteCCharFont();
                    break;
                }
                DeleteCCharFont();
                bFlashQuestBook = true;
                pMediaPlayer->PlayFullscreenMovie(MOVIE_Emerald, true);
                SaveNewGame();
                if (bNoMargareth)
                    _449B7E_toggle_bit(pParty->_quest_bits, PARTY_QUEST_EMERALD_MARGARETH_OFF, 1);
                Game_Loop();
                if (uGameState == GAME_STATE_NEWGAME_OUT_GAMEMENU)
                {
                    SetCurrentMenuID(MENU_NEWGAME);
                    uGameState = GAME_STATE_PLAYING;
                    continue;
                }
                else if (uGameState == GAME_STATE_GAME_QUITTING_TO_MAIN_MENU)
                    break;
                assert(false && "Invalid game state");
            }
            if (GetCurrentMenuID() == MENU_CREDITS)
            {
                if (use_music_folder)
                    alSourceStop(mSourceID);
                else
                {
                    if (pAudioPlayer->hAILRedbook)
                        AIL_redbook_stop(pAudioPlayer->hAILRedbook);
                }
                MainMenuUI_Credits_Loop();
                break;
            }
            if (GetCurrentMenuID() == MENU_5 || GetCurrentMenuID() == MENU_LoadingProcInMainMenu)
            {
                uGameState = GAME_STATE_PLAYING;
                Game_Loop();
            }
            else
            {
                if (GetCurrentMenuID() == MENU_DebugBLVLevel)
                {
                    pMouse->ChangeActivation(0);
                    pParty->Reset();
                    pParty->CreateDefaultParty(1);

                    __debugbreak();
                    /*extern void CreateDefaultBLVLevel();
                    CreateDefaultBLVLevel();

                    OPENFILENAMEA ofn;
                    if ( !GetOpenFileNameA((LPOPENFILENAMEA)&ofn) )
                    {
                    pMouse->ChangeActivation(1);
                    break;
                    }
                    _chdir("..\\");
                    strcpy(pCurrentMapName, ofn.lpstrFileTitle);*/
                    pMouse->ChangeActivation(1);
                    Game_Loop();
                }
            }
            if (uGameState == GAME_STATE_LOADING_GAME)
            {
                SetCurrentMenuID(MENU_5);
                uGameState = GAME_STATE_PLAYING;
                continue;
            }
            if (uGameState == GAME_STATE_NEWGAME_OUT_GAMEMENU)
            {
                SetCurrentMenuID(MENU_NEWGAME);
                uGameState = GAME_STATE_PLAYING;
                continue;
            }
            if (uGameState == GAME_STATE_GAME_QUITTING_TO_MAIN_MENU)// from the loaded game
            {
                pAudioPlayer->StopChannels(-1, -1);
                uGameState = GAME_STATE_PLAYING;
                break;
            }
        }
        if (!bNoSound)
        {
            if (use_music_folder)
            {
                PlayAudio(L"Music\\14.mp3");
                alSourcef(mSourceID, AL_GAIN, pSoundVolumeLevels[uMusicVolimeMultiplier]);
            }
            else if (pAudioPlayer->hAILRedbook)
            {
                pAudioPlayer->SetMusicVolume(pSoundVolumeLevels[uMusicVolimeMultiplier] * 64.0f);
                AIL_redbook_stop(pAudioPlayer->hAILRedbook);
                unsigned int startms, end_ms;
                AIL_redbook_track_info(pAudioPlayer->hAILRedbook, 14, &startms, &end_ms);
                AIL_redbook_play(pAudioPlayer->hAILRedbook, startms + 1, end_ms);
            }
        }
    }
    //lua_close(L);
    pEngine->Deinitialize();
    return 1;
}



//----- (00466082) --------------------------------------------------------
void MM6_Initialize(const wchar_t *pIniFilename)
{
    size_t v2; // eax@31
    size_t v3; // ebx@32
    size_t v4; // edi@36
    char pDefaultGroundTexture[16]; // [sp+FCh] [bp-8Ch]@32
    unsigned int v9; // [sp+184h] [bp-4h]@28

    //_getcwd(v5, 120);
    //sprintfex(pIniFilename, "%s\\mm6.ini", v5);
    viewparams = new ViewingParams;
    game_viewport_x = viewparams->uScreen_topL_X = GetPrivateProfileIntW(L"screen", L"vx1", 8, pIniFilename);
    game_viewport_y = viewparams->uScreen_topL_Y = GetPrivateProfileIntW(L"screen", L"vy1", 8, pIniFilename);
    game_viewport_z = viewparams->uScreen_BttmR_X = GetPrivateProfileIntW(L"screen", L"vx2", 468, pIniFilename);
    game_viewport_w = viewparams->uScreen_BttmR_Y = GetPrivateProfileIntW(L"screen", L"vy2", 351, pIniFilename);
    game_viewport_width = game_viewport_z - game_viewport_x;
    game_viewport_height = game_viewport_w - game_viewport_y + 1;


    pAudioPlayer = new AudioPlayer;
    pAudioPlayer->uMixerChannels = GetPrivateProfileIntW(L"settings", L"mixerchannels", 16, pIniFilename);
    if (pAudioPlayer->uMixerChannels > 16)
        pAudioPlayer->uMixerChannels = 16;


    if (GetPrivateProfileIntW(L"debug", L"nomonster", 0, pIniFilename))
        dword_6BE368_debug_settings_2 |= DEBUG_SETTINGS_NO_ACTORS;
    if (ReadWindowsRegistryInt("startinwindow", 0))
        dword_6BE368_debug_settings_2 |= DEBUG_SETTINGS_RUN_IN_WIDOW;
    if (GetPrivateProfileIntW(L"debug", L"showFR", 0, pIniFilename))
        dword_6BE368_debug_settings_2 |= DEBUG_SETTINGS_0002_SHOW_FR;
    if (GetPrivateProfileIntW(L"debug", L"nodamage", 0, pIniFilename))
        dword_6BE368_debug_settings_2 |= DEBUG_SETTINGS_NO_DAMAGE;
    if (GetPrivateProfileIntW(L"debug", L"nodecoration", 0, pIniFilename))
        dword_6BE368_debug_settings_2 |= DEBUG_SETTINGS_NO_DECORATIONS;

    wchar_t pStartingMapNameW[1024];
    GetPrivateProfileStringW(L"file", L"startmap", L"out01.odm", pStartingMapNameW, 0x20u, pIniFilename);
    sprintf(pStartingMapName, "%S", pStartingMapNameW);

    v9 = 0;
    if (strlen(pStartingMapName))
    {
        do
        {
            if (pStartingMapName[v9] == ' ')
                pStartingMapName[v9] = 0;
            ++v9;
            v2 = strlen(pStartingMapName);
        } while (v9 < v2);
    }

    pODMRenderParams = new ODMRenderParams;
    pODMRenderParams->outdoor_no_mist = GetPrivateProfileIntW(L"debug", L"noMist", 0, pIniFilename);
    pODMRenderParams->bNoSky = GetPrivateProfileIntW(L"outdoor", L"nosky", 0, pIniFilename);
    pODMRenderParams->bDoNotRenderDecorations = GetPrivateProfileIntW(L"render", L"nodecorations", 0, pIniFilename);
    pODMRenderParams->outdoor_no_wavy_water = GetPrivateProfileIntW(L"outdoor", L"nowavywater", 0, pIniFilename);
    outdoor_grid_band_1 = GetPrivateProfileIntW(L"outdoor", L"gridband1", 10, pIniFilename);
    outdoor_grid_band_2 = GetPrivateProfileIntW(L"outdoor", L"gridband2", 15, pIniFilename);
    outdoor_grid_band_3 = GetPrivateProfileIntW(L"outdoor", L"gridband3", 25, pIniFilename);
    pODMRenderParams->terrain_gamma = GetPrivateProfileIntW(L"outdoor", L"ter_gamma", 0, pIniFilename);
    pODMRenderParams->building_gamme = GetPrivateProfileIntW(L"outdoor", L"bld_gamma", 0, pIniFilename);
    pODMRenderParams->shading_dist_shade = GetPrivateProfileIntW(L"shading", L"dist_shade", 2048, pIniFilename);
    pODMRenderParams->shading_dist_shademist = GetPrivateProfileIntW(L"shading", L"dist_shademist", 4096, pIniFilename);

    pODMRenderParams->shading_dist_mist = GetPrivateProfileIntW(L"shading", L"dist_mist", 0x2000, pIniFilename);//drawing dist 0x2000

    wchar_t pDefaultSkyTextureW[1024];
    GetPrivateProfileStringW(L"textures", L"sky", L"plansky1", pDefaultSkyTextureW, 0x10u, pIniFilename);
    sprintf(pDefaultSkyTexture.data(), "%S", pDefaultSkyTextureW);

    wchar_t pDefaultGroundTextureW[1024];
    GetPrivateProfileStringW(L"textures", L"default", L"dirt", pDefaultGroundTextureW, 0x10u, pIniFilename);
    sprintf(pDefaultGroundTexture, "%S", pDefaultGroundTextureW);

    wchar_t pFloat[1024];
    GetPrivateProfileStringW(L"debug", L"recmod1", L"1.0", pFloat, 0x10u, pIniFilename);
    swscanf(pFloat, L"%f", &flt_6BE3A4_debug_recmod1);

    GetPrivateProfileStringW(L"debug", L"recmod2", L"1.0", pFloat, 0x10u, pIniFilename);
    swscanf(pFloat, L"%f", &flt_6BE3A8_debug_recmod2);

    flt_6BE3AC_debug_recmod1_x_1_6 = flt_6BE3A4_debug_recmod1 * 1.666666666666667;

    v3 = 0;
    if (strlen(pDefaultSkyTexture.data()))
    {
        do
        {
            if (pDefaultSkyTexture[v3] == ' ')
                pDefaultSkyTexture[v3] = 0;
            ++v3;
        } while (v3 < strlen(pDefaultSkyTexture.data()));
    }
    v4 = 0;
    if (strlen(pDefaultGroundTexture))
    {
        do
        {
            if (pDefaultGroundTexture[v4] == ' ')
                pDefaultGroundTexture[v4] = 0;
            ++v4;
        } while (v4 < strlen(pDefaultGroundTexture));
    }

    MM7Initialization();
}

//----- (004666D5) --------------------------------------------------------
void MM7Initialization()
{
    if (uCurrentlyLoadedLevelType == LEVEL_Outdoor)
    {
        /*if (byte_6BE388_graphicsmode == 0)
        {
        outdoor_grid_band_1 = 10;
        outdoor_grid_band_2 = 15;
        outdoor_grid_band_3 = 20;
        pODMRenderParams->shading_dist_mist = 8192;
        pODMRenderParams->bNoSky = false;
        LOBYTE(viewparams->field_20) = 0;
        }*/
        pODMRenderParams->shading_dist_shade = 2048;
        pODMRenderParams->terrain_gamma = 0;
        pODMRenderParams->building_gamme = 0;
        pODMRenderParams->shading_dist_shademist = 4096;
        pODMRenderParams->outdoor_no_wavy_water = 0;
        //_47F4D3_initialize_terrain_bezier_stuff(outdoor_grid_band_1, outdoor_grid_band_2, outdoor_grid_band_3);
        {
            pODMRenderParams->outdoor_grid_band_3 = outdoor_grid_band_3;
            pODMRenderParams->uPickDepth = outdoor_grid_band_3 * 512;
        }
    }
    else
        LOBYTE(viewparams->field_20) = 0;
    pParty->uFlags |= 2;
    viewparams->uSomeY = viewparams->uScreen_topL_Y;
    viewparams->uSomeX = viewparams->uScreen_topL_X;
    viewparams->uSomeZ = viewparams->uScreen_BttmR_X;
    viewparams->uSomeW = viewparams->uScreen_BttmR_Y;

    pViewport->SetScreen(viewparams->uScreen_topL_X, viewparams->uScreen_topL_Y, viewparams->uScreen_BttmR_X, viewparams->uScreen_BttmR_Y);
    if (uCurrentlyLoadedLevelType == LEVEL_Outdoor)
        pODMRenderParams->Initialize();
}

//----- (004610AA) --------------------------------------------------------
void __fastcall PrepareToLoadODM(unsigned int bLoading, ODMRenderParams *a2)
{
    pGameLoadingUI_ProgressBar->Reset(27);
    pSoundList->_4A9D79(0);
    uCurrentlyLoadedLevelType = LEVEL_Outdoor;
    ODM_LoadAndInitialize(pCurrentMapName, a2);
    if (!bLoading)
        TeleportToStartingPoint(uLevel_StartingPointType);
    viewparams->_443365();
    PlayLevelMusic();
}
// 6BE35C: using guessed type int uLevel_StartingPointType;



//----- (004BF91E) --------------------------------------------------------
unsigned int GameOverMenu(void *ecx0)
{
    const char *v1; // eax@2
    unsigned int result; // eax@3
    const char *v6; // eax@10
    const char *v7; // edx@10
    const char *v8; // ecx@12
    const char *v9; // eax@14
    unsigned int v10; // eax@25
    GUIWindow pWindow; // [sp+34h] [bp-9Ch]@1
    unsigned int v14; // [sp+A4h] [bp-2Ch]@5
    void *v15; // [sp+A8h] [bp-28h]@1
    const char *pInString; // [sp+ACh] [bp-24h]@5
    unsigned int v17; // [sp+B0h] [bp-20h]@5
    unsigned int v18; // [sp+B4h] [bp-1Ch]@5
    unsigned int v19; // [sp+B8h] [bp-18h]@5
    int v20; // [sp+BCh] [bp-14h]@7
    GUIFont *pFont; // [sp+C4h] [bp-Ch]@1
    unsigned __int64 v23; // [sp+C8h] [bp-8h]@5
    MSG msg;

    v15 = ecx0;

    RGBTexture _this; // [sp+Ch] [bp-C4h]@1
    //RGBTexture::RGBTexture(&this);

    dword_6BE364_game_settings_1 &= ~GAME_SETTINGS_4000;
    bGameoverLoop = 1;
    pMediaPlayer->bStopBeforeSchedule = 0;
    pAudioPlayer->StopChannels(-1, -1);
    pRenderer->BeginScene();
    pRenderer->ClearBlack();
    pRenderer->EndScene();
    pRenderer->Present();
    //pMediaPlayer->pResetflag = 0;
    _449B57_test_bit(pParty->_quest_bits, 99);
    _this.Load("winbg.pcx", 2);
    pRenderer->BeginScene();
    pRenderer->DrawTextureRGB(0, 0, &_this);
    pRenderer->EndScene();
    free(_this.pPixels);
    _this.pPixels = 0;
    window_SpeakInHouse = GUIWindow::Create(0, 0, window->GetWidth(), window->GetHeight(), WINDOW_MainMenu, 0, 0);
    pWindow.uFrameX = 75;
    pWindow.uFrameY = 60;
    pWindow.uFrameWidth = 469;
    pWindow.uFrameHeight = 338;
    pWindow.uFrameZ = 543;
    pWindow.uFrameW = 397;
    pFont = LoadFont("endgame.fnt", "FONTPAL", NULL);
    if (pParty->IsPartyGood())
        v1 = pGlobalTXT_LocalizationStrings[675];//"Splendid job!  With the activation of the Gate, a thousand worlds lie at your feet.  Perhaps on one of them you will find the Ancients themselves, and return with the fruits their great civilization has to offer your world and your kingdom."
    else
    {
        result = pParty->IsPartyEvil();
        if (!(short)result)
            return result;
        v1 = pGlobalTXT_LocalizationStrings[676];//"Brilliant!  The completion of the Heavenly Forge has provided enough Ancient weapons to crush all resistance to your plans.  Soon the world will bow to your every whim!  Still, you can't help but wonder what was beyond the Gate the other side was trying so hard to build."
    }
    pInString = v1;
    v23 = pParty->uTimePlayed - 138240;
    v19 = (unsigned int)((signed __int64)((double)(pParty->uTimePlayed - 138240) * 0.234375) / 60 / 60) / 24;
    v14 = (unsigned int)((signed __int64)((double)(pParty->uTimePlayed - 138240) * 0.234375) / 60 / 60) / 24 / 0x1C / 0xC;
    v18 = (unsigned int)((signed __int64)((double)(pParty->uTimePlayed - 138240) * 0.234375) / 60 / 60) / 24 / 0x1C % 0xC;
    v17 = v19 % 0x1C;
    if (!v19)
        v19 = 1;
    pRenderer->BeginScene();
    pWindow.DrawTitleText(pFont, 1, 0x23, 1, pGlobalTXT_LocalizationStrings[9], 3);//Congratulations!
    v23 = 0i64;
    v20 = 0;
    for (uint i = 0; i < 4; i++)
    {
        sprintf(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[129], pParty->pPlayers[i].pName, pParty->pPlayers[i].GetBaseLevel(), pClassNames[pParty->pPlayers[i].classType]);//%s the Level %u %s
        pWindow.DrawTitleText(pFont, 1, i * (LOBYTE(pFont->uFontHeight) - 2) + LOBYTE(pFont->uFontHeight) + 46, 1, pTmpBuf.data(), 3);
        v23 += pParty->pPlayers[i].uExperience;//__PAIR__(*(int *)(i - 4), *(int *)(i - 8));
    }
    v23 = (signed __int64)v23 / v19;
    v6 = FitTextInAWindow(pInString, pFont, &pWindow, 0xC, 0);
    pWindow.DrawTitleText(pFont, 1, 5 * (LOBYTE(pFont->uFontHeight) + 11), 1, v6, 0);
    strcpy(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[37]);//Total Time:

    v7 = pGlobalTXT_LocalizationStrings[56];
    if (v17 != 1)
        v7 = pGlobalTXT_LocalizationStrings[57];

    v8 = pGlobalTXT_LocalizationStrings[146];//Month
    if (v18 != 1)
        v8 = pGlobalTXT_LocalizationStrings[148];//Months

    v9 = pGlobalTXT_LocalizationStrings[245];
    if (v14 != 1)
        v9 = pGlobalTXT_LocalizationStrings[132];

    sprintf(pTmpBuf2.data(), " %lu %s, %lu %s, %lu %s ", v14, v9, v18, v8, v17, v7);
    strcat(pTmpBuf.data(), pTmpBuf2.data());
    pWindow.DrawTitleText(pFont, 1, pWindow.uFrameHeight - 2 * LOBYTE(pFont->uFontHeight) - 5, 1, pTmpBuf.data(), 3);
    sprintf(pTmpBuf.data(), pGlobalTXT_LocalizationStrings[94], v23);
    pWindow.DrawTitleText(pFont, 1, pWindow.uFrameHeight, 1, pTmpBuf.data(), 3);
    dword_6BE364_game_settings_1 |= GAME_SETTINGS_4000;
    pRenderer->EndScene();
    pRenderer->Present();
    //if ( pRenderer->pRenderD3D )
    pRenderer->pBeforePresentFunction();
    pRenderer->SaveWinnersCertificate("MM7_Win.Pcx");
    free(pFont);
    window_SpeakInHouse->Release();
    window_SpeakInHouse = 0;
    if (v15 == (void *)2)
        result = pMessageQueue_50CBD0->uNumMessages;
    else
    {
        LODWORD(v23) = GetTickCount() + 5000;
        while ((unsigned int)v23 > GetTickCount())
            ;
        while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
        {
            if (msg.message == WM_QUIT)
                Engine_DeinitializeAndTerminate(0);
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        if (pMessageQueue_50CBD0->uNumMessages)
        {
            LOBYTE(v10) = pMessageQueue_50CBD0->pMessages[0].field_8 != 0;
            pMessageQueue_50CBD0->uNumMessages = v10;
        }
        pKeyActionMap->ResetKeys();
        pKeyActionMap->uLastKeyPressed = 0;
        do
        {
            while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
            {
                if (msg.message == WM_QUIT)
                    Engine_DeinitializeAndTerminate(0);
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        } while (!pKeyActionMap->uLastKeyPressed);
        result = pMessageQueue_50CBD0->uNumMessages;
        if (pMessageQueue_50CBD0->uNumMessages)
        {
            result = pMessageQueue_50CBD0->pMessages[0].field_8 != 0;
            pMessageQueue_50CBD0->uNumMessages = pMessageQueue_50CBD0->pMessages[0].field_8 != 0;
        }
    }
    if (v15)
    {
        /*if ( (signed int)result < 40 )
        {
        pMessageQueue_50CBD0->pMessages[result].eType = UIMSG_Quit;
        }*/
        pMessageQueue_50CBD0->AddGUIMessage(UIMSG_Quit, 1, 0);
    }
    else
    {
        pMessageQueue_50CBD0->AddGUIMessage(UIMSG_ShowFinalWindow, 1, 0);
        /*if ( (signed int)result < 40 )
        {
        pMessageQueue_50CBD0->pMessages[result].eType = UIMSG_C5;
        pMessageQueue_50CBD0->pMessages[pMessageQueue_50CBD0->uNumMessages].param = 1;
        result = 3 * pMessageQueue_50CBD0->uNumMessages + 3;
        *(&pMessageQueue_50CBD0->uNumMessages + result) = 0;
        ++pMessageQueue_50CBD0->uNumMessages;
        }*/
    }
    bGameoverLoop = 0;
    return result;
}

//----- (00464479) --------------------------------------------------------
void ResetCursor_Palettes_LODs_Level_Audio_SFT_Windows()
{
    int v0; // esi@9

    if (pMouse)
        pMouse->SetCursorBitmap("MICON1");

    pPaletteManager->ResetNonLocked();
    pBitmaps_LOD->ReleaseAll2();
    pSprites_LOD->DeleteSomeOtherSprites();
    pIcons_LOD->ReleaseAll2();

    if (uCurrentlyLoadedLevelType == LEVEL_Indoor)
        pIndoor->Release();
    else if (uCurrentlyLoadedLevelType == LEVEL_Outdoor)
        pOutdoor->Release();

    pAudioPlayer->StopChannels(-1, -1);
    pSoundList->_4A9D79(0);
    uCurrentlyLoadedLevelType = LEVEL_null;
    pSpriteFrameTable->ResetSomeSpriteFlags();
    v0 = uNumVisibleWindows;
    pParty->armageddon_timer = 0;
    while (v0 > 0)
        pWindowList[pVisibleWindowsIdxs[v0--] - 1].Release();
}

//----- (00461103) --------------------------------------------------------
void _461103_load_level_sub()
{
    int v4; // edx@8
    signed int v6; // esi@14
    signed int v8; // ecx@16
    int v12; // esi@25
    int v13; // eax@26
    __int16 v14; // ax@41
    signed int v17; // [sp+14h] [bp-48h]@3
    signed int v18; // [sp+14h] [bp-48h]@23
    int v19; // [sp+18h] [bp-44h]@1
    signed int v20; // [sp+18h] [bp-44h]@14
    int v21[16]; // [sp+1Ch] [bp-40h]@17

    GenerateItemsInChest();
    pGameLoadingUI_ProgressBar->Progress();
    pParty->uFlags |= 2;
    pParty->field_7B5_in_arena_quest = 0;
    dword_5C6DF8 = 1;
    pNPCStats->uNewlNPCBufPos = 0;
    v19 = pMapStats->GetMapInfo(pCurrentMapName);

    //v15 = 0;
    for (uint i = 0; i < uNumActors; ++i)
        //if ( (signed int)uNumActors > 0 )
    {
        //Actor* pActor = &pActors[i];
        //v2 = (char *)&pActors[0].uNPC_ID;
        //do
        //{
        //v3 = pActors[i].pMonsterInfo.uID;
        v17 = 0;
        if (pActors[i].pMonsterInfo.uID >= 115 && pActors[i].pMonsterInfo.uID <= 186
            || pActors[i].pMonsterInfo.uID >= 232 && pActors[i].pMonsterInfo.uID <= 249)
            v17 = 1;
        //v1 = 0;
        v4 = (pActors[i].pMonsterInfo.uID - 1) % 3;
        if (2 == v4)
        {
            if (pActors[i].sNPC_ID && pActors[i].sNPC_ID < 5000)
                continue;
        }
        else
        {
            if (v4 != 1)
            {
                if (v4 == 0 && pActors[i].sNPC_ID == 0)
                    pActors[i].sNPC_ID = 0;
                continue;
            }
        }
        if (pActors[i].sNPC_ID > 0 && pActors[i].sNPC_ID < 5000)
            continue;
        if (v17)
        {
            pNPCStats->InitializeAdditionalNPCs(&pNPCStats->pAdditionalNPC[pNPCStats->uNewlNPCBufPos], pActors[i].pMonsterInfo.uID, 0, v19);
            v14 = LOWORD(pNPCStats->uNewlNPCBufPos) + 5000;
            ++pNPCStats->uNewlNPCBufPos;
            pActors[i].sNPC_ID = v14;
            continue;
        }
        pActors[i].sNPC_ID = 0;
        //++v15;
        //v2 += 836;
        //}
        //while ( v15 < (signed int)uNumActors );
    }

    pGameLoadingUI_ProgressBar->Progress();

    //v5 = uNumActors;
    v6 = 0;
    v20 = 0;
    //v16 = v1;

    for (uint i = 0; i < uNumActors; ++i)
    {
        //v7 = (char *)&pActors[0].pMonsterInfo;
        //do
        //{
        for (v8 = 0; v8 < v6; ++v8)
        {
            if (v21[v8] == pActors[i].pMonsterInfo.uID - 1)
                break;
        }

        if (v8 == v6)
        {
            v21[v6++] = pActors[i].pMonsterInfo.uID - 1;
            v20 = v6;
            if (v6 == 16)
                break;
        }
        //++v16;
        //v7 += 836;
        //}
        //while ( v16 < (signed int)v5 );
    }

    pGameLoadingUI_ProgressBar->Progress();

    for (int _v0 = 0; _v0 < v6; ++_v0)
    {
        for (v18 = 4; v18; --v18)
            pSoundList->LoadSound(pMonsterList->pMonsters[v21[_v0]].pSoundSampleIDs[4 - v18], 0);
        v12 = 0;
        do
            v13 = pSoundList->LoadSound(v12++ + word_4EE088_sound_ids[pMonsterStats->pInfos[v21[_v0] + 1].uSpell1ID], 1);
        while (v13);
    }
    //v0 = pGameLoadingUI_ProgressBar;
    //v1 = 0;

    pGameLoadingUI_ProgressBar->Progress();

    if (dword_6BE368_debug_settings_2 & DEBUG_SETTINGS_NO_ACTORS)
        uNumActors = 0;
    if (dword_6BE368_debug_settings_2 & DEBUG_SETTINGS_NO_DECORATIONS)
        uNumLevelDecorations = 0;
    init_event_triggers();

    pGameLoadingUI_ProgressBar->Progress();

    pEngine->pIndoorCameraD3D->vPartyPos.x = 0;
    pEngine->pIndoorCameraD3D->vPartyPos.y = 0;
    pEngine->pIndoorCameraD3D->vPartyPos.z = 100;
    pEngine->pIndoorCameraD3D->sRotationX = 0;
    pEngine->pIndoorCameraD3D->sRotationY = 0;
    viewparams->bRedrawGameUI = true;
    uLevel_StartingPointType = MapStartPoint_Party;
    pSprites_LOD->_461397();
    pPaletteManager->LockTestAll();
    if (pParty->pPickedItem.uItemID != 0)
        pMouse->SetCursorBitmapFromItemID(pParty->pPickedItem.uItemID);
}

//----- (0042F3D6) --------------------------------------------------------
void InitializeTurnBasedAnimations(void *_this)
{
    for (unsigned int i = 0; i < pIconIDs_Turn.size(); ++i)
    {
        char icon_name[32];
        sprintf(icon_name, "turn%u", i);
        pIconIDs_Turn[i] = pIconsFrameTable->FindIcon(icon_name);
        pIconsFrameTable->InitializeAnimation(pIconIDs_Turn[i]);
    }

    uIconID_TurnStop = pIconsFrameTable->FindIcon("turnstop");
    uIconID_TurnHour = pIconsFrameTable->FindIcon("turnhour");
    uIconID_TurnStart = pIconsFrameTable->FindIcon("turnstart");
    uIconID_CharacterFrame = pIconsFrameTable->FindIcon("aframe1");
    uSpriteID_Spell11 = pSpriteFrameTable->FastFindSprite("spell11");

    pIconsFrameTable->InitializeAnimation(uIconID_TurnHour);
    pIconsFrameTable->InitializeAnimation(uIconID_TurnStop);
    pIconsFrameTable->InitializeAnimation(uIconID_TurnStart);
    pIconsFrameTable->InitializeAnimation(uIconID_CharacterFrame);
}

//----- (0046BDA8) --------------------------------------------------------
unsigned int  GetGravityStrength()
{
    int v0; // eax@1

    v0 = ~LOBYTE(pEngine->uFlags2) & 8;
    LOBYTE(v0) = v0 | 2;
    return (unsigned int)v0 >> 1;
}

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

//----- (0044861E) --------------------------------------------------------
void __fastcall sub_44861E_set_texture(unsigned int uFaceCog, const char *pFilename)
{
    unsigned int texture; // eax@2

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

            if (uCurrentlyLoadedLevelType == 1)
            {
                if ((signed int)pIndoor->uNumFaceExtras > 1)
                {
                    for (uint i = 1; i < (signed int)pIndoor->uNumFaceExtras; ++i)
                    {
                        if (pIndoor->pFaceExtras[i].sCogNumber == uFaceCog)
                        {
                            if (pIndoor->pFaces[pIndoor->pFaceExtras[i].field_C].uAttributes & FACE_TEXTURE_FRAME)
                            {
                                pIndoor->pFaces[pIndoor->pFaceExtras[i].field_C].uBitmapID = pTextureFrameTable->FindTextureByName(pFilename);
                                if (pIndoor->pFaces[pIndoor->pFaceExtras[i].field_C].uBitmapID)
                                {
                                    pTextureFrameTable->LoadAnimationSequenceAndPalettes(pIndoor->pFaces[pIndoor->pFaceExtras[i].field_C].uBitmapID);
                                }
                                else
                                {
                                    pIndoor->pFaces[pIndoor->pFaceExtras[i].field_C].uBitmapID = texture;
                                    pIndoor->pFaces[pIndoor->pFaceExtras[i].field_C].uAttributes &= 0xFFFFBFFF;
                                }
                            }
                            else
                            {
                                pIndoor->pFaces[pIndoor->pFaceExtras[i].field_C].uBitmapID = texture;
                            }
                        }
                    }
                }
                pParty->uFlags |= 2;
            }
            else
            {
                for (uint j = 0; j < (unsigned int)pOutdoor->uNumBModels; ++j)
                {
                    for (uint i = 0; i < pOutdoor->pBModels[j].uNumFaces; ++i)
                    {
                        if (pOutdoor->pBModels[j].pFaces[i].sCogNumber == uFaceCog)
                        {
                            if (pOutdoor->pBModels[j].pFaces[i].uAttributes & FACE_TEXTURE_FRAME)
                            {
                                pOutdoor->pBModels[j].pFaces[i].uTextureID = pTextureFrameTable->FindTextureByName(pFilename);
                                if (pOutdoor->pBModels[j].pFaces[i].uTextureID)
                                    pTextureFrameTable->LoadAnimationSequenceAndPalettes(pOutdoor->pBModels[j].pFaces[i].uTextureID);
                                else
                                {
                                    pOutdoor->pBModels[j].pFaces[i].uTextureID = texture;
                                    pOutdoor->pBModels[j].pFaces[i].uAttributes &= 0xFFFFBFFF;
                                }
                            }
                            else
                                pOutdoor->pBModels[j].pFaces[i].uTextureID = texture;
                        }
                    }
                }
            }
            pParty->uFlags |= 2;
        }
    }
}

//----- (0044892E) --------------------------------------------------------
void __fastcall sub_44892E_set_faces_bit(int sCogNumber, int bit, int on)
{
    if (sCogNumber)
    {
        if (uCurrentlyLoadedLevelType == 1)
        {
            for (uint i = 1; i < (unsigned int)pIndoor->uNumFaceExtras; ++i)
            {
                if (pIndoor->pFaceExtras[i].sCogNumber == sCogNumber)
                {
                    if (on)
                        pIndoor->pFaces[pIndoor->pFaceExtras[i].field_C].uAttributes |= bit;
                    else
                        pIndoor->pFaces[pIndoor->pFaceExtras[i].field_C].uAttributes &= ~bit;
                }
            }
            pParty->uFlags |= 2;
        }
        else
        {
            for (uint j = 0; j < (unsigned int)pOutdoor->uNumBModels; ++j)
            {
                for (uint i = 0; i < (unsigned int)pOutdoor->pBModels[j].uNumFaces; ++i)
                {
                    if (pOutdoor->pBModels[j].pFaces[i].sCogNumber == sCogNumber)
                    {
                        if (on)
                            pOutdoor->pBModels[j].pFaces[i].uAttributes |= bit;
                        else
                            pOutdoor->pBModels[j].pFaces[i].uAttributes &= ~bit;
                    }
                }
            }
        }
        pParty->uFlags |= 2;
    }
}

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

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

            pParty->uFlags |= 2;
        }
    }
}

//----- (004356FF) --------------------------------------------------------
void back_to_game()
{
    dword_507BF0_is_there_popup_onscreen = 0;
    dword_4E455C = 1;

    extern int no_rightlick_in_inventory;
    no_rightlick_in_inventory = false;

    if (pGUIWindow_ScrollWindow)
        free_book_subwindow();
    if (!current_screen_type && !pGUIWindow_Settings)
        pEventTimer->Resume();
    viewparams->bRedrawGameUI = 1;
}

//----- (00494035) --------------------------------------------------------
void _494035_timed_effects__water_walking_damage__etc()
{
    signed __int64 v0; // qax@1
    unsigned int v4; // edi@1
    //  signed int v12; // edi@29
    int v24; // ecx@60
    int v26; // ecx@64
    int v28; // ecx@68
    int v30; // ecx@72
    int v32; // ecx@76
    int v34; // ecx@80
    int v36; // ecx@84
    int v38; // ecx@88
    int v40; // ecx@92
    int v42; // ecx@96
    bool v43; // ebx@102
    bool v46; // edi@111
    //  unsigned int v56; // [sp-8h] [bp-38h]@55
    //  int v59; // [sp-4h] [bp-34h]@55
    //  unsigned int v61; // [sp+14h] [bp-1Ch]@1
    signed int a2a; // [sp+18h] [bp-18h]@47
    signed int old_day; // [sp+1Ch] [bp-14h]@47
    signed int old_hour;

    old_day = pParty->uDaysPlayed;
    old_hour = pParty->uCurrentHour;
    //auto prev_time = pEventTimer->uTimeElapsed;
    pParty->uTimePlayed += pEventTimer->uTimeElapsed;
    v0 = ((signed __int64)(pParty->uTimePlayed * 0.234375) / 60) / 60i64;
    v4 = (unsigned int)(((unsigned int)v0 / 24) / 7) >> 2;
    pParty->uCurrentTimeSecond = (signed __int64)((double)(signed __int64)pParty->uTimePlayed * 0.234375) % 60;
    pParty->uCurrentMinute = ((signed __int64)(pParty->uTimePlayed * 0.234375) / 60) % 60;
    pParty->uCurrentHour = v0 % 24;
    pParty->uCurrentMonthWeek = ((unsigned int)v0 / 24) / 7 & 3;
    pParty->uDaysPlayed = (unsigned int)((unsigned int)v0 / 24) % 28;
    pParty->uCurrentMonth = v4 % 12;
    pParty->uCurrentYear = v4 / 0xC + game_starting_year;
    if (pParty->uCurrentHour >= 3 && (old_hour < 3 || pParty->uDaysPlayed > old_day)) // new day dawns
    {
        pParty->pHirelings[0].bHasUsedTheAbility = false;
        pParty->pHirelings[1].bHasUsedTheAbility = false;

        for (uint i = 0; i < pNPCStats->uNumNewNPCs; ++i)
            pNPCStats->pNewNPCData[i].bHasUsedTheAbility = false;

        ++pParty->days_played_without_rest;
        if (pParty->days_played_without_rest > 1)
        {
            for (uint i = 0; i < 4; ++i)
                pParty->pPlayers[i].SetCondWeakWithBlockCheck(0);

            if (pParty->uNumFoodRations)
                Party::TakeFood(1);
            else
                for (uint i = 0; i < 4; ++i)
                    pParty->pPlayers[i].sHealth = pParty->pPlayers[i].sHealth / (pParty->days_played_without_rest + 1) + 1;

            if (pParty->days_played_without_rest > 3)
                for (uint i = 0; i < 4; ++i)
                {
                pParty->pPlayers[i].Zero();
                if (!pParty->pPlayers[i].IsPertified() && !pParty->pPlayers[i].IsEradicated()
                    && !pParty->pPlayers[i].IsDead())
                {
                    if (rand() % 100 < 5 * pParty->days_played_without_rest)
                        pParty->pPlayers[i].SetCondDeadWithBlockCheck(0);
                    if (rand() % 100 < 10 * pParty->days_played_without_rest)
                        pParty->pPlayers[i].SetCondInsaneWithBlockCheck(0);
                }
                }
        }
        if (uCurrentlyLoadedLevelType == LEVEL_Outdoor)
            pOutdoor->SetFog();

        for (uint i = 0; i < 4; ++i)
            pParty->pPlayers[i].uNumDivineInterventionCastsThisDay = 0;
    }

    if (pParty->uFlags & 4 && pParty->field_6FC < (signed __int64)pParty->uTimePlayed)//water damage
    {
        pParty->field_6FC = (signed __int64)pParty->uTimePlayed + 128;
        viewparams->bRedrawGameUI = true;
        for (uint pl = 1; pl <= 4; ++pl)
        {
            if (pPlayers[pl]->WearsItem(ITEM_RELIC_HARECS_LEATHER, EQUIP_ARMOUR)
                || pPlayers[pl]->HasEnchantedItemEquipped(71)
                || pPlayers[pl]->pPlayerBuffs[PLAYER_BUFF_WATER_WALK].uExpireTime > 0)
                pPlayers[pl]->PlayEmotion(CHARACTER_EXPRESSION_37, 0);
            else
            {
                if (!pPlayers[pl]->HasUnderwaterSuitEquipped())
                {
                    pPlayers[pl]->ReceiveDamage((signed __int64)pPlayers[pl]->GetMaxHealth() * 0.1, DMGT_FIRE);
                    if (pParty->uFlags & 4)
                    {
                        strcpy(GameUI_Footer_TimedString.data(), pGlobalTXT_LocalizationStrings[660]);// Вы тонете!
                        GameUI_Footer_TimeLeft = 128;
                    }
                }
                else
                    pPlayers[pl]->PlayEmotion(CHARACTER_EXPRESSION_37, 0);
            }
        }
    }
    if (pParty->uFlags & 0x200 && pParty->field_6FC < (signed __int64)pParty->uTimePlayed) //lava damage
    {
        viewparams->bRedrawGameUI = true;
        pParty->field_6FC = (signed __int64)pParty->uTimePlayed + 128;

        for (uint pl = 1; pl <= 4; pl++)
        {
            pPlayers[pl]->ReceiveDamage((signed __int64)pPlayers[pl]->GetMaxHealth() * 0.1, DMGT_FIRE);
            if (pParty->uFlags & 0x200)
            {
                strcpy(GameUI_Footer_TimedString.data(), pGlobalTXT_LocalizationStrings[661]); //Вы горите!
                GameUI_Footer_TimeLeft = 128;
            }
        }
    }
    _493938_regenerate();
    uint party_condition_flag = 4;
    a2a = pEventTimer->uTimeElapsed;
    if (pParty->uFlags2 & PARTY_FLAGS_2_RUNNING)//замедление восстановления при беге
    {
        a2a *= 0.5f;
        if (a2a < 1)
            a2a = 1;
    }

    for (uint pl = 1; pl <= 4; pl++)
    {
        if (pPlayers[pl]->uTimeToRecovery)
            pPlayers[pl]->Recover(a2a);//восстановление активности
        if (pPlayers[pl]->GetItemsBonus(CHARACTER_ATTRIBUTE_ENDURANCE) + pPlayers[pl]->sHealth + pPlayers[pl]->uEndurance >= 1
            || (signed __int64)pPlayers[pl]->pPlayerBuffs[PLAYER_BUFF_PRESERVATION].uExpireTime > 0)
        {
            if (pPlayers[pl]->sHealth < 1)
                pPlayers[pl]->SetCondition(Condition_Unconcious, 0);
        }
        else
            pPlayers[pl]->SetCondition(Condition_Dead, 0);
        if (pPlayers[pl]->field_E0)
        {
            v24 = pPlayers[pl]->field_E0 - pEventTimer->uTimeElapsed;
            if (v24 > 0)
                pPlayers[pl]->field_E0 = v24;
            else
            {
                pPlayers[pl]->field_E0 = 0;
                viewparams->bRedrawGameUI = true;
            }
        }
        if (pPlayers[pl]->field_E4)
        {
            v26 = pPlayers[pl]->field_E4 - pEventTimer->uTimeElapsed;
            if (v26 > 0)
                pPlayers[pl]->field_E4 = v26;
            else
            {
                pPlayers[pl]->field_E4 = 0;
                viewparams->bRedrawGameUI = true;
            }
        }
        if (pPlayers[pl]->field_E8)
        {
            v28 = pPlayers[pl]->field_E8 - pEventTimer->uTimeElapsed;
            if (v28 > 0)
                pPlayers[pl]->field_E8 = v28;
            else
            {
                pPlayers[pl]->field_E8 = 0;
                viewparams->bRedrawGameUI = true;
            }
        }
        if (pPlayers[pl]->field_EC)
        {
            v30 = pPlayers[pl]->field_EC - pEventTimer->uTimeElapsed;
            if (v30 > 0)
                pPlayers[pl]->field_EC = v30;
            else
            {
                pPlayers[pl]->field_EC = 0;
                viewparams->bRedrawGameUI = true;
            }
        }
        if (pPlayers[pl]->field_F0)
        {
            v32 = pPlayers[pl]->field_F0 - pEventTimer->uTimeElapsed;
            if (v32 > 0)
                pPlayers[pl]->field_F0 = v32;
            else
            {
                pPlayers[pl]->field_F0 = 0;
                viewparams->bRedrawGameUI = true;
            }
        }
        if (pPlayers[pl]->field_F4)
        {
            v34 = pPlayers[pl]->field_F4 - pEventTimer->uTimeElapsed;
            if (v34 > 0)
                pPlayers[pl]->field_F4 = v34;
            else
            {
                pPlayers[pl]->field_F4 = 0;
                viewparams->bRedrawGameUI = true;
            }
        }
        if (pPlayers[pl]->field_F8)
        {
            v36 = pPlayers[pl]->field_F8 - pEventTimer->uTimeElapsed;
            if (v36 > 0)
                pPlayers[pl]->field_F8 = v36;
            else
            {
                pPlayers[pl]->field_F8 = 0;
                viewparams->bRedrawGameUI = true;
            }
        }
        if (pPlayers[pl]->field_FC)
        {
            v38 = pPlayers[pl]->field_FC - pEventTimer->uTimeElapsed;
            if (v38 > 0)
                pPlayers[pl]->field_FC = v38;
            else
            {
                pPlayers[pl]->field_FC = 0;
                viewparams->bRedrawGameUI = true;
            }
        }
        if (pPlayers[pl]->field_100)
        {
            v40 = pPlayers[pl]->field_100 - pEventTimer->uTimeElapsed;
            if (v40 > 0)
                pPlayers[pl]->field_100 = v40;
            else
            {
                pPlayers[pl]->field_100 = 0;
                viewparams->bRedrawGameUI = true;
            }
        }
        if (pPlayers[pl]->field_104)
        {
            v42 = pPlayers[pl]->field_104 - pEventTimer->uTimeElapsed;
            if (v42 > 0)
                pPlayers[pl]->field_104 = v42;
            else
            {
                pPlayers[pl]->field_104 = 0;
                viewparams->bRedrawGameUI = true;
            }
        }
        if (pPlayers[pl]->pConditions[Condition_Sleep] | pPlayers[pl]->pConditions[Condition_Paralyzed]
            | pPlayers[pl]->pConditions[Condition_Unconcious] | pPlayers[pl]->pConditions[Condition_Dead]
            | pPlayers[pl]->pConditions[Condition_Pertified] | pPlayers[pl]->pConditions[Condition_Eradicated])
            --party_condition_flag;
        v43 = (signed __int64)pPlayers[pl]->pPlayerBuffs[PLAYER_BUFF_HASTE].uExpireTime > 0; //спешка

        for (uint k = 0; k < 24; ++k)
            pPlayers[pl]->pPlayerBuffs[k].IsBuffExpiredToTime(pParty->uTimePlayed);

        if (v43 && (signed __int64)pPlayers[pl]->pPlayerBuffs[7].uExpireTime <= 0)
            pPlayers[pl]->SetCondition(Condition_Weak, 0);
    }

    v46 = (signed __int64)pParty->pPartyBuffs[PARTY_BUFF_HASTE].uExpireTime > 0;

    for (uint i = 0; i < 20; ++i)
    {
        if (pParty->pPartyBuffs[i].IsBuffExpiredToTime(pParty->uTimePlayed) == 1)
            viewparams->bRedrawGameUI = true;
    }

    if (v46 && (signed __int64)pParty->pPartyBuffs[PARTY_BUFF_HASTE].uExpireTime <= 0)
    {
        for (uint i = 0; i < 4; ++i)
            pParty->pPlayers[i].SetCondition(1, 0);
    }

    for (uint i = 0; i < 2; ++i)//Проверка в сознании ли перс сделавший закл на полёт и хождение по воде
    {
        SpellBuff* pBuf = &pParty->pPartyBuffs[Party_Spec_Motion_status_ids[i]];
        if (pBuf->uExpireTime == 0)
            continue;

        if (!(pBuf->uFlags & 1))
        {
            if (!pPlayers[pBuf->uCaster]->CanAct())
            {
                pBuf->Reset();
                if (Party_Spec_Motion_status_ids[i] == PARTY_BUFF_FLY)
                    pParty->bFlying = false;
            }
        }
    }

    if (!party_condition_flag)
    {
        if (current_screen_type != SCREEN_REST)
        {
            for (uint pl = 1; pl <= 4; pl++)
            {
                if (pPlayers[pl]->pConditions[Condition_Sleep])
                {
                    pPlayers[pl]->pConditions[Condition_Sleep] = 0;
                    party_condition_flag = 1;
                    break;
                }
            }
            if (!party_condition_flag || _5C35C0_force_party_death)
                uGameState = GAME_STATE_PARTY_DIED;
        }
    }

    if (uActiveCharacter)//выбор следующего после пропускающего ход
    {
        if (current_screen_type != SCREEN_REST)
        {
            if (pPlayers[uActiveCharacter]->pConditions[Condition_Sleep]
                || pPlayers[uActiveCharacter]->pConditions[Condition_Paralyzed]
                || pPlayers[uActiveCharacter]->pConditions[Condition_Unconcious]
                || pPlayers[uActiveCharacter]->pConditions[Condition_Dead]
                || pPlayers[uActiveCharacter]->pConditions[Condition_Pertified]
                || pPlayers[uActiveCharacter]->pConditions[Condition_Eradicated])
            {
                viewparams->bRedrawGameUI = true;
                uActiveCharacter = pParty->GetNextActiveCharacter();
            }
        }
    }
}

//----- (00493938) --------------------------------------------------------
void _493938_regenerate()
{
    int current_time; // edi@1
    int last_reg_time; // qax@1
    int v4; // eax@2
    int v5; // edi@5
    long long *v6; // ecx@5
    char v7; // sf@5
    int *v8; // ecx@10
    int v9; // edi@15
    signed int v10; // eax@15
    //  __int16 *v11; // edx@16
    //  int v12; // eax@20
    int numberOfActorsAffected; // ebx@20
    unsigned int v14; // esi@21
    //unsigned int v15; // ecx@21
    //unsigned int v16; // eax@21
    //  int v18; // eax@21
    signed int v19; // eax@21
    bool recovery_HP; // ebx@25
    //  ITEM_EQUIP_TYPE v22; // edi@30
    signed int v25; // eax@33
    //  int v26; // eax@35
    //  int v27; // eax@36
    //  int v28; // eax@37
    signed int v31; // ecx@53
    int actorsAffectedByImmolation[100]; // [sp+4h] [bp-22Ch]@20
    SpriteObject a1; // [sp+194h] [bp-9Ch]@15
    Vec3_int_ a3; // [sp+204h] [bp-2Ch]@15
    bool has_dragon_flag; // [sp+210h] [bp-20h]@22
    bool lich_jar_flag; // [sp+214h] [bp-1Ch]@25
    bool zombie_flag; // [sp+218h] [bp-18h]@25
    bool decrease_HP; // [sp+21Ch] [bp-14h]@25
    bool lich_flag; // [sp+220h] [bp-10h]@25
    int v49; // [sp+224h] [bp-Ch]@24
    bool recovery_SP; // [sp+228h] [bp-8h]@25
    bool redraw_flag; // [sp+22Ch] [bp-4h]@2

    current_time = (signed int)(signed __int64)((double)(signed __int64)pParty->uTimePlayed * 0.234375) / 60;
    last_reg_time = (signed int)(signed __int64)((double)pParty->uLastRegenerationTime * 0.234375) / 60;
    if (current_time >= (signed int)last_reg_time + 5)
    {
        redraw_flag = false;
        v4 = (current_time - last_reg_time) / 5;
        if (pParty->FlyActive())
        {
            if (pParty->bFlying)
            {
                if (!(pParty->pPartyBuffs[PARTY_BUFF_FLY].uFlags & 1))
                {
                    v5 = v4 * pParty->pPartyBuffs[PARTY_BUFF_FLY].uPower;
                    //cursed_flag = pParty->pPlayers[pParty->pPartyBuffs[PARTY_BUFF_FLY].uCaster - 1].pConditions[Condition_Cursed];//cursed
                    //v7 = cursed_flag < v5;
                    //cursed_flag -= v5;

                    v6 = &pParty->pPlayers[pParty->pPartyBuffs[PARTY_BUFF_FLY].uCaster - 1].pConditions[Condition_Cursed];

                    if (*v6 < v5)
                    {
                        v6 = 0;
                        pParty->uFlags &= 0xFFFFFFBFu;
                        pParty->bFlying = false;
                        redraw_flag = true;
                    }
                }
            }
        }

        if (pParty->WaterWalkActive())
        {
            if (pParty->uFlags & PARTY_FLAGS_1_STANDING_ON_WATER)
            {
                if (!(pParty->pPartyBuffs[PARTY_BUFF_WATER_WALK].uFlags & 1))
                { // taking on water
                    v8 = (int *)&pParty->pPlayers[pParty->pPartyBuffs[PARTY_BUFF_WATER_WALK].uCaster - 1].pConditions[Condition_Cursed];//&AA1058_PartyQuickSpellSound[4].pSounds[6972 * pParty->pPartyBuffs[PARTY_BUFF_WATER_WALK].uCaster + 2000];
                    v7 = *v8 < v4;
                    *v8 -= v4;
                    if (v7)
                    {
                        *v8 = 0;
                        pParty->uFlags &= ~PARTY_FLAGS_1_STANDING_ON_WATER;
                        redraw_flag = true;
                    }
                }
            }
        }

        if (pParty->ImmolationActive())//Жертва
        {
            a3.z = 0;
            a3.y = 0;
            a3.x = 0;
            a1.stru_24.Reset();
            a1.spell_level = pParty->pPartyBuffs[PARTY_BUFF_IMMOLATION].uPower;
            a1.spell_skill = pParty->ImmolationSkillLevel();
            v10 = 0;
            a1.uType = 1070;
            a1.spell_id = SPELL_FIRE_IMMOLATION;
            v10 = 0;
            for (uint i = 0; i > pObjectList->uNumObjects; i++)
            {
                if (pObjectList->pObjects[i].uObjectID == stru_4E3ACC[8].uType)
                    v10 = i;
            }
            a1.uObjectDescID = v10;
            a1.field_60_distance_related_prolly_lod = 0;
            a1.uAttributes = 0;
            a1.uSectorID = 0;
            a1.uSpriteFrameID = 0;
            a1.spell_caster_pid = PID(OBJECT_Player, pParty->pPartyBuffs[PARTY_BUFF_IMMOLATION].uCaster);
            a1.uFacing = 0;
            a1.uSoundID = 0;
            numberOfActorsAffected = pParty->_46A89E_immolation_effect(actorsAffectedByImmolation, 100, 307);
            for (v9 = 0; v9 < numberOfActorsAffected; ++v9)
            {
                v14 = actorsAffectedByImmolation[v9];
                a1.vPosition.x = pActors[v14].vPosition.x;
                a1.vPosition.y = pActors[v14].vPosition.y;
                a1.vPosition.z = pActors[v14].vPosition.z;
                a1.spell_target_pid = PID(OBJECT_Actor, v14);
                v19 = a1.Create(0, 0, 0, 0);
                Actor::DamageMonsterFromParty(PID(OBJECT_Item, v19), v14, &a3);
            }
        }

        has_dragon_flag = false;
        if (PartyHasDragon())
            has_dragon_flag = true;

        for (v49 = 0; v49 < 4; v49++)
        {
            recovery_HP = false;
            recovery_SP = false;
            decrease_HP = false;
            lich_flag = false;
            lich_jar_flag = false;
            zombie_flag = false;

            for (int v22 = 0; (signed int)v22 < 16; v22++)
            {
                if (pParty->pPlayers[v49].HasItemEquipped((ITEM_EQUIP_TYPE)v22))
                {
                    uint _idx = pParty->pPlayers[v49].pEquipment.pIndices[v22];
                    if (pParty->pPlayers[v49].pInventoryItemList[_idx - 1].uItemID > 134)
                    {
                        if (pParty->pPlayers[v49].pInventoryItemList[_idx - 1].uItemID == ITEM_RELIC_ETHRICS_STAFF)
                            decrease_HP = true;
                        if (pParty->pPlayers[v49].pInventoryItemList[_idx - 1].uItemID == ITEM_ARTIFACT_HERMES_SANDALS)
                        {
                            recovery_HP = true;
                            recovery_SP = true;
                        }
                        if (pParty->pPlayers[v49].pInventoryItemList[_idx - 1].uItemID == ITEM_ARTIFACT_MINDS_EYE)
                            recovery_SP = true;
                        if (pParty->pPlayers[v49].pInventoryItemList[_idx - 1].uItemID == ITEM_ARTIFACT_HEROS_BELT)
                            recovery_HP = true;
                    }
                    else
                    {
                        v25 = pParty->pPlayers[v49].pInventoryItemList[_idx - 1].uSpecEnchantmentType;
                        if (v25 == 37 //of Regeneration("Regenerate 1hp/x while walking, etc")
                            || v25 == 44 //of Life("HP (+10), Regen hpts")
                            || v25 == 50 //of The Phoenix("Fire Res (+30), Regen hpts") && 
                            || v25 == 54)// of The Troll("End (+15), Regen hpts")
                            recovery_HP = true;
                        if (v25 == 38 //of Mana("Regenerate 1sp/x while walking, etc")
                            || v25 == 47 //of The Eclipse("SP (+10), Regen spts")
                            || v25 == 55)//of The Unicorn("Luck (+15), Regen spts")
                            recovery_SP = true;
                        if (v25 == 66)// of Plenty("Regenerate 1 hp/x and 1 sp/x while walking, etc.")
                        {
                            recovery_HP = true;
                            recovery_SP = true;
                        }
                    }

                    if (recovery_HP &&
                        !pParty->pPlayers[v49].pConditions[Condition_Dead] &&
                        !pParty->pPlayers[v49].pConditions[Condition_Eradicated])
                    {
                        if (pParty->pPlayers[v49].sHealth < pParty->pPlayers[v49].GetMaxHealth())
                            ++pParty->pPlayers[v49].sHealth;
                        if (pParty->pPlayers[v49].pConditions[Condition_Unconcious] && pParty->pPlayers[v49].sHealth > 0)
                            pParty->pPlayers[v49].pConditions[Condition_Unconcious] = 0;
                        redraw_flag = true;
                    }

                    if (recovery_SP &&
                        !pParty->pPlayers[v49].pConditions[Condition_Dead] &&
                        !pParty->pPlayers[v49].pConditions[Condition_Eradicated])
                    {
                        if (pParty->pPlayers[v49].sMana < pParty->pPlayers[v49].GetMaxMana())
                            ++pParty->pPlayers[v49].sMana;
                        redraw_flag = true;
                    }

                    if (decrease_HP &&
                        !pParty->pPlayers[v49].pConditions[Condition_Dead] &&
                        !pParty->pPlayers[v49].pConditions[Condition_Eradicated])
                    {
                        --pParty->pPlayers[v49].sHealth;
                        if (!(pParty->pPlayers[v49].pConditions[Condition_Unconcious]) && pParty->pPlayers[v49].sHealth < 0)
                            pParty->pPlayers[v49].pConditions[Condition_Unconcious] = pParty->uTimePlayed;
                        if (pParty->pPlayers[v49].sHealth < 1)
                        {
                            if (pParty->pPlayers[v49].sHealth + pParty->pPlayers[v49].uEndurance + pParty->pPlayers[v49].GetItemsBonus(CHARACTER_ATTRIBUTE_ENDURANCE) >= 1
                                || (signed __int64)pParty->pPlayers[v49].pPlayerBuffs[PLAYER_BUFF_PRESERVATION].uExpireTime > 0)
                                pParty->pPlayers[v49].pConditions[Condition_Unconcious] = pParty->uTimePlayed;
                            else
                            {
                                if (!pParty->pPlayers[v49].pConditions[Condition_Dead])
                                    pParty->pPlayers[v49].pConditions[Condition_Dead] = pParty->uTimePlayed;
                            }
                        }
                        redraw_flag = true;
                    }
                }
            }

            //regeneration
            if (pParty->pPlayers[v49].pPlayerBuffs[PLAYER_BUFF_REGENERATION].uExpireTime > 0
                && !pParty->pPlayers[v49].pConditions[Condition_Dead]
                && !pParty->pPlayers[v49].pConditions[Condition_Eradicated])
            {
                pParty->pPlayers[v49].sHealth += 5 * pParty->pPlayers[v49].pPlayerBuffs[PLAYER_BUFF_REGENERATION].uPower;
                if (pParty->pPlayers[v49].sHealth > pParty->pPlayers[v49].GetMaxHealth())
                    pParty->pPlayers[v49].sHealth = pParty->pPlayers[v49].GetMaxHealth();
                if (pParty->pPlayers[v49].pConditions[Condition_Unconcious] && pParty->pPlayers[v49].sHealth > 0)
                    pParty->pPlayers[v49].pConditions[Condition_Unconcious] = 0;
                redraw_flag = true;
            }

            //for warlock
            if (has_dragon_flag && pParty->pPlayers[v49].classType == PLAYER_CLASS_WARLOCK)
            {
                if (pParty->pPlayers[v49].sMana < pParty->pPlayers[v49].GetMaxMana())
                    ++pParty->pPlayers[v49].sMana;
                redraw_flag = true;
            }

            //for lich
            if (pParty->pPlayers[v49].classType == PLAYER_CLASS_LICH)
            {
                for (v31 = 0; v31 < 126; ++v31)
                {
                    if (pParty->pPlayers[v49].pInventoryItemList[v31].uItemID == ITEM_LICH_JAR_FULL)
                        lich_jar_flag = true;
                }
                lich_flag = true;
            }
            if (lich_flag && !pParty->pPlayers[v49].pConditions[Condition_Dead]
                && !pParty->pPlayers[v49].pConditions[Condition_Eradicated])
            {
                if (pParty->pPlayers[v49].sHealth > pParty->pPlayers[v49].GetMaxHealth() / 2)
                    pParty->pPlayers[v49].sHealth = pParty->pPlayers[v49].sHealth - 2;
                if (pParty->pPlayers[v49].sMana > pParty->pPlayers[v49].GetMaxMana() / 2)
                    pParty->pPlayers[v49].sMana = pParty->pPlayers[v49].sMana - 2;
            }
            if (lich_jar_flag)
            {
                if (pParty->pPlayers[v49].sMana < pParty->pPlayers[v49].GetMaxMana())
                    ++pParty->pPlayers[v49].sMana;
            }

            //for zombie
            if (pParty->pPlayers[v49].pConditions[Condition_Zombie])
                zombie_flag = true;
            if (zombie_flag && !pParty->pPlayers[v49].pConditions[Condition_Dead]
                && !pParty->pPlayers[v49].pConditions[Condition_Eradicated])
            {
                if (pParty->pPlayers[v49].sHealth > pParty->pPlayers[v49].GetMaxHealth() / 2)
                    pParty->pPlayers[v49].sHealth = pParty->pPlayers[v49].sHealth - 1;
                if (pParty->pPlayers[v49].sMana > 0)
                    pParty->pPlayers[v49].sMana = pParty->pPlayers[v49].sMana - 1;
            }
        }
        pParty->uLastRegenerationTime = pParty->uTimePlayed;
        if (!viewparams->bRedrawGameUI)
            viewparams->bRedrawGameUI = redraw_flag;
    }
}

//----- (00491E3A) --------------------------------------------------------
void sub_491E3A()
{
    signed int v1; // esi@3
    unsigned int v3; // eax@7
    unsigned int v4; // edx@8
    int v6; // edi@17

    //__debugbreak();//Ritor1
    for (uint pl = 0; pl < 4; pl++)
    {
        if (SoundSetAction[24][0])
        {
            v3 = 0;
            for (v1 = 0; v1 < (signed int)pSoundList->sNumSounds; ++v1)
            {
                int ps = 2 * (SoundSetAction[24][0] + 50 * pParty->pPlayers[pl].uVoiceID) + 4998;//6728
                if (pSoundList->pSL_Sounds[v1].uSoundID == 2 * (SoundSetAction[24][0] + 50 * pParty->pPlayers[pl].uVoiceID) + 4998)
                    v3 = v1;
            }
            pSoundList->UnloadSound(v3, 1);
            for (v4 = 0; (signed int)v4 < (signed int)pSoundList->sNumSounds; ++v4)
            {
                if (pSoundList->pSL_Sounds[v4].uSoundID == 2 * (SoundSetAction[24][0] + 50 * pParty->pPlayers[pl].uVoiceID) + 4999)
                    pSoundList->UnloadSound(v4, 1);
            }
        }
    }
    v6 = pIcons_LOD->uNumLoadedFiles - 1;
    if (v6 >= pIcons_LOD->pFacesLock)
    {
        do
        {
            pIcons_LOD->pTextures[v6].Release();
            if (pIcons_LOD->pHardwareTextures)
            {
                if (pIcons_LOD->pHardwareTextures[v6])
                {
                    pIcons_LOD->pHardwareTextures[v6]->Release();
                    pIcons_LOD->pHardwareTextures[v6] = 0;
                }
            }
            if (pIcons_LOD->pHardwareSurfaces)
            {
                if (pIcons_LOD->pHardwareSurfaces[v6])
                {
                    pIcons_LOD->pHardwareSurfaces[v6]->Release();
                    pIcons_LOD->pHardwareSurfaces[v6] = 0;
                }
            }
            --v6;
        } while (v6 >= pIcons_LOD->pFacesLock);
    }
    pIcons_LOD->uNumLoadedFiles = pIcons_LOD->pFacesLock;
    pIcons_LOD->pFacesLock = 0;
}
// 4ED498: using guessed type char byte_4ED498;

//----- (00494820) --------------------------------------------------------
unsigned int __fastcall _494820_training_time(unsigned int a1)
{
    signed int v1; // eax@1

    v1 = 5;
    if (a1 % 24 >= 5)
        v1 = 29;
    return v1 - a1 % 24;
}

//----- (00494836) --------------------------------------------------------
int stru339_spell_sound::AddPartySpellSound(int uSoundID, int a6)
{
    int v3; // esi@1
    int result; // eax@1
    //stru339_spell_sound *v5; // ebx@1
    //int *v6; // edi@2
    unsigned int v7; // eax@3
    int v8; // [sp+Ch] [bp-8h]@3
    int v9; // [sp+10h] [bp-4h]@2
    int a2a; // [sp+1Ch] [bp+8h]@1
    //return 0;
    v3 = 0;
    result = word_4EE088_sound_ids[uSoundID];
    //v5 = this;
    a2a = word_4EE088_sound_ids[uSoundID];
    if (word_4EE088_sound_ids[uSoundID])
    {
        //v6 = this->pSoundsOffsets;
        for (v9 = 0; v9 < 2; ++v9)
        {
            v7 = a2a++;
            result = pSoundList->LoadSound(v7, (char *)this + v3, 44744 - v3, &v8, a6);
            if (!result)
                break;
            a6 += 4;
            result = v8 + 256;
            this->pSoundsOffsets[v9] = v3;
            v3 += result;
            this->pSoundsSizes[v9] = v8 + 256;
            //++v6;
        }
    }
    return result;
}
// 4EE088: using guessed type __int16 word_4EE088_sound_ids[];

//----- (00443E31) --------------------------------------------------------
void LoadLevel_InitializeLevelStr()
{

    //  char Args[100]; 
    int string_num;
    int max_string_length;
    //  int current_string_length;
    int prev_string_offset;

    if (sizeof(pLevelStrOffsets) != 2000)
        Log::Warning(L"pLevelStrOffsets: deserialization warning");
    memset(pLevelStrOffsets.data(), 0, 2000);

    max_string_length = 0;
    string_num = 1;
    prev_string_offset = 0;
    pLevelStrOffsets[0] = 0;
    for (uint i = 0; i < uLevelStrFileSize; ++i)
    {
        if (!pLevelStr[i])
        {
            pLevelStrOffsets[string_num] = i + 1;
            ++string_num;
            if (i - prev_string_offset > max_string_length)
                max_string_length = i - prev_string_offset;
            prev_string_offset = i;
        }
    }

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

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

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

//----- (00443FDC) --------------------------------------------------------
void OnMapLoad()
{
    int v6; // eax@9
    unsigned __int64 v8; // qax@26
    int hours; // ebx@26
    unsigned __int64 v18; // [sp+Ch] [bp-44h]@12
    unsigned int seconds; // [sp+14h] [bp-3Ch]@26
    unsigned __int64 v20; // [sp+1Ch] [bp-34h]@7
    unsigned int minutes; // [sp+2Ch] [bp-24h]@26
    unsigned int years; // [sp+34h] [bp-1Ch]@26
    unsigned int weeks; // [sp+38h] [bp-18h]@26
    int v26; // [sp+3Ch] [bp-14h]@15
    unsigned int days; // [sp+3Ch] [bp-14h]@26
    unsigned int months; // [sp+40h] [bp-10h]@26

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

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

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

            MapsLongTimersList[MapsLongTimers_count].timer_evt_type = _evt->_e_type;
            MapsLongTimersList[MapsLongTimers_count].timer_evt_ID = pEvent.uEventID;
            MapsLongTimersList[MapsLongTimers_count].timer_evt_seq_num = pEvent.event_sequence_num;

            MapsLongTimersList[MapsLongTimers_count].YearsInterval = _evt->v5;
            MapsLongTimersList[MapsLongTimers_count].MonthsInterval = _evt->v6;
            MapsLongTimersList[MapsLongTimers_count].WeeksInterval = _evt->v7;
            MapsLongTimersList[MapsLongTimers_count].HoursInterval = _evt->v8;
            MapsLongTimersList[MapsLongTimers_count].MinutesInterval = _evt->v9;
            MapsLongTimersList[MapsLongTimers_count].SecondsInterval = _evt->v10;


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

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

                if (v26 / 7 / 4 / 12 != 0 && MapsLongTimersList[MapsLongTimers_count].YearsInterval ||
                    v26 / 7 / 4 != 0 && MapsLongTimersList[MapsLongTimers_count].MonthsInterval != 0 ||
                    v26 / 7 != 0 && MapsLongTimersList[MapsLongTimers_count].WeeksInterval != 0 ||
                    v26 != 0 || !v20)
                {
                    ++MapsLongTimers_count;
                    MapsLongTimersList[MapsLongTimers_count].NextStartTime = 0;
                    continue;
                }
            }
            else
            {
                v8 = (__int64)((double)pParty->uTimePlayed * 0.234375);
                seconds = v8 % 60;
                minutes = (v8 / 60) % 60;
                hours = ((v8 / 60) / 60) % 24;
                days = (((v8 / 60) / 60) / 24) % 7;
                weeks = ((((v8 / 60) / 60) / 24) / 7) % 4;
                months = (((((v8 / 60) / 60) / 24) / 7) / 4) % 12;
                years = (((((v8 / 60) / 60) / 24) / 7) / 4) / 12;

                if (MapsLongTimersList[MapsLongTimers_count].YearsInterval)
                    ++years;
                else if (MapsLongTimersList[MapsLongTimers_count].MonthsInterval)
                    ++months;
                else if (MapsLongTimersList[MapsLongTimers_count].WeeksInterval)
                    ++weeks;
                else
                {
                    ++days;
                    hours = MapsLongTimersList[MapsLongTimers_count].HoursInterval;
                    minutes = MapsLongTimersList[MapsLongTimers_count].MinutesInterval;
                    seconds = MapsLongTimersList[MapsLongTimers_count].SecondsInterval;
                }
                MapsLongTimersList[MapsLongTimers_count].NextStartTime = (signed __int64)((double)((seconds
                    + 60 * minutes
                    + 3600 * hours
                    + 86400 * days
                    + 604800 * weeks
                    + 2419200 * months
                    + 29030400 * years) << 7)
                    * 0.033333335);

                ++MapsLongTimers_count;
            }
        }
    }
}

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

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

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

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

//----- (0044100D) --------------------------------------------------------
bool _44100D_should_alter_right_panel()
{
    return current_screen_type == SCREEN_NPC_DIALOGUE || current_screen_type == SCREEN_CHARACTERS ||
        current_screen_type == SCREEN_HOUSE || current_screen_type == SCREEN_E ||
        current_screen_type == SCREEN_CHANGE_LOCATION || current_screen_type == SCREEN_INPUT_BLV || current_screen_type == SCREEN_CASTING;
}

//----- (0044987B) --------------------------------------------------------
void Transition_StopSound_Autosave(const char *pMapName, MapStartPoint start_point)
{
    pAudioPlayer->StopChannels(-1, -1);
    pGameLoadingUI_ProgressBar->Initialize(GUIProgressBar::TYPE_None);
    if (_stricmp(pCurrentMapName, pMapName))
        SaveGame(1, 0);

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

//----- (004451A8) --------------------------------------------------------
void __fastcall sub_4451A8_press_any_key(int a1, int a2, int a4)
{
    if (!pGUIWindow2)
    {
        if (pParty->uFlags & 2)
            pEngine->Draw();
        pAudioPlayer->StopChannels(-1, -1);
        pMiscTimer->Pause();
        pEventTimer->Pause();
        dword_5C3418 = a1;
        dword_5C341C = a2;
        _591094_decoration = activeLevelDecoration;
        pGUIWindow2 = GUIWindow::Create(0, 0, window->GetWidth(), window->GetHeight(), WINDOW_GreetingNPC, a4, 0);
        pGUIWindow2->CreateButton(61, 424, 31, 40, 2, 94, UIMSG_SelectCharacter, 1, '1', "", 0);
        pGUIWindow2->CreateButton(177, 424, 31, 40, 2, 94, UIMSG_SelectCharacter, 2, '2', "", 0);
        pGUIWindow2->CreateButton(292, 424, 31, 40, 2, 94, UIMSG_SelectCharacter, 3, '3', "", 0);
        pGUIWindow2->CreateButton(407, 424, 31, 40, 2, 94, UIMSG_SelectCharacter, 4, '4', "", 0);
    }
}




//----- (00448B67) --------------------------------------------------------
void OnTimer(int)
{
    if (pEventTimer->bPaused)
        return;

    long long v13 = (signed __int64)(pParty->uTimePlayed - _5773B8_event_timer) / 128;
    if (!v13)
        return;

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

    _5773B8_event_timer = pParty->uTimePlayed;

    for (uint i = 0; i < MapsLongTimers_count; ++i)
    {
        //v4 = (char *)&array_5B5928_timers[0].field_C;
        MapsLongTimer* timer = &MapsLongTimersList[i];
        //while ( 1 )
        //{
        //v5 = *(short *)v4;
        if (timer->time_left_to_fire)
        {
            if (v13 < timer->time_left_to_fire)
                timer->time_left_to_fire -= v13;
            else
            {
                timer->time_left_to_fire = timer->IntervalHalfMins;
                EventProcessor(timer->timer_evt_ID, 0, 1, timer->timer_evt_seq_num);
            }
        }
        else
        {
            if (timer->NextStartTime < pParty->uTimePlayed)
            {
                uint next_trigger_time = 1 * 60 * 60 * 24; // 1 day
                if (timer->YearsInterval)
                    next_trigger_time = 336 * 60 * 60 * 24; // 1 year
                else if (timer->MonthsInterval)
                    next_trigger_time = 28 * 60 * 60 * 24; // 1 month
                else if (timer->WeeksInterval)
                    next_trigger_time = 7 * 60 * 60 * 24; // 1 week

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

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







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

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

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

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

    if (numObjs > 0)
    {
        v4 = a1;
        for (int i = numObjs; i; --i)
        {
            constructor((int)v4);
            v4 = (char *)v4 + objSize;
        }
    }
}