Beispiel #1
0
static int l_anim_get_tile(lua_State *L)
{
    THAnimation* pAnimation = luaT_testuserdata<THAnimation>(L);
    lua_settop(L, 1);
    lua_getfenv(L, 1);
    lua_getfield(L, 2, "map");
    lua_replace(L, 2);
    if(lua_isnil(L, 2))
    {
        return 0;
    }
    THMap* pMap = (THMap*)lua_touserdata(L, 2);
    const THLinkList* pListNode = pAnimation->getPrevious();
    while(pListNode->m_pPrev)
    {
        pListNode = pListNode->m_pPrev;
    }
    // Casting pListNode to a THMapNode* is slightly dubious, but it should
    // work. If on the normal list, then pListNode will be a THMapNode*, and
    // all is fine. However, if on the early list, pListNode will be pointing
    // to a member of a THMapNode, so we're relying on pointer arithmetic
    // being a subtract and integer divide by sizeof(THMapNode) to yield the
    // correct map node.
    const THMapNode *pRootNode = pMap->getNodeUnchecked(0, 0);
    uintptr_t iDiff = reinterpret_cast<const char*>(pListNode) -
                      reinterpret_cast<const char*>(pRootNode);
    int iIndex = (int)(iDiff / sizeof(THMapNode));
    int iY = iIndex / pMap->getWidth();
    int iX = iIndex - (iY * pMap->getWidth());
    lua_pushinteger(L, iX + 1);
    lua_pushinteger(L, iY + 1);
    return 3; // map, x, y
}
int ScrollableGamePanel::_l_on_ui_scroll_map(lua_State *L)
{
    ScrollableGamePanel *pThis = reinterpret_cast<ScrollableGamePanel*>(
        lua_touserdata(L, lua_upvalueindex(2)));

    // Make a copy of the "self" parameter at the bottom of the stack
    lua_pushvalue(L, 1);
    lua_insert(L, 1);

    // Call original GameUI:scrollMap() function
    lua_pushvalue(L, lua_upvalueindex(1));
    lua_insert(L, 2);
    lua_call(L, lua_gettop(L) - 2, LUA_MULTRET);

    if(pThis->m_bShouldRespondToScroll)
    {
        int iPanelW, iPanelH;
        pThis->m_pGamePanel->GetSize(&iPanelW, &iPanelH);

        // Get world co-ordinates of window center
        lua_checkstack(L, 4);
        lua_getfield(L, 1, "ScreenToWorld");
        lua_pushvalue(L, 1);
        lua_pushinteger(L, iPanelW / 2);
        lua_pushinteger(L, iPanelH / 2);
        lua_call(L, 3, 2);
        lua_Number fX = lua_tonumber(L, -2) - 1.0;
        lua_Number fY = lua_tonumber(L, -1) - 1.0;
        lua_pop(L, 2);

        // Get map extents
        THMap* pMap = pThis->m_pGamePanel->getMap();
        int iMapH = pMap->getHeight();
        int iTemp = pMap->getWidth();
        pMap->worldToScreen(iTemp, iMapH);
        int iMapW = pMap->getWidth();
        iTemp = 0;
        pMap->worldToScreen(iMapW, iTemp);

        // Get screen co-ordinates of window center
        // We could get these directly from the GameUI, but we'd be delving into
        // its member variables, and also perhaps not properly accounting for zoom.
        pMap->worldToScreen(fX, fY);
        int iX = (int)fX;
        int iY = (int)fY;

        // Update scrollbars
        pThis->m_pMapScrollX->SetScrollbar(iX + iMapW, iPanelW, iMapW * 2 + iPanelW, iPanelW);
        pThis->m_pMapScrollY->SetScrollbar(iY        , iPanelH, iMapH     + iPanelH, iPanelH);
    }

    // Return results from original call
    return lua_gettop(L) - 1;
}
Beispiel #3
0
static int l_map_getsize(lua_State *L)
{
    THMap* pMap = luaT_testuserdata<THMap>(L);
    lua_pushinteger(L, pMap->getWidth());
    lua_pushinteger(L, pMap->getHeight());
    return 2;
}
Beispiel #4
0
static int l_map_unmark_room(lua_State *L)
{
    THMap* pMap = luaT_testuserdata<THMap>(L);
    int iX_ = static_cast<int>(luaL_checkinteger(L, 2) - 1);
    int iY_ = static_cast<int>(luaL_checkinteger(L, 3) - 1);
    int iW = static_cast<int>(luaL_checkinteger(L, 4));
    int iH = static_cast<int>(luaL_checkinteger(L, 5));

    if(iX_ < 0 || iY_ < 0 || (iX_ + iW) > pMap->getWidth() || (iY_ + iH) > pMap->getHeight())
        luaL_argerror(L, 2, "Rectangle is out of bounds");

    for(int iY = iY_; iY < iY_ + iH; ++iY)
    {
        for(int iX = iX_; iX < iX_ + iW; ++iX)
        {
            THMapNode *pNode = pMap->getNodeUnchecked(iX, iY);
            pNode->iBlock[0] = pMap->getOriginalNodeUnchecked(iX, iY)->iBlock[0];
            pNode->flags.room = false;
            pNode->iRoomId = 0;
        }
    }

    pMap->updatePathfinding();
    pMap->updateShadows();

    lua_settop(L, 1);
    return 1;
}
Beispiel #5
0
static int l_map_mark_room(lua_State *L)
{
    THMap* pMap = luaT_testuserdata<THMap>(L);
    int iX_ = static_cast<int>(luaL_checkinteger(L, 2) - 1);
    int iY_ = static_cast<int>(luaL_checkinteger(L, 3) - 1);
    int iW = static_cast<int>(luaL_checkinteger(L, 4));
    int iH = static_cast<int>(luaL_checkinteger(L, 5));
    uint16_t iTile = static_cast<uint16_t>(luaL_checkinteger(L, 6));
    uint16_t iRoomId = static_cast<uint16_t>(luaL_optinteger(L, 7, 0));

    if(iX_ < 0 || iY_ < 0 || (iX_ + iW) > pMap->getWidth() || (iY_ + iH) > pMap->getHeight())
        luaL_argerror(L, 2, "Rectangle is out of bounds");

    for(int iY = iY_; iY < iY_ + iH; ++iY)
    {
        for(int iX = iX_; iX < iX_ + iW; ++iX)
        {
            THMapNode *pNode = pMap->getNodeUnchecked(iX, iY);
            pNode->iBlock[0] = iTile;
            pNode->iBlock[3] = 0;
            pNode->flags.room = true;
            pNode->flags.passable |= pNode->flags.passable_if_not_for_blueprint;
            pNode->flags.passable_if_not_for_blueprint = false;
            pNode->iRoomId = iRoomId;
        }
    }

    pMap->updatePathfinding();
    pMap->updateShadows();
    lua_settop(L, 1);
    return 1;
}
Beispiel #6
0
/* Compute the fraction of corridor tiles with litter, of the parcels owned by the given player. */
static int l_map_get_litter_fraction(lua_State *L)
{
    THMap* pMap = luaT_testuserdata<THMap>(L);
    int owner = static_cast<int>(luaL_checkinteger(L, 2));
    if (owner == 0)
    {
        lua_pushnumber(L, 0.0); // Outside has no litter.
        return 1;
    }

    double tile_count = 0;
    double litter_count = 0;
    for (int x = 0; x < pMap->getWidth(); x++)
    {
        for (int y = 0; y < pMap->getHeight(); y++)
        {
            const THMapNode* pNode = pMap->getNodeUnchecked(x, y);
            if (pNode->iParcelId == 0 || owner != pMap->getParcelOwner(pNode->iParcelId) ||
                pNode->iRoomId != 0)
            {
                continue;
            }

            tile_count++;
            for(auto iter = pNode->objects.begin(); iter != pNode->objects.end(); iter++)
            {
                if(*iter == THObjectType::litter)
                {
                    litter_count++;
                    break;
                }
            }
        }
    }

    double fraction = (tile_count == 0) ? 0.0 : litter_count / tile_count;
    lua_pushnumber(L, fraction);
    return 1;
}
Beispiel #7
0
static int l_map_updateblueprint(lua_State *L)
{
    // NB: This function can be implemented in Lua, but is implemented in C for
    // efficiency.
    const unsigned short iFloorTileGood = 24 + (THDF_Alpha50 << 8);
    const unsigned short iFloorTileGoodCenter = 37 + (THDF_Alpha50 << 8);
    const unsigned short iFloorTileBad  = 67 + (THDF_Alpha50 << 8);
    const unsigned int iWallAnimTopCorner = 124;
    const unsigned int iWallAnim = 120;

    THMap* pMap = luaT_testuserdata<THMap>(L);
    int iOldX = static_cast<int>(luaL_checkinteger(L, 2)) - 1;
    int iOldY = static_cast<int>(luaL_checkinteger(L, 3)) - 1;
    int iOldW = static_cast<int>(luaL_checkinteger(L, 4));
    int iOldH = static_cast<int>(luaL_checkinteger(L, 5));
    int iNewX = static_cast<int>(luaL_checkinteger(L, 6)) - 1;
    int iNewY = static_cast<int>(luaL_checkinteger(L, 7)) - 1;
    int iNewW = static_cast<int>(luaL_checkinteger(L, 8));
    int iNewH = static_cast<int>(luaL_checkinteger(L, 9));
    luaL_checktype(L, 10, LUA_TTABLE); // Animation list
    THAnimationManager* pAnims = luaT_testuserdata<THAnimationManager>(L, 11, luaT_upvalueindex(1));
    bool entire_invalid = lua_toboolean(L, 12) != 0;
    bool valid = !entire_invalid;

    if(iOldX < 0 || iOldY < 0 || (iOldX + iOldW) > pMap->getWidth() || (iOldY + iOldH) > pMap->getHeight())
        luaL_argerror(L, 2, "Old rectangle is out of bounds");
    if(iNewX < 0 || iNewY < 0 || (iNewX + iNewW) >= pMap->getWidth() || (iNewY + iNewH) >= pMap->getHeight())
        luaL_argerror(L, 6, "New rectangle is out of bounds");

    // Clear blueprint flag from previous selected floor tiles (copying it to the passable flag).
    for(int iY = iOldY; iY < iOldY + iOldH; ++iY)
    {
        for(int iX = iOldX; iX < iOldX + iOldW; ++iX)
        {
            THMapNode *pNode = pMap->getNodeUnchecked(iX, iY);
            pNode->iBlock[3] = 0;
            uint32_t iFlags = pNode->iFlags;
            iFlags |= ((iFlags & THMN_PassableIfNotForBlueprint) != 0) ? THMN_Passable : 0;
            iFlags &= ~THMN_PassableIfNotForBlueprint;
            pNode->iFlags = iFlags;
        }
    }

    // Add blueprint flag to new floor tiles.
    for(int iY = iNewY; iY < iNewY + iNewH; ++iY)
    {
        for(int iX = iNewX; iX < iNewX + iNewW; ++iX)
        {
            THMapNode *pNode = pMap->getNodeUnchecked(iX, iY);
            if(is_valid(entire_invalid, pNode))
                pNode->iBlock[3] = iFloorTileGood;
            else
            {
                pNode->iBlock[3] = iFloorTileBad;
                valid = false;
            }
            pNode->iFlags |= ((pNode->iFlags & THMN_Passable) != 0) ? THMN_PassableIfNotForBlueprint : 0;
        }
    }

    // Set center floor tiles
    if(iNewW >= 2 && iNewH >= 2)
    {
        int iCenterX = iNewX + (iNewW - 2) / 2;
        int iCenterY = iNewY + (iNewH - 2) / 2;

        THMapNode *pNode = pMap->getNodeUnchecked(iCenterX, iCenterY);
        if(pNode->iBlock[3] == iFloorTileGood)
            pNode->iBlock[3] = iFloorTileGoodCenter + 2;

        pNode = pMap->getNodeUnchecked(iCenterX + 1, iCenterY);
        if(pNode->iBlock[3] == iFloorTileGood)
            pNode->iBlock[3] = iFloorTileGoodCenter + 1;

        pNode = pMap->getNodeUnchecked(iCenterX, iCenterY + 1);
        if(pNode->iBlock[3] == iFloorTileGood)
            pNode->iBlock[3] = iFloorTileGoodCenter + 0;

        pNode = pMap->getNodeUnchecked(iCenterX + 1, iCenterY + 1);
        if(pNode->iBlock[3] == iFloorTileGood)
            pNode->iBlock[3] = iFloorTileGoodCenter + 3;
    }

    // Set wall animations
    int iNextAnim = 1;
    THAnimation *pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim);
    THMapNode *pNode = pMap->getNodeUnchecked(iNewX, iNewY);
    pAnim->setAnimation(pAnims, iWallAnimTopCorner);
    pAnim->setFlags(THDF_ListBottom | (is_valid(entire_invalid, pNode) ? 0 : THDF_AltPalette));
    pAnim->attachToTile(pNode, 0);

    for(int iX = iNewX; iX < iNewX + iNewW; ++iX)
    {
        if(iX != iNewX)
        {
            pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim);
            pNode = pMap->getNodeUnchecked(iX, iNewY);
            pAnim->setAnimation(pAnims, iWallAnim);
            pAnim->setFlags(THDF_ListBottom | (is_valid(entire_invalid, pNode) ? 0 : THDF_AltPalette));
            pAnim->attachToTile(pNode, 0);
            pAnim->setPosition(0, 0);
        }
        pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim);
        pNode = pMap->getNodeUnchecked(iX, iNewY + iNewH - 1);
        pAnim->setAnimation(pAnims, iWallAnim);
        pAnim->setFlags(THDF_ListBottom | (is_valid(entire_invalid, pNode) ? 0 : THDF_AltPalette));
        pNode = pMap->getNodeUnchecked(iX, iNewY + iNewH);
        pAnim->attachToTile(pNode, 0);
        pAnim->setPosition(0, -1);
    }
    for(int iY = iNewY; iY < iNewY + iNewH; ++iY)
    {
        if(iY != iNewY)
        {
            pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim);
            pNode = pMap->getNodeUnchecked(iNewX, iY);
            pAnim->setAnimation(pAnims, iWallAnim);
            pAnim->setFlags(THDF_ListBottom | THDF_FlipHorizontal | (is_valid(entire_invalid, pNode) ? 0 : THDF_AltPalette));
            pAnim->attachToTile(pNode, 0);
            pAnim->setPosition(2, 0);
        }
        pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim);
        pNode = pMap->getNodeUnchecked(iNewX + iNewW - 1, iY);
        pAnim->setAnimation(pAnims, iWallAnim);
        pAnim->setFlags(THDF_ListBottom | THDF_FlipHorizontal | (is_valid(entire_invalid, pNode) ? 0 : THDF_AltPalette));
        pNode = pMap->getNodeUnchecked(iNewX + iNewW, iY);
        pAnim->attachToTile(pNode, 0);
        pAnim->setPosition(2, -1);
    }

    // Clear away extra animations
    int iAnimCount = (int)lua_objlen(L, 10);
    if(iAnimCount >= iNextAnim)
    {
        for(int i = iNextAnim; i <= iAnimCount; ++i)
        {
            pAnim = l_map_updateblueprint_getnextanim(L, iNextAnim);
            pAnim->removeFromTile();
            lua_pushnil(L);
            lua_rawseti(L, 10, i);
        }
    }

    lua_pushboolean(L, valid ? 1 : 0);
    return 1;
}
Beispiel #8
0
static int l_town_map_draw(lua_State *L)
{
    luaL_checktype(L, 1, LUA_TTABLE);
    THMap *pMap = luaT_testuserdata<THMap>(L, 2);
    THRenderTarget *pCanvas = luaT_testuserdata<THRenderTarget>(L, 3);
    int iCanvasXBase = luaL_checkint(L, 4);
    int iCanvasYBase = luaL_checkint(L, 5);
    bool bShowHeat = lua_toboolean(L, 6) != 0;

    uint32_t iColourMyHosp = pCanvas->mapColour(0, 0, 70);
    uint32_t iColourWall = pCanvas->mapColour(255, 255, 255);
    uint32_t iColourDoor = pCanvas->mapColour(200, 200, 200);
    uint32_t iColourPurchasable = pCanvas->mapColour(255, 0, 0);

    const THMapNode *pNode = pMap->getNodeUnchecked(0, 0);
    const THMapNode *pOriginalNode = pMap->getOriginalNodeUnchecked(0, 0);
    int iCanvasY = iCanvasYBase + 3;
    for(int iY = 0; iY < pMap->getHeight(); ++iY, iCanvasY += 3)
    {
        int iCanvasX = iCanvasXBase;
        for(int iX = 0; iX < pMap->getWidth(); ++iX, ++pNode, ++pOriginalNode, iCanvasX += 3)
        {
            if(pOriginalNode->iFlags & THMN_Hospital)
            {
                uint32_t iColour = iColourMyHosp;
                if(!(pNode->iFlags & THMN_Hospital))
                {
                    // TODO: Replace 1 with player number
                    if(pMap->isParcelPurchasable(pNode->iParcelId, 1))
                        iColour = iColourPurchasable;
                    else
                        goto dont_paint_tile;
                }
                else if(bShowHeat)
                {
                    uint16_t iTemp = pMap->getNodeTemperature(pNode);
                    if(iTemp < 5200) // Less than 4 degrees
                        iTemp = 0;
                    else if(iTemp > 32767) // More than 25 degrees
                        iTemp = 255;
                    else // NB: 108 == (32767 - 5200) / 255
                        iTemp = (iTemp - 5200) / 108;
                    iColour = pCanvas->mapColour(static_cast<uint8_t>(iTemp), 0, 70);
                }
                pCanvas->fillRect(iColour, iCanvasX, iCanvasY, 3, 3);
            }
            dont_paint_tile:
#define IsWall(blk) ((82 <= ((blk) & 0xFF)) && (((blk) & 0xFF) <= 164))
#define IsWallDrawn(n) pMap->getNodeOwner(pNode) != 0 ? \
    IsWall(pNode->iBlock[n]) : IsWall(pOriginalNode->iBlock[n])
            if(IsWallDrawn(1))
                pCanvas->fillRect(iColourWall, iCanvasX, iCanvasY, 3, 1);
            if(IsWallDrawn(2))
                pCanvas->fillRect(iColourWall, iCanvasX, iCanvasY, 1, 3);
#undef IsWallDrawn
#undef IsWall
            if(pNode->iFlags & THMN_DoorNorth)
                pCanvas->fillRect(iColourDoor, iCanvasX, iCanvasY - 2, 2, 3);
            if(pNode->iFlags & THMN_DoorWest)
                pCanvas->fillRect(iColourDoor, iCanvasX - 3, iCanvasY, 3, 2);
        }
    }

    return 0;
}
Beispiel #9
0
static int l_town_map_draw(lua_State *L)
{
    luaL_checktype(L, 1, LUA_TTABLE);
    THMap *pMap = luaT_testuserdata<THMap>(L, 2);
    THRenderTarget *pCanvas = luaT_testuserdata<THRenderTarget>(L, 3);
    int iCanvasXBase = luaL_checkint(L, 4);
    int iCanvasYBase = luaL_checkint(L, 5);
    bool bShowHeat = lua_toboolean(L, 6) != 0;

    uint32_t iColourMyHosp = pCanvas->mapColour(0, 0, 70);
    uint32_t iColourWall = pCanvas->mapColour(255, 255, 255);
    uint32_t iColourDoor = pCanvas->mapColour(200, 200, 200);
    uint32_t iColourPurchasable = pCanvas->mapColour(255, 0, 0);

    const THMapNode *pNode = pMap->getNodeUnchecked(0, 0);
    const THMapNode *pOriginalNode = pMap->getOriginalNodeUnchecked(0, 0);
    int iCanvasY = iCanvasYBase + 3;
    int iMapWidth = pMap->getWidth();
    for(int iY = 0; iY < pMap->getHeight(); ++iY, iCanvasY += 3)
    {
        int iCanvasX = iCanvasXBase;
        for(int iX = 0; iX < iMapWidth; ++iX, ++pNode, ++pOriginalNode, iCanvasX += 3)
        {
            if(pOriginalNode->iFlags & THMN_Hospital)
            {
                uint32_t iColour = iColourMyHosp;
                if(!(pNode->iFlags & THMN_Hospital))
                {
                    // TODO: Replace 1 with player number
                    if(pMap->isParcelPurchasable(pNode->iParcelId, 1))
                        iColour = iColourPurchasable;
                    else
                        goto dont_paint_tile;
                }
                else if(bShowHeat)
                {
                    uint16_t iTemp = pMap->getNodeTemperature(pNode);
                    if(iTemp < 5200) // Less than 4 degrees
                        iTemp = 0;
                    else if(iTemp > 32767) // More than 25 degrees
                        iTemp = 255;
                    else // NB: 108 == (32767 - 5200) / 255
                        iTemp = (iTemp - 5200) / 108;

#define MIN_OK_TEMP 140
#define MAX_OK_TEMP 180
#define RangeScale(low, high, val, start, end) \
    Clamp8(start + (end - start) * (val - low) / (high - low))
                    switch(pMap->getTemperatureDisplay())
                    {
                    case THMT_MultiColour:
                    {
                        uint8_t iR = 0;
                        uint8_t iG = 0;
                        uint8_t iB = 70;
                        if(iTemp < MIN_OK_TEMP)
                            iB = RangeScale(0, MIN_OK_TEMP - 1, iTemp, 200, 60);
                        else if(iTemp < MAX_OK_TEMP)
                            iG = RangeScale(MIN_OK_TEMP, MAX_OK_TEMP - 1, iTemp, 140, 224);
                        else
                            iR = RangeScale(MAX_OK_TEMP, 255, iTemp, 224, 255);
                        iColour = pCanvas->mapColour(iR, iG, iB);
                        break;
                    }
                    case THMT_YellowRed:
                        if(iTemp < MIN_OK_TEMP) // Below 11 degrees
                        {
                            uint8_t iR = RangeScale(0, MIN_OK_TEMP - 1, iTemp, 100, 213);
                            uint8_t iG = RangeScale(0, MIN_OK_TEMP - 1, iTemp, 80, 180);
                            iColour = pCanvas->mapColour(iR, iG, 0);
                        }
                        else
                        {
                            uint8_t iR = RangeScale(MIN_OK_TEMP, 255, iTemp, 223, 235);
                            uint8_t iG = RangeScale(MIN_OK_TEMP, 255, iTemp, 184, 104);
                            uint8_t iB = RangeScale(MIN_OK_TEMP, 255, iTemp, 0, 53);
                            iColour = pCanvas->mapColour(iR, iG, iB);
                        }
                        break;
                    default:
                    case THMT_Red:
                        iColour = pCanvas->mapColour(static_cast<uint8_t>(iTemp), 0, 70);
                        break;
                    }
#undef RangeScale
                }
                pCanvas->fillRect(iColour, iCanvasX, iCanvasY, 3, 3);
            }
            dont_paint_tile:
#define IsWall(blk) ((82 <= ((blk) & 0xFF)) && (((blk) & 0xFF) <= 164))
#define IsWallDrawn(n) pMap->getNodeOwner(pNode) != 0 ? \
    IsWall(pNode->iBlock[n]) : IsWall(pOriginalNode->iBlock[n])
            if(IsWallDrawn(1)) {
                pCanvas->fillRect(iColourWall, iCanvasX, iCanvasY, 3, 1);

                // Draw entrance door
                if((pNode-1)->iFlags >> 24 == THOB_EntranceRightDoor) {
                    if (pNode->iFlags & THMN_Hospital) {
                        pCanvas->fillRect(iColourDoor, iCanvasX-6, iCanvasY-2, 9, 3);
                    } else {
                        pCanvas->fillRect(iColourDoor, iCanvasX-6, iCanvasY, 9, 3);
                    }
                }
            }
            if(IsWallDrawn(2)) {
                pCanvas->fillRect(iColourWall, iCanvasX, iCanvasY, 1, 3);

                // Draw entrance door
                if((pNode-iMapWidth)->iFlags >> 24 == THOB_EntranceRightDoor) {
                    if (pNode->iFlags & THMN_Hospital) {
                        pCanvas->fillRect(iColourDoor, iCanvasX-2, iCanvasY-6, 3, 9);
                    } else {
                        pCanvas->fillRect(iColourDoor, iCanvasX, iCanvasY-6, 3, 9);
                    }
                }
            }
#undef IsWallDrawn
#undef IsWall
        }