File WfItemHelpers.c

File List > game > src > items > WfItemHelpers.c

Go to the documentation of this file

#include "WfItemHelpers.h"
#include "GameFramework.h"
#include "Game2DLayer.h"
#include <cglm/cglm.h>
#include "Entities.h"
#include "WfEntities.h"
#include <stdbool.h>
#include "AssertLib.h"
#include "WfTree.h"
#include "WfPlayer.h"
#include "Geometry.h"
#include "EntityQuadTree.h"

bool WfGetEntityGroundContactPoint(struct Entity2D* pEnt, vec2 outPoint)
{
    switch (pEnt->type)
    {
    case WfEntityType_Exit:
        // not implemented for this kind
        return false;
        break;
    case WfEntityType_WoodedArea:
    case WfEntityType_DebrisField:
        EASSERT("WfEntityType_WoodedArea and WfEntityType_DebrisField are transient and shouldn't be passed to this function normally" && false);
        return false;
    case WfEntityType_Tree:
        WfTreeGetGroundContactPoint(pEnt, outPoint);
        return true;
    case WfEntityType_Rock:
        EASSERT("Not implemented yet but will need to be so assert(false) as a reminder" && false);
        return false;
    case WfEntityType_Log:
        EASSERT("Not implemented yet but will need to be so assert(false) as a reminder" && false);
        return false;
    case WfEntityType_Player:
        WfPlayerGetGroundContactPoint(pEnt, outPoint);
        return true;
    }
    return false;
}

HTimer WfScheduleCallbackOnAnimation(struct Entity2D* pPlayer, struct GameFrameworkLayer* pLayer, 
    TimerCallbackFn callback,
    float percentageIntoAnimation,
    char* anim_name, 
    void* pCallbackUserData)
{
    /* delay the actual damage by a certain amount of time based on animation length */
    struct GameLayer2DData* pData = pLayer->userData;
    struct WfPlayerEntData* pEntData = WfGetPlayerEntData(pPlayer);
    struct AtlasAnimation* pCurrentAnim = At_FindAnim(pData->hAtlas, anim_name);
    float animLen = (float)VectorSize(pCurrentAnim->frames) / pCurrentAnim->fps;

    struct SDTimer timerDef = {
        .bActive = true,
        .bRepeat = false,
        .bAutoReset = false,
        .total = animLen * percentageIntoAnimation,
        .fnCallback = callback,
        .pUserData = pCallbackUserData,
        .elapsed = 0.0
    };
    HTimer timer = TP_GetTimer(&pData->timerPool, &timerDef);
    return timer;
}

VECTOR(struct Entity2D*) WfFindEntitiesWithinFan(
    struct WfSearchFan* pFan, 
    struct GameFrameworkLayer* pLayer, 
    struct GameLayer2DData* pData, 
    enum WfEntitySearchType searchType,
    VECTOR(struct Entity2D*) pEntityListOut)
{
    pEntityListOut = VectorClear(pEntityListOut);
    static VECTOR(HEntity2D) sFoundEnts = NULL;
    if(!sFoundEnts)
    {
        sFoundEnts = NEW_VECTOR(HEntity2D);
    }

    sFoundEnts = VectorClear(sFoundEnts);

    vec2 tl = {
        pFan->base[0] - pFan->length,
        pFan->base[1] - pFan->length,
    };
    vec2 br = {
        pFan->base[0] + pFan->length,
        pFan->base[1] + pFan->length,
    };

    if( searchType & WfStaticEntities)
    {
        sFoundEnts = Entity2DQuadTree_Query(pData->hEntitiesQuadTree, tl, br, sFoundEnts, &pData->entities, pLayer);
    }

    if(searchType & WfDynamicEntities)
    {
        sFoundEnts = Et2D_QueryDynEntities(pLayer, &pData->entities, tl, br, sFoundEnts);
    }

    int foundEnts = VectorSize(sFoundEnts);
    for(int i=0; i<foundEnts; i++)
    {
        HEntity2D hEnt = sFoundEnts[i];
        struct Entity2D* pEnt = Et2D_GetEntity(&pData->entities, hEnt);
        vec2 entityGroundPoint;
        bool bSuccess = WfGetEntityGroundContactPoint(pEnt, entityGroundPoint);
        if(!bSuccess)
        {
            continue;
        }
        float distance = Ge_DistanceBetweenPoints(pFan->base, entityGroundPoint);
        if(distance > pFan->length)
        {
            continue;
        }
        vec2 base2Ent;
        glm_vec2_sub(entityGroundPoint, pFan->base, base2Ent);
        float angle = Ge_AngleBetweenVec2s(pFan->direction, base2Ent);
        if(angle <= pFan->widthRadians)
        {
            pEntityListOut = VectorPush(pEntityListOut, &pEnt);
        }

    }
    return pEntityListOut;
}

void WfGetDirectionVector(enum WfDirection dir, vec2 outVec)
{
    static const vec2 dirs[NumDirections] = {
        { 0.0f,-1.0f}, // up
        { 0.0f, 1.0f}, // down
        {-1.0f, 0.0f}, // left
        { 1.0f, 0.0f}, // right
    };
    outVec[0] = dirs[dir][0];
    outVec[1] = dirs[dir][1];
}

struct Entity2D* WfFindClosestEntity(vec2 pointClosestTo, VECTOR(struct Entity2D*) pEnt)
{
    float distance = FLT_MAX;
    struct Entity2D* pRet = NULL;
    for(int i=0; i<VectorSize(pEnt); i++)
    {
        vec2 g;
        WfGetEntityGroundContactPoint(pEnt[i], g);
        float d = Ge_DistanceBetweenPoints(g, pointClosestTo);
        if(d < distance)
        {
            pRet = pEnt[i];
            distance = d;
        }
    }
    return pRet;
}

TileIndex* WfGetTileAtXY(struct TileMapLayer* pLayer, int x, int y)
{
    return pLayer->Tiles + (y * pLayer->widthTiles + x);
}

TileIndex* WfGetTileAtPoint(vec2 pt, struct GameLayer2DData* pData, int tileLayer, int* pXOut, int* pYOut)
{
    int iX = ((int)pt[0] / (int)pData->tilemap.layers[tileLayer].tileWidthPx);
    int iY = ((int)pt[1] / (int)pData->tilemap.layers[tileLayer].tileHeightPx);
    struct TileMapLayer* pLayer = &pData->tilemap.layers[tileLayer];
    TileIndex* pIndex = WfGetTileAtXY(pLayer, iX, iY);
    *pXOut = iX;
    *pYOut = iY;
    return pIndex;
}

TileIndex* WfGetTileInFrontOfPlayer(struct GameLayer2DData* pData, struct WfPlayerEntData* pPlayerData, float distanceInFront, HEntity2D hEntPlayer, int tileLayer, int* pXOut, int* pYOut)
{
    vec2 facingVec, pt;
    WfGetDirectionVector(pPlayerData->directionFacing, facingVec);
    vec2 playerGroundPos;
    struct Entity2D* pPlayerEnt = Et2D_GetEntity(&pData->entities, hEntPlayer);
    WfPlayerGetGroundContactPoint(pPlayerEnt, playerGroundPos);
    glm_vec2_scale(facingVec, distanceInFront, facingVec);
    glm_vec2_add(playerGroundPos, facingVec, pt);

    return WfGetTileAtPoint(pt, pData, tileLayer, pXOut, pYOut);
}

static bool IsIndexInSet(TileIndex index, TileIndex* indices, int numIndices)
{
    for(int i=0; i<numIndices; i++)
    {
        if(indices[i] == index)
        {
            return true;
        }
    }
    return false;
}

u8 WfGetTerrainLUTIndex(int tileX, int tileY, struct TileMap* tilemap, int layer, TileIndex* indices, int numIndices)
{
    u8 r = 0;
    struct TileMapLayer* pLayer = &tilemap->layers[layer];
    TileIndex indices_surrounding[8] = {
        *(WfGetTileAtXY(pLayer, tileX-1, tileY-1)),
        *(WfGetTileAtXY(pLayer, tileX,   tileY-1)),
        *(WfGetTileAtXY(pLayer, tileX+1, tileY-1)),

        *(WfGetTileAtXY(pLayer, tileX-1, tileY)),
        *(WfGetTileAtXY(pLayer, tileX,   tileY)),
        *(WfGetTileAtXY(pLayer, tileX+1, tileY)),

        *(WfGetTileAtXY(pLayer, tileX-1, tileY+1)),
        *(WfGetTileAtXY(pLayer, tileX,   tileY+1)),
        *(WfGetTileAtXY(pLayer, tileX+1, tileY+1)),
    };
    for(int i=0; i<8; i++)
    {
        if(IsIndexInSet(indices_surrounding[i], indices, numIndices))
        {
            r |= (1 << i);
        }
    }
    return r;
}