1
0
Fork 0

Chorus fruit teleport (#5259)

* Outline function for teleporting.

* Created new handler for chorus fruit.

* Fixed AttemptTeleport failing.

* Better names, working sound effect.

* Corrected naming.

* Remove stray LOGD.

* Offset teleport to middle of block.

* Style Fixes

Co-authored-by: x12xx12x <44411062+12xx12@users.noreply.github.com>

* Style Fixes 2

Co-authored-by: x12xx12x <44411062+12xx12@users.noreply.github.com>

* Move FindTeleportDestination to static cPawn method.

* cBoundingBox interface.

* Cleanup includes.

* Maybe exported to API?

* Change a_World to reference, add to APIDesc.

Co-authored-by: x12xx12x <44411062+12xx12@users.noreply.github.com>
This commit is contained in:
KingCol13 2021-07-10 21:05:00 +01:00 committed by GitHub
parent e9265b1d01
commit 1d1fa91401
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 227 additions and 2 deletions

View File

@ -9587,6 +9587,91 @@ a_Player:OpenWindow(Window);
{
Notes = "Removes all currently applied entity effects",
},
FindTeleportDestination =
{
{
Params =
{
{
Name = "World",
Type = "cWorld",
},
{
Name = "HeightRequired",
Type = "number",
},
{
Name = "NumTries",
Type = "number",
},
{
Name = "Destination",
Type = "Vector3d",
},
{
Name = "MinBoxCorner",
Type = "Vector3i",
},
{
Name = "MaxBoxCorner",
Type = "Vector3i",
},
},
Notes = "Function to find suitable teleport destination in or below box. Returns true and places result in Destination if found, otherwise returns false. Details at: https://minecraft.fandom.com/wiki/Enderman#Teleportation.",
},
{
Params =
{
{
Name = "World",
Type = "cWorld",
},
{
Name = "HeightRequired",
Type = "number",
},
{
Name = "NumTries",
Type = "number",
},
{
Name = "Destination",
Type = "Vector3d",
},
{
Name = "BoundingBox",
Type = "cBoundingBox",
},
},
Notes = "Function to find suitable teleport destination in or below box. Returns true and places result in Destination if found, otherwise returns false. Details at: https://minecraft.fandom.com/wiki/Enderman#Teleportation.",
},
{
Params =
{
{
Name = "World",
Type = "cWorld",
},
{
Name = "HeightRequired",
Type = "number",
},
{
Name = "NumTries",
Type = "number",
},
{
Name = "Centre",
Type = "Vector3i",
},
{
Name = "HalfCubeWidth",
Type = "number",
},
},
Notes = "Function to find suitable teleport destination in or below box. Returns true and places result in Destination if found, otherwise returns false. Details at: https://minecraft.fandom.com/wiki/Enderman#Teleportation.",
},
},
HasEntityEffect =
{
Params =

View File

@ -1756,7 +1756,8 @@ void cClientHandle::HandleUseItem(bool a_UsedMainHand)
if (
ItemHandler->IsFood() &&
(m_Player->IsSatiated() || m_Player->IsGameModeCreative()) && // Only non-creative or hungry players can eat
(HeldItem.m_ItemType != E_ITEM_GOLDEN_APPLE) // Golden apple is a special case, it is used instead of eaten
(HeldItem.m_ItemType != E_ITEM_GOLDEN_APPLE) && // Golden apple is a special case, it is used instead of eaten
(HeldItem.m_ItemType != E_ITEM_CHORUS_FRUIT) // Chorus fruit is a special case, it is used instead of eaten
)
{
// The player is satiated or in creative, and trying to eat

View File

@ -547,3 +547,81 @@ bool cPawn::DeductTotem(const eDamageType a_DamageType)
}
return false;
}
bool cPawn::FindTeleportDestination(cWorld & a_World, const int a_HeightRequired, const unsigned int a_NumTries, Vector3d & a_Destination, const Vector3i a_MinBoxCorner, const Vector3i a_MaxBoxCorner)
{
/*
Algorithm:
Choose random destination.
Seek downwards, regardless of distance until the block is made of movement-blocking material: https://minecraft.fandom.com/wiki/Materials
Succeeds if no liquid or solid blocks prevents from standing at destination.
*/
auto & Random = GetRandomProvider();
for (unsigned int i = 0; i < a_NumTries; i++)
{
const int DestX = Random.RandInt(a_MinBoxCorner.x, a_MaxBoxCorner.x);
int DestY = Random.RandInt(a_MinBoxCorner.y, a_MaxBoxCorner.y);
const int DestZ = Random.RandInt(a_MinBoxCorner.z, a_MaxBoxCorner.z);
// Seek downwards from initial destination until we find a solid block or go into the void
BLOCKTYPE DestBlock = a_World.GetBlock({DestX, DestY, DestZ});
while ((DestY >= 0) && !cBlockInfo::IsSolid(DestBlock))
{
DestBlock = a_World.GetBlock({DestX, DestY, DestZ});
DestY--;
}
// Couldn't find a solid block so move to next attempt
if (DestY < 0)
{
continue;
}
// Succeed if blocks above destination are empty
bool Success = true;
for (int j = 1; j <= a_HeightRequired; j++)
{
BLOCKTYPE TestBlock = a_World.GetBlock({DestX, DestY + j, DestZ});
if (cBlockInfo::IsSolid(TestBlock) || IsBlockLiquid(TestBlock))
{
Success = false;
break;
}
}
if (!Success)
{
continue;
}
// Offsets for entity to be centred and standing on solid block
a_Destination = Vector3d(DestX + 0.5, DestY + 1, DestZ + 0.5);
return true;
}
return false;
}
bool cPawn::FindTeleportDestination(cWorld & a_World, const int a_HeightRequired, const unsigned int a_NumTries, Vector3d & a_Destination, const cBoundingBox a_BoundingBox)
{
return FindTeleportDestination(a_World, a_HeightRequired, a_NumTries, a_Destination, a_BoundingBox.GetMin(), a_BoundingBox.GetMax());
}
bool cPawn::FindTeleportDestination(cWorld & a_World, const int a_HeightRequired, const unsigned int a_NumTries, Vector3d & a_Destination, Vector3i a_Centre, const int a_HalfCubeWidth)
{
Vector3i MinCorner(a_Centre.x - a_HalfCubeWidth, a_Centre.y - a_HalfCubeWidth, a_Centre.z - a_HalfCubeWidth);
Vector3i MaxCorner(a_Centre.x + a_HalfCubeWidth, a_Centre.y + a_HalfCubeWidth, a_Centre.z + a_HalfCubeWidth);
return FindTeleportDestination(a_World, a_HeightRequired, a_NumTries, a_Destination, MinCorner, MaxCorner);
}

View File

@ -70,6 +70,21 @@ public:
/** Returns the entity effect, if it is currently applied or nullptr if not. */
cEntityEffect * GetEntityEffect(cEntityEffect::eType a_EffectType) const;
// tolua_begin
static bool FindTeleportDestination(cWorld & a_World, const int a_HeightRequired, const unsigned int a_NumTries, Vector3d & a_Destination, const Vector3i a_MinBoxCorner, const Vector3i a_MaxBoxCorner);
static bool FindTeleportDestination(cWorld & a_World, const int a_HeightRequired, const unsigned int a_NumTries, Vector3d & a_Destination, const cBoundingBox a_BoundingBox);
/** Used by enderman and chorus fruit.
Checks for valid destinations in a cube of length 2 * a_HalfCubeWidth centred at a_Centre.
Returns true and places destination in a_Destination if successful.
Returns false if destination could be found after a_NumTries attempts.
Details at: https://minecraft.fandom.com/wiki/Enderman#Teleportation. */
static bool FindTeleportDestination(cWorld & a_World, const int a_HeightRequired, const unsigned int a_NumTries, Vector3d & a_Destination, Vector3i a_Centre, const int a_HalfCubeWidth);
// tolua_end
protected:
typedef std::map<cEntityEffect::eType, std::unique_ptr<cEntityEffect>> tEffectMap;

View File

@ -15,6 +15,7 @@ target_sources(
ItemBucket.h
ItemButton.h
ItemChest.h
ItemChorusFruit.h
ItemCloth.h
ItemComparator.h
ItemCookedFish.h

View File

@ -0,0 +1,44 @@
#pragma once
#include "ItemFood.h"
#include "../Entities/Pawn.h"
class cItemChorusFruitHandler:
public cItemFoodHandler
{
using Super = cItemFoodHandler;
public:
cItemChorusFruitHandler():
Super(E_ITEM_CHORUS_FRUIT, FoodInfo(4, 2.4))
{
}
virtual bool EatItem(cPlayer * a_Player, cItem * a_Item) override
{
cItemHandler::EatItem(a_Player, a_Item);
if (!a_Player->IsGameModeCreative())
{
a_Player->GetInventory().RemoveOneEquippedItem();
}
// Attempt to find a teleport destination
Vector3d Destination;
cWorld * World = a_Player->GetWorld();
if (cPawn::FindTeleportDestination(*World, 2, 16, Destination, a_Player->GetPosition(), 8))
{
// Broadcast sound effect to _pre-teleport_ location, then teleport player.
World->BroadcastSoundEffect("item.chorus_fruit.teleport", a_Player->GetPosition(), 1, 1);
a_Player->TeleportToCoords(Destination.x, Destination.y, Destination.z);
}
return true;
}
};

View File

@ -20,6 +20,7 @@
#include "ItemBucket.h"
#include "ItemButton.h"
#include "ItemChest.h"
#include "ItemChorusFruit.h"
#include "ItemCloth.h"
#include "ItemComparator.h"
#include "ItemCookedFish.h"
@ -354,7 +355,6 @@ cItemHandler * cItemHandler::CreateItemHandler(int a_ItemType)
case E_ITEM_BAKED_POTATO: return new cItemFoodHandler(a_ItemType, FoodInfo(5, 6));
case E_ITEM_BEETROOT: return new cItemFoodHandler(a_ItemType, FoodInfo(1, 1.2));
case E_ITEM_BREAD: return new cItemFoodHandler(a_ItemType, FoodInfo(5, 6));
case E_ITEM_CHORUS_FRUIT: return new cItemFoodHandler(a_ItemType, FoodInfo(4, 2.4));
case E_ITEM_COOKED_CHICKEN: return new cItemFoodHandler(a_ItemType, FoodInfo(6, 7.2));
case E_ITEM_COOKED_MUTTON: return new cItemFoodHandler(a_ItemType, FoodInfo(6, 9.6));
case E_ITEM_COOKED_PORKCHOP: return new cItemFoodHandler(a_ItemType, FoodInfo(8, 12.8));
@ -371,6 +371,7 @@ cItemHandler * cItemHandler::CreateItemHandler(int a_ItemType)
case E_ITEM_STEAK: return new cItemFoodHandler(a_ItemType, FoodInfo(8, 12.8));
// Special-case food with their own handler
case E_ITEM_CHORUS_FRUIT: return new cItemChorusFruitHandler();
case E_ITEM_COOKED_FISH: return new cItemCookedFishHandler();
case E_ITEM_GOLDEN_APPLE: return new cItemGoldenAppleHandler();
case E_ITEM_POISONOUS_POTATO: return new cItemPoisonousPotatoHandler();