Ranch/Yard System

Got any custom JavaScript additions/tweaks you think other people would like to see? Post 'em here!
Post Reply
dragon slayer
UOX3 Guru
Posts: 776
Joined: Thu Dec 21, 2006 7:37 am
Has thanked: 4 times
Been thanked: 26 times

Ranch/Yard System

Post by dragon slayer »

Ranch Stone & Fencing System for UOX3

I’m excited to share a brand-new system for UOX3 that brings player-owned ranches to life! This system allows players to claim, manage, and fence off their own ranching area, directly in-game.

📌 Features:

Ranch Stone

Acts as the heart of your ranch.

Displays ranch details such as owner, size, and area coverage.

Ranch size is upgradeable, paving the way for future expansions.

Custom Fencing System

Players can craft or acquire a Fencing Hammer.

Use the hammer to “set” fence pieces (posts, corners, straights) into the ground.

Fence pieces are validated to ensure they are within your ranch boundary before becoming immovable.

Ownership & Range Checks

Only the ranch owner (or co-owners, if added later) can place fences tied to their stone.

Proper range validation ensures you can’t place or secure fences outside of your ranch’s radius.

Prevents abuse by checking that players are within their stone’s defined area, not just a fixed tile distance.

Upgradeable System

Designed with future expansions in mind:

Larger ranch sizes.

Additional fence types and visuals.

Possible add-ons like gates, barns, or animal handling features.

🛠 Technical Notes:

Makes use of UOX3’s CalcMultiFromSer and FindMulti functions to ensure ranches integrate properly with multi-structures.

Ranch Stones store their size/area data as tags for easy upgrades and future persistence.

Fences become static (non-movable) once hammered in within valid ranch boundaries.

Built entirely in UOX3’s SpiderMonkey 1.8.5 JS engine for easy modification and shard customization.

This system provides a great foundation for roleplay, farming, and animal management features while keeping expansion possibilities wide open. Perfect for shards looking to add depth to housing and land ownership beyond standard homes.
[ranchdeed]
{
get=base_item
name=ranchdeed
id=0x14F0
script=19602
}

[ranchstone]
{
get=base_item
name=ranchstone
id=0xED6
movable=0
script=19602
decay=0
}

[ranchupgrade]
{
get=base_item
id=0x14F0
name=Ranch Size Upgrade
script=19602
}

[Fence]
{
get=base_fence
name=wooden fence
id=0x088A
weight=100
}
[Fencetwo]
{
get=base_fence
name=wooden fence
id=0x088B
weight=100
}
[FenceCorner]
{
get=base_fence
name=wooden fence
id=0x0862
weight=100
}
[FencePost]
{
get=base_fence
name=wooden fence
id=0x085F
weight=100
}

[fencinghammer]
{
get=0x0fb4_lbr
name=fencing hammer
weight=900
value=32 16
damage=12 38
hp=31 60
spd=15
str=30
script=19603
}
// ============================================================================
// Fencing Hammer (UOX3 - SpiderMonkey 1.8.5)
// ScriptID: 19603
// File: js/custom/fencinghammer.js
// ============================================================================

var FENCE_TAG = "ranchStoneSerial";     // set on fence when “hammered in”
var STONE_TAG = "ranchStoneSerial";     // stored on hammer to bind it to a stone
var RANGE_TO_STONE_USE = 10;            // working range for targeting
var RANGE_RENAME = 5;                   // “in pack & near stone” quick rename distance
// --- Add near the top with your other constants ---
var FENCE_SECTIONS = {
    "Fence": true,
    "Fencetwo": true,
    "FenceCorner": true,
    "FencePost": true
};

function GetRanchSize( iStone )
{
    var v = parseInt( iStone.GetTag( "ranchSize" ), 10 );
    if( isNaN( v ) || v <= 0 )
        v = SIZE_DEFAULT || 10; // fallback if constants not shared here
    return v;
}

// Recognize a valid fence/gate item by sectionID
function IsWhitelistedFence( it )
{
    return ( it && it.isItem && !!FENCE_SECTIONS[ it.sectionID ] );
}

function GetBoundStoneFromHammer( hammer )
{
    if( !ValidateObject( hammer )) return null;
    var ser = parseInt( hammer.GetTag( STONE_TAG ), 10 );
    if( !ser || ser <= 0 ) return null;

    // Try to locate the stone by serial
    var stone = CalcItemFromSer ? CalcItemFromSer( ser ) : null;
    if( ValidateObject( stone )) return stone;

    // Fallback: if not resolvable by serial, at least ensure player is in same multi as stored coords
    return null;
}

function IsOwnerNearStone( pChar, stone, maxRange )
{
    if( !ValidateObject( pChar ) || !ValidateObject( stone )) return false;
    if( pChar.serial != parseInt( stone.GetTag( "ownerSerial" ), 10 )) return false;
    return stone.InRange( pChar, maxRange|0 );
}

// Optional: require same house (multi) as stone
function IsSameHouseAsStone( who, stone )
{
    var mStone = FindMulti( stone );
    var mUser  = FindMulti( who );
    if( !mStone || !mUser ) return false;
    // Basic equality (many shards just compare pointers or serials if exposed)
    return ( mStone.serial && mUser.serial && ( mStone.serial == mUser.serial ));
}

function IsPlayerInsideRanch( pUser, stone )
{
    if( !ValidateObject(pUser) || !ValidateObject(stone) )
        return false;

    var radius = TriggerEvent( 19602, "GetRanchSize", stone );
    return pUser.InRange(stone, radius);
}

// --- Main use handler ---
function onUseChecked( pUser, iUsed )
{
    if( !iUsed || !iUsed.isItem ) return false;

    // Only respond to fencing hammer section
    if( iUsed.sectionID != "fencinghammer" )
        return false;

    var socket = pUser.socket;
    var stone  = GetBoundStoneFromHammer( iUsed );

    // If hammer is in pack and near the bound stone, allow quick rename via stone
    if( iUsed.container && iUsed.container.isItem && iUsed.container == pUser.pack )
    {
        if( ValidateObject( stone ) && IsOwnerNearStone( pUser, stone, RANGE_RENAME ))
        {
            // Let the stone’s normal menu handle rename; feels like RunUO’s prompt
            socket.SysMessage( "Opening ranch menu for renaming..." );
            socket.tempObj = stone;
            TriggerEvent( 19602, "OpenRanchStoneGump", pUser, stone, 1, null );
            return false;
        }
        // If not near stone, just message
        socket.SysMessage( "Equip the hammer to work on fences, or stand near your ranch stone to rename." );
        return false;
    }

    // Must be equipped to target fences/gates
    if( iUsed.container != pUser )
    {
        socket.SysMessage( "You must equip that in order to use it." );
        return false;
    }

    // Bound stone present & in range?
    if( !ValidateObject( stone ))
    {
        socket.SysMessage( "This hammer is not bound to a ranch stone. Claim one from your ranch stone." );
        return false;
    }
var ranchSize = TriggerEvent( 19602, "GetRanchSize", stone );
if( !IsPlayerInsideRanch(pUser, stone) )
{
    // Double-tier warning
    if( pUser.InRange(stone, ranchSize + 10) )
        socket.SysMessage("You are WELL out of range of your Ranch Stone!");
    else
        socket.SysMessage("You are out of range of your Ranch Stone.");
        socket.SysMessage("Stone. " + stone);
    return false;
}

    // Optional house check – uncomment if you want to require working inside same house:
    // if( !IsSameHouseAsStone( pUser, stone )) { socket.SysMessage("You must be inside your ranch house."); return true; }

    socket.CustomTarget( 0, "Target the fence or gate to hammer in (or knock free)." );
    // Remember which hammer is asking
    pUser.SetTempTag( "fh_ser", iUsed.serial.toString() );
    return false;
}

// Target callback
function onCallback0( pSock, myTarget )
{
    var pUser  = pSock.currentChar;
    var fhSer  = parseInt( pUser.GetTempTag( "fh_ser" ) || "0", 10 );
    pUser.SetTempTag( "fh_ser", "" );

    if( !fhSer ) return;
    var hammer = CalcItemFromSer ? CalcItemFromSer( fhSer ) : null;
    if( !ValidateObject( hammer )) return;

    var stone = GetBoundStoneFromHammer( hammer );
    if( !ValidateObject( stone )) { pSock.SysMessage("This hammer is no longer bound to a ranch."); return; }

    var r = TriggerEvent( 19602, "GetRanchSize", stone );
    if( !myTarget.InRange( stone, r ) )
    {
        pSock.SysMessage( "That fence is outside your ranch boundary (size " + r + ")." );
        return;
    }

    // If the player targets the ranch stone itself: open rename UI
    if( myTarget && myTarget.isItem && myTarget.sectionID == stone.sectionID && myTarget.serial == stone.serial )
    {

        TriggerEvent( 19602, "OpenRanchStoneGump", pUser, stone, 1, null );
        return;
    }

    // Expecting a fence/gate item. We’ll accept any item and toggle if allowed.
    if( !myTarget || !myTarget.isItem )
    {
        pSock.SysMessage( "You can't do that." );
        return;
    }

    // Only allow the 4 fence sections you specified
    if( !IsWhitelistedFence( myTarget ))
    {
        pSock.SysMessage( "You can only use this on ranch fence pieces." );
        return;
    }


    // Toggle movable and set/clear ranch tag
    // (Your shard may limit which sectionIDs are valid; you can whitelist if desired.)
    if( myTarget.movable == 1 )
    {
        // Trying to hammer in (lock) must be within ranch radius from the stone
        var radius = TriggerEvent( 19602, "GetRanchSize", stone );
        if( !myTarget.InRange( stone, radius ) ) // or stone.InRange(myTarget, radius)
        {
            pSock.SysMessage( "That fence is outside your ranch boundary (size " + radius + ")." );
            return;
        }
        pUser.SoundEffect( 0x0136, true );         // “hammer in”
        myTarget.movable = 2;
        myTarget.decayable = false;
        myTarget.Refresh();
        myTarget.SetTag( FENCE_TAG, stone.serial );
        pSock.SysMessage( "You set the fence into the ground." );
    }
    else
    {
        pUser.SoundEffect( 0x013F, true );         // “knock free”
        myTarget.movable = 1;
        myTarget.decayable = true;
        myTarget.Refresh();
        myTarget.SetTag( FENCE_TAG, null );
        pSock.SysMessage( "You knock it free from the ground." );
    }
}
// ============================================================================
// RanchStone System for UOX3 (SpiderMonkey 1.8.5)
// ScriptID: 19602
// File: js/custom/ranchstone.js
// ============================================================================

// ------------------------------
// Config
// ------------------------------
var RANCH_STONE_SECTION  = "ranchstone";
var RANCH_DEED_SECTION   = "ranchdeed";
var NEARBY_PLAYER_RANGE  = 12;
var TITLE_MAXLEN         = 24;
var SIZE_DEFAULT        = 10;      // starting radius
var SIZE_STEP           = 5;       // how much each upgrade adds
var SIZE_MAX            = 50;      // hard cap (tune as you like)
var UPGRADE_SECTION     = "ranchupgrade"; // DFN section name for the upgrade token/deed
var GUMP_W               = 300;
var GUMP_H               = 260;
var FENCING_HAMMER_SECTION = "fencinghammer"; // DFN for the hammer item

// ------------------------------
// Helpers
// ------------------------------

function GetMultiAtObject( obj )
{
    // returns MULTI or null
    if( !obj ) return null;
    return FindMulti( obj ); // easiest form: pass the object
}

function GetMultiAtCoords( x, y, z, world, instanceID )
{
    // returns MULTI or null
    if( typeof instanceID === "number" )
        return FindMulti( x, y, z, world, instanceID );
    return FindMulti( x, y, z, world ); // common case
}
function IsBadPlacementRegion( region )
{
    if( !region )
        return true;

    // Adjust to your rules
    if( region.town )
        return true;
    if( region.guarded )
        return true;
    if( region.dungeon )
        return true;
    if( region.house )
        return true;

    return false;
}

function InFrontOf( pUser )
{
    var x = pUser.x;
    var y = pUser.y;

    switch( pUser.dir )
    {
        case 0: y -= 1; break; // N
        case 1: x += 1; break; // E
        case 2: y += 1; break; // S
        case 3: x -= 1; break; // W
        case 4: y -= 1; break; // NE
        case 5: x += 1; break; // SE
        case 6: y += 1; break; // SW
        case 7: x -= 1; break; // NW
    }
    return { x: x, y: y, z: pUser.z };
}

function MakeDefaultRanchName( pUser )
{
    return ( pUser && pUser.name ? pUser.name : "Player" ) + "'s Ranch";
}

function ValidateOwner( pChar, iStone )
{
    if( !ValidateObject( pChar ) || !ValidateObject( iStone ))
        return false;

    var ownerSer = parseInt( iStone.GetTag( "ownerSerial" ), 10 );
    return ownerSer === pChar.serial;
}

function GetNearbyPlayers( pUser, range )
{
    var list = [];
    if( !ValidateObject( pUser ))
        return list;

    if( typeof AreaCharFunction === "function" )
    {
        AreaCharFunction( pUser, range, function( ch )
        {
            if( ch && ch.isChar && ch.online && ch.serial !== pUser.serial )
                list.push( ch );
            return false; // continue
        });
    }
    return list;
}

function MakeTransferBtnId( idx ){ return 100 + idx; }
function IsTransferBtnId( btn ){ return btn >= 100 && btn < 150; } // up to 50 entries
function TransferIdxFromBtn( btn ){ return btn - 100; }

function GetRanchSize( iStone )
{
    var v = parseInt( iStone.GetTag( "ranchSize" ), 10 );
    if( isNaN( v ) || v <= 0 )
        v = SIZE_DEFAULT;
    return v;
}

function SetRanchSize( iStone, size )
{
    if( size < 1 ) size = 1;
    if( size > SIZE_MAX ) size = SIZE_MAX;
    iStone.SetTag( "ranchSize", size );
}

function CalcRanchArea( size )
{
    return Math.floor( size * size * 3.14159 );
}

function FindPackItemBySection( pUser, sectionID )
{
    var pack = pUser ? pUser.pack : null;
    if( !ValidateObject( pack ))
        return null;

    var it;
    for( it = pack.FirstItem(); !pack.FinishedItems(); it = pack.NextItem() )
    {
        if( !ValidateObject( it )) continue;
        if( it.sectionID == sectionID )
            return it;
    }
    return null;
}

function TryUpgradeRanchSize( pSock, pUser, iStone )
{
    var cur = GetRanchSize( iStone );
    if( cur >= SIZE_MAX )
    {
        pSock.SysMessage( "This ranch is already at maximum size." );
        return false;
    }

    // Require an upgrade token in the backpack
    var token = FindPackItemBySection( pUser, UPGRADE_SECTION );
    if( !ValidateObject( token ))
    {
        pSock.SysMessage( "You need a Ranch Size Upgrade to increase size." );
        return false;
    }

    // Consume token and increase size
    token.Delete();
    var next = cur + SIZE_STEP;
    if( next > SIZE_MAX ) next = SIZE_MAX;

    SetRanchSize( iStone, next );
    pSock.SysMessage( "Ranch size increased to " + next + " (area " + CalcRanchArea( next ) + ")." );
    return true;
}

// ------------------------------
// Gump
// ------------------------------
function OpenRanchStoneGump( pUser, iStone, page, playersCache )
{
    if( !ValidateObject( pUser ) || !ValidateObject( iStone ))
        return;

    // Fetch and show size/area
    var ranchSize = GetRanchSize( iStone );
    var ranchArea = CalcRanchArea( ranchSize );

    if( page !== 2 )
        page = 1;

    var g = new Gump;

    g.AddBackground( 0, 0, GUMP_W, GUMP_H, 9200 );
    //g.AddCheckerTrans( 8, 8, GUMP_W - 16, GUMP_H - 16 );

    var ranchName = iStone.GetTag( "ranchName" ) || "Ranch";
    var ownerSer  = parseInt( iStone.GetTag( "ownerSerial" ), 10 );
    var header    = ranchName + " (Owner: " + ( ownerSer ? ( "0x" + ownerSer.toString( 16 ).toUpperCase()) : "Unset" ) + ")";

    g.AddText( 16, 16, 0, header ); // TextID 0

    if( page === 1 )
    {
        g.AddText( 16, 48, 0, "Rename:" ); // TextID 1

        g.AddButton( 16, 80, 1209, 1, 1, 0, 1 );  g.AddText( 42, 82, 0, "Save Name" );           // pButton=1
        g.AddButton( 16, 110, 1209, 1, 1, 0, 4 );  g.AddText( 42, 112, 0, "Upgrade Size" );        // pButton=4  <-- NE
        g.AddButton( 160, 110, 1209, 1, 1, 0, 5 );  g.AddText( 186, 112, 0, "Get Hammer" ); // pButton=5
        g.AddButton( 16, 140, 1209, 1, 1, 0, 2 ); g.AddText( 42, 142, 0, "Redeed Ranch" );       // pButton=2
        g.AddButton( 16, 210, 1209, 1, 1, 0, 3 ); g.AddText( 42, 212, 0, "Transfer Ownership" ); // pButton=3
        g.AddButton( 200, 210, 0xA50, 1, 1, 0, 0 ); g.AddText( 226, 212, 0, "Close" );             // pButton=0

        g.AddText( 16, 180, 0, "Size: " + ranchSize ); // like AddLabel in RunUO
        g.AddText( 120, 180, 0, "Area: " + ranchArea );

        g.AddTextEntryLimited( 80, 46, 200, 20, 0, 1, 10, ranchName, TITLE_MAXLEN ); // textID=2
    }
    else
    {
        g.AddText( 16, 48, 0, "Transfer to nearby player:" ); // TextID 1

        var list = playersCache || GetNearbyPlayers( pUser, NEARBY_PLAYER_RANGE );
        var y = 70;

        if( list && list.length )
        {
            var max = Math.min( list.length, 10 );
            for( var i = 0; i < max; ++i )
            {
                var ch = list[i];
                var nm = ch.name || ( "0x" + ch.serial.toString( 16 ).toUpperCase());
                g.AddButton( 16, y, 0xF7, 1, 0, MakeTransferBtnId( i ), 0 );
                g.AddText( 42, y + 2, 0, nm );
                y += 24;
            }
        }
        else
        {
            g.AddText( 16, 72, 0, "None in range." );
            y += 24;
        }

        g.AddButton( 16, GUMP_H - 50, 1209, 1, 1, 0, 9 );    g.AddText( 42, GUMP_H - 48, 0, "Back" );
        g.AddButton( 200, GUMP_H - 50, 0xA50, 1, 1, 0, 0 ); g.AddText( 226, GUMP_H - 48, 0, "Close" );

        // Cache serials on socket temp tags
        if( list && list.length )
        {
            var serList = [];
            for( var k = 0; k < list.length; ++k )
                serList.push( list[k].serial );
            pUser.SetTempTag( "ranch_transfer_candidates", serList.join( "," ) );
        }
        else
        {
            pUser.SetTempTag( "ranch_transfer_candidates", "" );
        }
    }

    pUser.socket.tempObj = iStone;
    g.Send( pUser.socket );
    g.Free();
}

// ------------------------------
// Events
// ------------------------------
function onUseChecked( pUser, iUsed )
{
    // Deed -> place stone
    if( iUsed.sectionID == RANCH_DEED_SECTION )
    {
        var socket = pUser.socket;
        //if( !iUsed.InRange( pUser, 2 ))
        //  return false;

        // Must be standing inside a multi (house)
        //var iMulti = GetMultiAtObject( pUser );
        //if( !iMulti )
        //{
        //  socket.SysMessage( "You must be inside a house to place this." );
        //  return false;
        //}

        //if( IsBadPlacementRegion( pUser.region ))
        //{
        //  socket.SysMessage( "You cannot place that here." );
        //  return false;
        //}

        var spot = InFrontOf( pUser );

        var stone = CreateDFNItem( null, null, RANCH_STONE_SECTION, 1, "ITEM", false, 0, pUser.worldnumber, pUser.instanceID );
        if( !ValidateObject( stone ))
        {
            socket.SysMessage( "Failed to place the ranch stone." );
            return false;
        }

        stone.Teleport( spot.x, spot.y, spot.z, pUser.worldnumber );
        stone.SetTag( "ownerSerial", pUser.serial );
        stone.SetTag( "ranchName", MakeDefaultRanchName( pUser ) );
        stone.SetTag( "ranchSize", SIZE_DEFAULT );

        socket.SysMessage( "You place your ranch stone." );
        iUsed.Delete();
        return true;
    }

    // Stone -> open gump
    if( iUsed && iUsed.isItem && iUsed.sectionID == RANCH_STONE_SECTION )
    {
        if( !ValidateOwner( pUser, iUsed ))
        {
            pUser.socket.SysMessage( "You are not the owner of this ranch." );
            return false;
        }
        OpenRanchStoneGump( pUser, iUsed, 1, null );
        return false;
    }

    return false;
}

function onGumpPress( pSock, pButton, gumpData )
{
    var pUser = pSock.currentChar;
    var iStone = pSock.tempObj;

    if( !ValidateObject( pUser ) || !ValidateObject( iStone ))
        return;

    if( pButton == 0 )
        return;

    // Save Name
    if( pButton == 1 )
    {
        var newName = gumpData.getEdit( 0 ) || "";
        newName = newName.trim();
        if( newName.length == 0 )
            newName = "Ranch";
        if( newName.length > TITLE_MAXLEN )
            newName = newName.substring( 0, TITLE_MAXLEN );

        iStone.SetTag( "ranchName", newName );
        iStone.name = newName;
        pSock.SysMessage( "Ranch renamed to: " + newName );
        OpenRanchStoneGump( pUser, iStone, 1, null );
        return;
    }

    // Redeed
    if( pButton == 2 )
    {
        var deed = CreateDFNItem( pSock, pUser, RANCH_DEED_SECTION, 1, "ITEM", true );
        if( ValidateObject( deed ))
        {
            pSock.SysMessage( "Your ranch has been redeeded." );
            iStone.Delete();
        }
        else
        {
            pSock.SysMessage( "Failed to create the deed." );
        }
        return;
    }

    // Transfer menu
    if( pButton == 3 )
    {
        var list = GetNearbyPlayers( pUser, NEARBY_PLAYER_RANGE );
        OpenRanchStoneGump( pUser, iStone, 2, list );
        return;
    }

    // Upgrade Size
    if( pButton == 4 )
    {
        if( TryUpgradeRanchSize( pSock, pUser, iStone ) )
        {
           // Refresh page to show new size/area
           OpenRanchStoneGump( pUser, iStone, 1, null );
        }
        return;
    }

    // Get Fencing Hammer (bound)
    if( pButton == 5 )
    {
        if( !ValidateOwner( pUser, iStone ))
        {
            pSock.SysMessage( "Only the ranch owner can claim the hammer." );
            return;
        }
        if( GiveFencingHammerBoundToStone( pSock, pUser, iStone ))
            OpenRanchStoneGump( pUser, iStone, 1, null ); // refresh
        return;
    }

    // Back
    if( pButton == 9 )
    {
        OpenRanchStoneGump( pUser, iStone, 1, null );
        return;
    }

    // Transfer to specific player
    if( IsTransferBtnId( pButton ))
    {
        var idx = TransferIdxFromBtn( pButton );
        var serCsv = pSock.GetTempTag( "ranch_transfer_candidates" ) || "";

        if( serCsv.length == 0 )
        {
            pSock.SysMessage( "No nearby candidates found." );
            OpenRanchStoneGump( pUser, iStone, 2, [] );
            return;
        }

        var parts = serCsv.split( "," );
        if( idx < 0 || idx >= parts.length )
        {
            pSock.SysMessage( "Invalid selection." );
            OpenRanchStoneGump( pUser, iStone, 2, [] );
            return;
        }

        var targSer = parseInt( parts[idx], 10 );
        var targ = CalcCharFromSer( targSer );

        if( !ValidateObject( targ ) || !targ.online || !targ.InRange( pUser, NEARBY_PLAYER_RANGE ))
        {
            pSock.SysMessage( "That player is no longer valid or in range." );
            OpenRanchStoneGump( pUser, iStone, 2, GetNearbyPlayers( pUser, NEARBY_PLAYER_RANGE ) );
            return;
        }

        iStone.SetTag( "ownerSerial", targ.serial );

        var oldName = iStone.GetTag( "ranchName" ) || "Ranch";
        var suffix = "'s Ranch";
        var newName;

        if( oldName.length >= suffix.length && oldName.indexOf( suffix, oldName.length - suffix.length ) != -1 )
            newName = MakeDefaultRanchName( targ );
        else
            newName = oldName;

        iStone.SetTag( "ranchName", newName );
        pSock.SysMessage( "Ranch ownership transferred to " + ( targ.name || "player" ) + "." );

        OpenRanchStoneGump( pUser, iStone, 1, null );
        return;
    }

    pSock.SysMessage( "Unhandled button: " + pButton );
}

function GiveFencingHammerBoundToStone( pSock, pUser, iStone )
{
    // Make (or re-make) the hammer in player pack
    var hammer = CreateDFNItem( pSock, pUser, FENCING_HAMMER_SECTION, 1, "ITEM", true );
    if( !ValidateObject( hammer ))
    {
        pSock.SysMessage( "Could not create a fencing hammer." );
        return false;
    }

    // Bind the hammer to this ranch stone so it knows which stone to range-check
    hammer.SetTag( "ranchStoneSerial", iStone.serial );
    hammer.SetTag( "ranchStoneWorld", iStone.worldnumber );
    hammer.SetTag( "ranchStoneX", iStone.x );
    hammer.SetTag( "ranchStoneY", iStone.y );
    hammer.SetTag( "ranchStoneZ", iStone.z );

    // Cosmetic
    if( !hammer.name || hammer.name == "" )
        hammer.name = "a fencing hammer";

    pSock.SysMessage( "A fencing hammer bound to this ranch has been placed in your pack." );
    return true;
}
Post Reply