2018-01-05 06:28:06 -05:00
|
|
|
|
2014-03-28 18:51:30 -04:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "ItemHandler.h"
|
|
|
|
#include "../Entities/Player.h"
|
|
|
|
#include "../LineBlockTracer.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-04-13 12:38:06 -04:00
|
|
|
class cItemLilypadHandler:
|
2014-03-28 18:51:30 -04:00
|
|
|
public cItemHandler
|
|
|
|
{
|
2020-04-13 12:38:06 -04:00
|
|
|
using Super = cItemHandler;
|
2014-03-28 18:51:30 -04:00
|
|
|
|
|
|
|
public:
|
2020-04-13 12:38:06 -04:00
|
|
|
|
2014-04-04 03:56:57 -04:00
|
|
|
cItemLilypadHandler(int a_ItemType):
|
2020-04-13 12:38:06 -04:00
|
|
|
Super(a_ItemType)
|
2014-03-28 18:51:30 -04:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2014-04-04 03:56:57 -04:00
|
|
|
|
2020-04-21 16:19:22 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
2014-03-28 18:51:30 -04:00
|
|
|
virtual bool IsPlaceable(void) override
|
|
|
|
{
|
2014-07-17 16:15:34 -04:00
|
|
|
return false; // Set as not placeable so OnItemUse is called
|
2014-03-28 18:51:30 -04:00
|
|
|
}
|
|
|
|
|
2014-04-04 03:56:57 -04:00
|
|
|
|
2015-04-14 04:49:01 -04:00
|
|
|
|
2020-04-21 16:19:22 -04:00
|
|
|
|
|
|
|
|
2015-04-14 04:49:01 -04:00
|
|
|
virtual bool OnItemUse(
|
2020-04-21 16:19:22 -04:00
|
|
|
cWorld * a_World,
|
|
|
|
cPlayer * a_Player,
|
|
|
|
cBlockPluginInterface & a_PluginInterface,
|
|
|
|
const cItem & a_HeldItem,
|
|
|
|
const Vector3i a_ClickedBlockPos,
|
|
|
|
eBlockFace a_ClickedBlockFace
|
2015-04-14 04:49:01 -04:00
|
|
|
) override
|
2014-03-28 18:51:30 -04:00
|
|
|
{
|
2020-11-27 20:01:47 -05:00
|
|
|
// The client sends BLOCK_FACE_NONE when it determines it should do a tracing-based placement.
|
|
|
|
// Otherwise, a normal block face is sent.
|
|
|
|
|
|
|
|
if (a_ClickedBlockFace != BLOCK_FACE_NONE)
|
2014-03-28 18:51:30 -04:00
|
|
|
{
|
2020-11-27 20:01:47 -05:00
|
|
|
// The position the client wants the lilypad placed.
|
|
|
|
const auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
|
|
|
|
|
|
|
|
// Lilypad should not replace non air and non water blocks:
|
|
|
|
if (
|
|
|
|
const auto BlockToReplace = a_World->GetBlock(PlacePos);
|
|
|
|
(BlockToReplace != E_BLOCK_AIR) &&
|
|
|
|
(BlockToReplace != E_BLOCK_WATER) &&
|
|
|
|
(BlockToReplace != E_BLOCK_STATIONARY_WATER)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-11-28 15:48:53 -05:00
|
|
|
const auto Below = PlacePos.addedY(-1);
|
|
|
|
if (Below.y < 0)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lilypad should be placed only if there is a water block below:
|
2020-11-27 20:01:47 -05:00
|
|
|
if (
|
2020-11-28 15:48:53 -05:00
|
|
|
const auto BlockBelow = a_World->GetBlock(Below);
|
2020-11-27 20:01:47 -05:00
|
|
|
(BlockBelow != E_BLOCK_WATER) &&
|
|
|
|
(BlockBelow != E_BLOCK_STATIONARY_WATER)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-04-21 16:19:22 -04:00
|
|
|
a_World->SetBlock(PlacePos, E_BLOCK_LILY_PAD, 0);
|
2014-03-28 18:51:30 -04:00
|
|
|
if (!a_Player->IsGameModeCreative())
|
2014-03-28 19:51:52 -04:00
|
|
|
{
|
2014-03-28 18:51:30 -04:00
|
|
|
a_Player->GetInventory().RemoveOneEquippedItem();
|
2014-03-28 19:51:52 -04:00
|
|
|
}
|
2020-11-28 15:48:53 -05:00
|
|
|
|
2014-03-28 18:51:30 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-04-21 16:19:22 -04:00
|
|
|
class cCallbacks:
|
2014-03-28 18:51:30 -04:00
|
|
|
public cBlockTracer::cCallbacks
|
|
|
|
{
|
|
|
|
public:
|
2014-04-23 16:06:07 -04:00
|
|
|
|
2020-05-08 05:04:07 -04:00
|
|
|
virtual bool OnNextBlock(Vector3i a_CBBlockPos, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, eBlockFace a_CBEntryFace) override
|
2014-03-28 18:51:30 -04:00
|
|
|
{
|
2020-11-27 20:01:47 -05:00
|
|
|
if (
|
|
|
|
!IsBlockWater(a_CBBlockType) ||
|
|
|
|
(a_CBBlockMeta != 0) // The hit block should be a source
|
|
|
|
)
|
2014-03-28 18:51:30 -04:00
|
|
|
{
|
2020-11-27 20:01:47 -05:00
|
|
|
// TODO: Vanilla stops the trace. However, we need to continue the trace, to work around our lack of block bounding box support
|
|
|
|
// which would otherwise mean we misbehave when clicking through the voxel a (e.g.) button occupies. Now, however, we misbehave
|
|
|
|
// when clicking on a block near water... Nonetheless, the former would cause ghost blocks, so continue for now.
|
|
|
|
|
|
|
|
// Ignore and continue trace:
|
|
|
|
return false;
|
2014-03-28 18:51:30 -04:00
|
|
|
}
|
2020-11-27 20:01:47 -05:00
|
|
|
|
|
|
|
Position = AddFaceDirection(a_CBBlockPos, BLOCK_FACE_YP); // Always place pad at top of water block
|
|
|
|
return true;
|
2014-03-28 18:51:30 -04:00
|
|
|
}
|
|
|
|
|
2020-11-27 20:01:47 -05:00
|
|
|
Vector3i Position;
|
2014-03-28 18:51:30 -04:00
|
|
|
|
2020-04-21 16:19:22 -04:00
|
|
|
} Callbacks;
|
2014-03-28 18:51:30 -04:00
|
|
|
|
2020-11-27 20:01:47 -05:00
|
|
|
const auto EyePosition = a_Player->GetEyePosition();
|
|
|
|
const auto End = EyePosition + a_Player->GetLookVector() * 5;
|
|
|
|
if (cLineBlockTracer::Trace(*a_Player->GetWorld(), Callbacks, EyePosition, End))
|
2014-03-28 18:51:30 -04:00
|
|
|
{
|
2020-11-27 20:01:47 -05:00
|
|
|
// The line traced to completion; no suitable water was found:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto BlockToReplace = a_World->GetBlock(Callbacks.Position);
|
|
|
|
if (BlockToReplace != E_BLOCK_AIR)
|
|
|
|
{
|
|
|
|
// Lilypad should not replace non air blocks:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
a_World->SetBlock(Callbacks.Position, E_BLOCK_LILY_PAD, 0);
|
|
|
|
if (!a_Player->IsGameModeCreative())
|
|
|
|
{
|
|
|
|
a_Player->GetInventory().RemoveOneEquippedItem();
|
2014-03-28 18:51:30 -04:00
|
|
|
}
|
|
|
|
|
2020-11-27 20:01:47 -05:00
|
|
|
return true;
|
2014-03-28 18:51:30 -04:00
|
|
|
}
|
|
|
|
};
|