Source Development Resurrection at the place of death

zLuke

Active Pirate
Developer
Registered
LV
4
 
Joined
Jan 29, 2026
Messages
49
Reaction score
32
Points
38
Age
40

Resurrection at the place of death

1. Add to iteminfo.txt in client and server
Code:
15400    Sailor's Spirit    a7350    10130005    0    0    0    0    0    00    41    0    0    0    0    0    1    1    1    1    99    0    10000    -1    0    -1    0    0    -1    -1    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0    0    0,0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    Keep it in your inventory. Allows you to resurrect at the place of death. After resurrection, restores 1% HP    1   
15401    Pirate's Spirit    a7340    10130005    0    0    0    0    0    00    41    0    0    0    0    0    1    1    1    1    99    0    10000    -1    0    -1    0    0    -1    -1    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0    0    0,0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    Keep it in your inventory. Allows you to resurrect at the place of death. After resurrection, restores 10% HP    1   
15402    Captain's Spirit    a7353    10130005    0    0    0    0    0    00    41    0    0    0    0    0    1    1    1    1    99    0    10000    -1    0    -1    0    0    -1    -1    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0    0    0,0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    Keep it in your inventory. Allows you to resurrect at the place of death. After resurrection, restores 50% HP    1   
15403    Dead Man's Soul    a7341    10130005    0    0    0    0    0    00    41    0    0    0    0    0    1    1    1    1    99    0    10000    -1    0    -1    0    0    -1    -1    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0,0    0    0    0,0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    Keep it in your inventory. Allows you to resurrect at the place of death. After resurrection, restores 100% HP    1
2. Copy the item icon files from the archive texture.zip to the client's folder.
3. \Client\scripts\lua\forms\player.clu
search "frmRelive = UI_CreateForm"
Replace the resurrection form script with

C++:
frmRelive = UI_CreateForm( "frmRelive",  FALSE, 185, 101, 397, 500, TRUE, FALSE )
UI_LoadFormImage( frmRelive, "texture/ui/sure.dds", 185, 101, 0, 0, "", 0, 0 )
UI_ShowForm( frmRelive, FALSE )
UI_AddFormToTemplete( frmRelive, FORM_MAIN )
UI_SetFormStyle( frmRelive, 0 )
UI_SetIsDrag( frmRelive, TRUE )
 UI_FormSetIsEscClose( frmRelive, FALSE )
--UI_SetAlpha( frmRelive, 200 )
--UI_FormSetHotKey( frmRelive, ALT_KEY, HOTKEY_X )

labReCity = UI_CreateCompent( frmRelive, LABELEX_TYPE, "labReCity", 1, 1, 34, 34 )
UI_SetCaption( labReCity, "Revive \nin town?" )
UI_SetTextColor( labReCity, COLOR_BLACK)
UI_SetLabelExFont( labReCity, DEFAULT_FONT, TRUE, COLOR_WHITE )

labTitle = UI_CreateCompent( frmRelive, LABELEX_TYPE, "labTitle", 400, 150, 10, 4 )
UI_SetCaption( labTitle, "Revive")
UI_SetTextColor( labTitle, COLOR_BLACK )
UI_SetLabelExFont( labTitle, DEFAULT_FONT, TRUE, COLOR_WHITE )

btnReCity = UI_CreateCompent( frmRelive, BUTTON_TYPE, "btnReCity", 41, 19, 34, 78 )
UI_LoadButtonImage( btnReCity, "texture/ui/SystemBotton3.tga", 41, 19, 169, 39, FALSE )

btnReSpot = UI_CreateCompent( frmRelive, BUTTON_TYPE, "btnReSpot", 76, 19, 94, 78 )
UI_LoadButtonImage( btnReSpot, "texture/ui/Store8.tga", 76, 19, 0, 0, FALSE )

labReSpot = UI_CreateCompent( frmRelive, LABELEX_TYPE, "labReSpot", 41, 19, 104, 81 )
UI_SetCaption( labReSpot, "Resurrect")
UI_SetTextColor( labReSpot, COLOR_BLACK )
UI_SetLabelExFont( labReSpot, DEFAULT_FONT, TRUE, COLOR_WHITE )

imgResurrectItem = UI_CreateCompent( frmRelive, IMAGE_TYPE, "imgResurrectItem", 36, 36, 112 , 30 )
UI_LoadImage( imgResurrectItem, "texture/ui/Store6.tga", NORMAL, 36, 36, 157, 76 )

cmdResurrectItem = UI_CreateCompent( frmRelive, COMMAND_ONE_TYPE, "cmdResurrectItem", 32, 32, 114, 32 )
UI_SetIsShow( cmdResurrectItem, false )

4. \sources\Client\src\UIStartForm.cpp
Add at the beginning of the file after using namespace GUI;
C++:
// Item ID constants for resurrection at the place of death
// These values must match the constants on the server in exp_and_level.lua
#define ITEM_ID_RESURRECT_1    15400    // 1% HP
#define ITEM_ID_RESURRECT_10   15401    // 10% HP
#define ITEM_ID_RESURRECT_50   15402    // 50% HP
#define ITEM_ID_RESURRECT_100  15403    // 100% HP
// Countdown time for the on-site resurrection button (in seconds)
#define RESURRECT_COUNTDOWN_SECONDS  20
static DWORD g_dwResurrectCountdownStartTime = 0;

Replace the entire CStartMgr::_evtReliveFormMouseEvent (~str 771) function with
C++:
void CStartMgr::_evtReliveFormMouseEvent(CCompent *pSender, int nMsgType, int x, int y, DWORD dwKey)
{
    std::string name = pSender->GetName();

    if (name == "btnReCity")
    {
        CS_DieReturn(enumEPLAYER_RELIVE_CITY);
        pSender->GetForm()->SetIsShow(false);
        if (frmSelectOriginRelive)
        {
            frmSelectOriginRelive->SetIsShow(false);
            frmSelectOriginRelive = nullptr;
        }
    }
    else if (name == "btnReSpot")
    {
        // We send a request for resurrection at the place of death
        CS_DieReturn(enumEPLAYER_RELIVE_ITEM_ORIGIN);
        pSender->GetForm()->SetIsShow(false);
        if (frmSelectOriginRelive)
        {
            frmSelectOriginRelive->SetIsShow(false);
            frmSelectOriginRelive = nullptr;
        }
    }
}

Replace the entire CStartMgr::MainChaDied() (~str 1052) function with
C++:
void CStartMgr::MainChaDied()
{
    if( frmMainChaRelive )
    {
        int nLeft = ( g_pGameApp->GetWindowHeight() - frmMainChaRelive->GetWidth() ) / 2;
        int nTop = ( g_pGameApp->GetWindowHeight() - frmMainChaRelive->GetHeight() ) / 2;
        nTop-=80;
        frmMainChaRelive->SetPos( nLeft, nTop );
        frmMainChaRelive->Refresh();
        
        static CLabel* pInfo = dynamic_cast<CLabel*>( frmMainChaRelive->Find( "labReCity" ) );   
        CCharacter* pCha = CGameScene::GetMainCha();
        bool IsShow = true;
        if( pInfo && pCha )
        {
            if( pCha->IsBoat() )
            {
                pInfo->SetCaption( g_oLangRec.GetString(761) );               
            }
            else
            {
                pInfo->SetCaption( "Revive \nin town?" );

                if( CGameScene* pScene = CGameApp::GetCurScene() )
                {
                    if( CMapInfo *pInfo = pScene->GetCurMapInfo() )
                    {
                        // Modify by lark.li 20080719 begin
                        //if( stricmp( pInfo->szDataName, "teampk" )==0 )
                        if( stricmp( pInfo->szDataName, "teampk" )==0 || stricmp( pInfo->szDataName,"starena1") == 0
                            || stricmp( pInfo->szDataName,"starena2") == 0 || stricmp( pInfo->szDataName,"starena3") == 0)
                            IsShow = false;
                        // End
                    }
                }
            }
        }

        CUIInterface::MainChaMove();

        g_stUITrade.CloseAllForm();

        CWorldScene* pWorldScene = dynamic_cast<CWorldScene*>(g_pGameApp->GetCurScene());
        if(pWorldScene && pWorldScene->GetShipMgr())
        {
            pWorldScene->GetShipMgr()->CloseForm();
        }

        // Checking for items to resurrect at the place of death
        static CTextButton* pBtnReSpot = dynamic_cast<CTextButton*>(frmMainChaRelive->Find("btnReSpot"));
        static COneCommand* cmdResurrectItem = dynamic_cast<COneCommand*>(frmMainChaRelive->Find("cmdResurrectItem"));

        if (cmdResurrectItem)
        {
            cmdResurrectItem->SetIsDrag(false);
        }

        if (pBtnReSpot && cmdResurrectItem)
        {
            // Array of item IDs for resurrection (from smallest to largest)
            const short sResurrectItemIDs[] = {
                ITEM_ID_RESURRECT_1,   // 1% HP
                ITEM_ID_RESURRECT_10,  // 10% HP
                ITEM_ID_RESURRECT_50,  // 50% HP
                ITEM_ID_RESURRECT_100  // 100% HP
            };

            short sFoundItemID = 0;
            short sFoundItemCount = 0;

            // Search for the item with the highest ID (the most powerful)
            // Traverse the array in reverse order (from highest to lowest)
            for (int i = 3; i >= 0; i--)
            {
                short sItemID = sResurrectItemIDs[i];
                short sCount = g_stUIEquip.GetItemCount(sItemID);
                if (sCount > 0)
                {
                    sFoundItemID = sItemID;
                    sFoundItemCount = sCount;
                    break;
                }
            }

            bool bHasItem = (sFoundItemID > 0);

            // Initialize the countdown when the character dies
            static CLabel* labReSpot = dynamic_cast<CLabel*>(frmMainChaRelive->Find("labReSpot"));
            if (bHasItem && pBtnReSpot)
            {
                g_dwResurrectCountdownStartTime = CGameApp::GetCurTick();
                pBtnReSpot->SetIsEnabled(false);  // The button is inactive during the countdown
                char szCaption[64];
                sprintf(szCaption, "%d", RESURRECT_COUNTDOWN_SECONDS);
                labReSpot->SetCaption(szCaption);
            }
            else if (pBtnReSpot)
            {
                pBtnReSpot->SetIsEnabled(false);
                labReSpot->SetCaption("Resurrect");
                g_dwResurrectCountdownStartTime = 0;  // Reset the timer if there is no item
            }

            // Clearing the previous item
            if (cmdResurrectItem)
            {
                cmdResurrectItem->DelCommand();
                cmdResurrectItem->SetIsShow(false);
            }

            if (bHasItem && cmdResurrectItem)
            {
                CItemRecord* pItemRec = GetItemRecordInfo(sFoundItemID);
                if (pItemRec)
                {
                    CItemCommand* pItem = new CItemCommand(pItemRec);

                    if (pItem->GetData().sID == 0)
                    {
                        pItem->GetData().sID = (short)pItemRec->lID;
                    }

                    pItem->GetData().sNum = sFoundItemCount;

                    pItem->SetOwnDefText("");

                    pItem->SetCanDrag(false);

                    cmdResurrectItem->AddCommand(pItem);
                    cmdResurrectItem->SetIsShow(true);
                }
            }
        }

        if( IsShow ) frmMainChaRelive->Show();
    }
}

Add to the beginning of the function CStartMgr::FrameMove
C++:
// Update the countdown for the resurrection button in place
if (frmMainChaRelive && frmMainChaRelive->GetIsShow() && g_dwResurrectCountdownStartTime > 0)
{
    static CTextButton* pBtnReSpot = dynamic_cast<CTextButton*>(frmMainChaRelive->Find("btnReSpot"));
    static CLabel* labReSpot = dynamic_cast<CLabel*>(frmMainChaRelive->Find("labReSpot"));

    if (labReSpot)
    {
        DWORD dwElapsed = dwTime - g_dwResurrectCountdownStartTime;
        int nSecondsRemaining = RESURRECT_COUNTDOWN_SECONDS - (int)(dwElapsed / 1000);

        if (nSecondsRemaining > 0)
        {
            // Update the countdown button text
            char szCaption[64];
            sprintf(szCaption, "   %d", nSecondsRemaining);
            labReSpot->SetCaption(szCaption);
            pBtnReSpot->SetIsEnabled(false);
        }
        else
        {
            // Time has expired - we make the button active
            labReSpot->SetCaption("Resurrect");
            pBtnReSpot->SetIsEnabled(true);
            g_dwResurrectCountdownStartTime = 0;
        }
    }
}

5. \sources\Libraries\common\include\CompCommand.h
Search enum EPlayerReliveType (~str 284)
Add to the end of the enumeration
C++:
enumEPLAYER_RELIVE_ITEM_ORIGIN,

6. \sources\Server\GameServer\src\Character.h
Search m_chReliveLv; (~str 789)
Add to next string
C++:
bool    m_bReliveByItem;

7. \sources\Server\GameServer\src\Character.cpp
Search m_chReliveLv = 0; (~str 112)
Add to next string
C++:
m_bReliveByItem = false;

Search (~str 1487)
C++:
else if (m_chSelRelive == enumEPLAYER_RELIVE_ORIGIN)
Replace the entire code block before the line else if (m_chSelRelive == enumEPLAYER_RELIVE_MAP) with
C++:
else if (m_chSelRelive == enumEPLAYER_RELIVE_ORIGIN)
{
                if (m_chReliveLv > 0)
                {
                    SubMap    *pCMap = GetSubMap();
                    GetSubMap()->GoOut(this);
                    SetExistState(enumEXISTS_NATALITY);
                    //m_timerScripts.Reset();

                    m_chSelRelive = enumEPLAYER_RELIVE_NONE;
                    
                    if (m_bReliveByItem) // Check the new flag
                    {
                        g_CParser.DoString("Relive_now_item", enumSCRIPT_RETURN_NONE, 0,
                            enumSCRIPT_PARAM_LIGHTUSERDATA, 1, this,
                            enumSCRIPT_PARAM_NUMBER, 1, m_chReliveLv, DOSTRING_PARAM_END);
                    }
                    else
                    {
                        g_CParser.DoString("Relive_now", enumSCRIPT_RETURN_NONE, 0,
                            enumSCRIPT_PARAM_LIGHTUSERDATA, 1, this,
                            enumSCRIPT_PARAM_NUMBER, 1, m_chReliveLv, DOSTRING_PARAM_END);
                    }
                    m_bReliveByItem = false; // Reset flag after use
                    if (getAttr(ATTR_HP) <= 0)
                        LG("renascence compute error", "character %s(%d)after renascence compute HP is unlawful\n", GetLogName(), getAttr(ATTR_JOB));
                    SwitchMap(pCMap, pCMap->GetName(), GetPos().x, GetPos().y, false, enumSWITCHMAP_DIE, pCMap->GetCopyNO());
                }
}

8. \sources\Server\GameServer\src\CharacterPrl.cpp
Search (~str 317)
C++:
case CMD_CM_DIE_RETURN:
Replace the entire code block before the line case CMD_CM_SAY: with
C++:
case CMD_CM_DIE_RETURN:
{
    Char chReliveType = READ_CHAR(pk);

    if (chReliveType == enumEPLAYER_RELIVE_CITY)
    {
        GetPlyMainCha()->ResetChaRelive();
        m_chSelRelive = enumEPLAYER_RELIVE_CITY;
        m_bReliveByItem = false;
    }
    else if (chReliveType == enumEPLAYER_RELIVE_ORIGIN)
    {
        GetPlyMainCha()->ResetChaRelive();
        m_chSelRelive = enumEPLAYER_RELIVE_ORIGIN;
        m_bReliveByItem = false;
    }
    else if (chReliveType == enumEPLAYER_RELIVE_ITEM_ORIGIN)
    {
        bool bSuccess = false;
        short sItemID = 0;
        short sHPPercent = 0;

        g_CParser.DoString("CheckAndUseResurrectItem", enumSCRIPT_RETURN_NUMBER, 3,
            enumSCRIPT_PARAM_LIGHTUSERDATA, 1, this, DOSTRING_PARAM_END);
        sItemID = (short)g_CParser.GetReturnNumber(1);
        sHPPercent = (short)g_CParser.GetReturnNumber(2);
        bSuccess = ((g_CParser.GetReturnNumber(0) == 1) || (sItemID > 0 && sHPPercent > 0));

        if (bSuccess && sHPPercent > 0)
        {
            m_chSelRelive = enumEPLAYER_RELIVE_ORIGIN;
            m_chReliveLv = (Char)sHPPercent;
            m_bReliveByItem = true;
        }
        else
        {
            GetPlyMainCha()->ResetChaRelive();
            m_chSelRelive = enumEPLAYER_RELIVE_NONE;
            m_bReliveByItem = false;
        }
    }
    else if (chReliveType == enumEPLAYER_RELIVE_NORIGIN)
    {
        GetPlyMainCha()->ResetChaRelive();
        SetRelive(enumEPLAYER_RELIVE_ORIGIN, 0);
        m_bReliveByItem = false;
    }
    break;
}

9. \server\GameServer\resource\script\calculate\exp_and_level.lua
Add to the end of the file
C++:
-- Defining the ID of items for on-site resurrection (must be set in the configuration)
-- These values must match the constants on the client in UIStartForm.cpp
ITEM_ID_RESURRECT_1 = 15400   -- 1% HP
ITEM_ID_RESURRECT_10 = 15401  -- 10% HP
ITEM_ID_RESURRECT_50 = 15402  -- 50% HP
ITEM_ID_RESURRECT_100 = 15403 -- 100% HP

RESURRECT_ITEM_IDS = {
    ITEM_ID_RESURRECT_1,
    ITEM_ID_RESURRECT_10,
    ITEM_ID_RESURRECT_50,
    ITEM_ID_RESURRECT_100
}

RESURRECT_HP_PERCENTS = {
    [1] = 1,
    [2] = 10,
    [3] = 50,
    [4] = 100
}

-- List of maps where resurrection at the place of death is prohibited
local FORBIDDEN_RESURRECT_MAPS = {
    "guildwar",
    -- Add other maps as needed.
    -- "map_name_2",
    -- "map_name_3",
}

-- Checking and using the item for resurrection on the spot
-- Return: success (number 0/1), itemID (number), hpPercent (number)
function CheckAndUseResurrectItem(role)
    local cha_role = TurnToCha(role)
    
    local map_name = GetChaMapName(cha_role)
    for i = 1, #FORBIDDEN_RESURRECT_MAPS do
        if map_name == FORBIDDEN_RESURRECT_MAPS[i] then
            SystemNotice(cha_role, "Resurrection at the place of death is not allowed on this map")
            return 0, 0, 0
        end
    end
    
    local foundItemID = 0
    local foundItemIndex = 0

    for i = #RESURRECT_ITEM_IDS, 1, -1 do
        local itemID = RESURRECT_ITEM_IDS[i]
        local itemCount = CheckBagItem(cha_role, itemID)
        if itemCount and itemCount > 0 then
            foundItemID = itemID
            foundItemIndex = i
            break
        end
    end

    if foundItemID == 0 then
        SystemNotice(cha_role, "You need an item to resurrect at the place of death")
        return 0, 0, 0
    end

    local ret = DelBagItem(cha_role, foundItemID, 1)
    if ret ~= 1 then 
        SystemNotice(cha_role, "Error when using the resurrection item")
        return 0, 0, 0
    end

    local hpPercent = RESURRECT_HP_PERCENTS[foundItemIndex]
    return 1, foundItemID, hpPercent
end

-- On-site resurrection using an item (percentage HP/SP restoration)
function Relive_now_item(role, hpPercent)
    local cha_role = TurnToCha(role)
    local mxhp = Mxhp(cha_role)
    local mxsp = Mxsp(cha_role)

    local hp = math.max(1, math.floor((hpPercent / 100.0) * mxhp))
    local sp = math.max(1, math.floor((hpPercent / 100.0) * mxsp))
    
    SetCharaAttr(hp, cha_role, ATTR_HP)
    SetCharaAttr(sp, cha_role, ATTR_SP)
end

Compile the client and server. Compile the tables in the client, and the clu scripts.
Enjoy!!!
2026 (c) zLuke
 

Attachments

Disable on-site resurrection if the character is on a ship, as it doesn't work anyway.
Replace in the CStartMgr::_evtReliveFormMouseEvent (~str 785) function
C++:
else if (name == "btnReSpot")
{
    // We send a request for resurrection at the place of death
    CS_DieReturn(enumEPLAYER_RELIVE_ITEM_ORIGIN);
on
C++:
else if (name == "btnReSpot")
{
    CCharacter* pMainCha = CGameScene::GetMainCha();
        if (pMainCha && pMainCha->IsBoat())
        {
            return;
        }
    // We send a request for resurrection at the place of death
    CS_DieReturn(enumEPLAYER_RELIVE_ITEM_ORIGIN);

Replace in the CStartMgr::MainChaDied() (~str 1109) function
C++:
if (cmdResurrectItem)
{
    cmdResurrectItem->SetIsDrag(false);
}

if (pBtnReSpot && cmdResurrectItem)
on
C++:
if (cmdResurrectItem)
{
    cmdResurrectItem->SetIsDrag(false);
}
// Do not allow item resurrection on boats: hide button and icon completely.
const bool bCanShowResurrectOnSpot = (pCha && !pCha->IsBoat());
if (pBtnReSpot && cmdResurrectItem)

Replace in the CStartMgr::MainChaDied() (~str 1144) function
C++:
// Initialize the countdown when the character dies
static CLabel* labReSpot = dynamic_cast<CLabel*>(frmMainChaRelive->Find("labReSpot"));
if (bHasItem && pBtnReSpot)
on
C++:
// Initialize the countdown when the character dies
static CLabel* labReSpot = dynamic_cast<CLabel*>(frmMainChaRelive->Find("labReSpot"));
if (!bCanShowResurrectOnSpot)
{
    pBtnReSpot->SetIsEnabled(false);
    pBtnReSpot->SetCaption("");
    g_dwResurrectCountdownStartTime = 0;
}
else if (bHasItem && pBtnReSpot)

Replace in the CStartMgr::MainChaDied() (~str 1174) function
C++:
if (bHasItem && cmdResurrectItem)
on
C++:
if (bCanShowResurrectOnSpot && bHasItem && cmdResurrectItem)