Merge pull request #1079 from mc-server/potions
Added potions and entity effect accessors
This commit is contained in:
commit
ec77cf1b06
@ -1691,6 +1691,9 @@ a_Player:OpenWindow(Window);
|
||||
TakeDamage = { Return = "" },
|
||||
KilledBy = { Return = "" },
|
||||
GetHealth = { Return = "number" },
|
||||
AddEntityEffect = { Params = "EffectType, {{cEntityEffect}}", Return = "", Notes = "Applies an entity effect" },
|
||||
RemoveEntityEffect = { Params = "EffectType", Return = "", Notes = "Removes a currently applied entity effect" },
|
||||
ClearEntityEffects = { Return = "", Notes = "Removes all currently applied entity effects" },
|
||||
},
|
||||
Inherits = "cEntity",
|
||||
}, -- cPawn
|
||||
|
33
MCServer/Plugins/APIDump/Hooks/OnEntityAddEffect.lua
Normal file
33
MCServer/Plugins/APIDump/Hooks/OnEntityAddEffect.lua
Normal file
@ -0,0 +1,33 @@
|
||||
return
|
||||
{
|
||||
HOOK_ENTITY_ADD_EFFECT =
|
||||
{
|
||||
CalledWhen = "An entity effect is about to get added to an entity.",
|
||||
DefaultFnName = "OnEntityAddEffect", -- also used as pagename
|
||||
Desc = [[
|
||||
This hook is called whenever an entity effect is about to be added to an entity. The plugin may
|
||||
disallow the addition by returning true.</p>
|
||||
<p>Note that this hook only fires for adding the effect, but not for the actual effect application. See
|
||||
also the {{OnEntityRemoveEffect|HOOK_ENTITY_REMOVE_EFFECT}} for notification about effects expiring /
|
||||
removing, and {{OnEntityApplyEffect|HOOK_ENTITY_APPLY_EFFECT}} for the actual effect application to the
|
||||
entity.
|
||||
]],
|
||||
Params =
|
||||
{
|
||||
{ Name = "Entity", Type = "{{cEntity}}", Notes = "The entity to which the effect is about to be added" },
|
||||
{ Name = "EffectType", Type = "number", Notes = "The type of the effect to be added. One of the effXXX constants." },
|
||||
{ Name = "EffectDuration", Type = "number", Notes = "The duration of the effect to be added, in ticks." },
|
||||
{ Name = "EffectIntensity", Type = "number", Notes = "The intensity (level) of the effect to be added. " },
|
||||
{ Name = "DistanceModifier", Type = "number", Notes = "The modifier for the effect intensity, based on distance. Used mainly for splash potions." },
|
||||
},
|
||||
Returns = [[
|
||||
If the plugin returns true, the effect will not be added and none of the remaining hook handlers will
|
||||
be called. If the plugin returns false, MCServer calls all the remaining hook handlers and finally
|
||||
the effect is added to the entity.
|
||||
]],
|
||||
}, -- HOOK_EXECUTE_COMMAND
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -40,7 +40,7 @@ $cfile "../Entities/Painting.h"
|
||||
$cfile "../Entities/Pickup.h"
|
||||
$cfile "../Entities/ProjectileEntity.h"
|
||||
$cfile "../Entities/TNTEntity.h"
|
||||
$cfile "../Entities/Effects.h"
|
||||
$cfile "../Entities/EntityEffect.h"
|
||||
$cfile "../Server.h"
|
||||
$cfile "../World.h"
|
||||
$cfile "../Inventory.h"
|
||||
|
@ -57,6 +57,7 @@ public:
|
||||
virtual bool OnCollectingPickup (cPlayer * a_Player, cPickup * a_Pickup) = 0;
|
||||
virtual bool OnCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0;
|
||||
virtual bool OnDisconnect (cClientHandle & a_Client, const AString & a_Reason) = 0;
|
||||
virtual bool OnEntityAddEffect (cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier) = 0;
|
||||
virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split) = 0;
|
||||
virtual bool OnExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) = 0;
|
||||
virtual bool OnExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) = 0;
|
||||
|
@ -420,6 +420,26 @@ bool cPluginLua::OnDisconnect(cClientHandle & a_Client, const AString & a_Reason
|
||||
|
||||
|
||||
|
||||
bool cPluginLua::OnEntityAddEffect(cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier)
|
||||
{
|
||||
cCSLock Lock(m_CriticalSection);
|
||||
bool res = false;
|
||||
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_ENTITY_ADD_EFFECT];
|
||||
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
|
||||
{
|
||||
m_LuaState.Call((int)(**itr), &a_Entity, a_EffectType, a_EffectDurationTicks, a_EffectIntensity, a_DistanceModifier, cLuaState::Return, res);
|
||||
if (res)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split)
|
||||
{
|
||||
cCSLock Lock(m_CriticalSection);
|
||||
@ -1524,6 +1544,7 @@ const char * cPluginLua::GetHookFnName(int a_HookType)
|
||||
case cPluginManager::HOOK_CRAFTING_NO_RECIPE: return "OnCraftingNoRecipe";
|
||||
case cPluginManager::HOOK_DISCONNECT: return "OnDisconnect";
|
||||
case cPluginManager::HOOK_PLAYER_ANIMATION: return "OnPlayerAnimation";
|
||||
case cPluginManager::HOOK_ENTITY_ADD_EFFECT: return "OnEntityAddEffect";
|
||||
case cPluginManager::HOOK_EXECUTE_COMMAND: return "OnExecuteCommand";
|
||||
case cPluginManager::HOOK_HANDSHAKE: return "OnHandshake";
|
||||
case cPluginManager::HOOK_KILLING: return "OnKilling";
|
||||
|
@ -80,6 +80,7 @@ public:
|
||||
virtual bool OnCollectingPickup (cPlayer * a_Player, cPickup * a_Pickup) override;
|
||||
virtual bool OnCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override;
|
||||
virtual bool OnDisconnect (cClientHandle & a_Client, const AString & a_Reason) override;
|
||||
virtual bool OnEntityAddEffect (cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier) override;
|
||||
virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split) override;
|
||||
virtual bool OnExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) override;
|
||||
virtual bool OnExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) override;
|
||||
|
@ -474,6 +474,27 @@ bool cPluginManager::CallHookDisconnect(cClientHandle & a_Client, const AString
|
||||
|
||||
|
||||
|
||||
bool cPluginManager::CallHookEntityAddEffect(cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier)
|
||||
{
|
||||
HookMap::iterator Plugins = m_Hooks.find(HOOK_ENTITY_ADD_EFFECT);
|
||||
if (Plugins == m_Hooks.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr)
|
||||
{
|
||||
if ((*itr)->OnEntityAddEffect(a_Entity, a_EffectType, a_EffectDurationTicks, a_EffectIntensity, a_DistanceModifier))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cPluginManager::CallHookExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split)
|
||||
{
|
||||
FIND_HOOK(HOOK_EXECUTE_COMMAND);
|
||||
|
@ -82,6 +82,7 @@ public: // tolua_export
|
||||
HOOK_CRAFTING_NO_RECIPE,
|
||||
HOOK_DISCONNECT,
|
||||
HOOK_PLAYER_ANIMATION,
|
||||
HOOK_ENTITY_ADD_EFFECT,
|
||||
HOOK_EXECUTE_COMMAND,
|
||||
HOOK_EXPLODED,
|
||||
HOOK_EXPLODING,
|
||||
@ -183,6 +184,7 @@ public: // tolua_export
|
||||
bool CallHookCollectingPickup (cPlayer * a_Player, cPickup & a_Pickup);
|
||||
bool CallHookCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe);
|
||||
bool CallHookDisconnect (cClientHandle & a_Client, const AString & a_Reason);
|
||||
bool CallHookEntityAddEffect (cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier);
|
||||
bool CallHookExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split); // If a_Player == NULL, it is a console cmd
|
||||
bool CallHookExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData);
|
||||
bool CallHookExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData);
|
||||
|
@ -363,6 +363,7 @@ AString DamageTypeToString(eDamageType a_DamageType)
|
||||
case dtLightning: return "dtLightning";
|
||||
case dtOnFire: return "dtOnFire";
|
||||
case dtPoisoning: return "dtPoisoning";
|
||||
case dtWithering: return "dtWithering";
|
||||
case dtPotionOfHarming: return "dtPotionOfHarming";
|
||||
case dtRangedAttack: return "dtRangedAttack";
|
||||
case dtStarving: return "dtStarving";
|
||||
@ -408,6 +409,7 @@ eDamageType StringToDamageType(const AString & a_DamageTypeString)
|
||||
{ dtCactusContact, "dtCactusContact"},
|
||||
{ dtLavaContact, "dtLavaContact"},
|
||||
{ dtPoisoning, "dtPoisoning"},
|
||||
{ dtWithering, "dtWithering"},
|
||||
{ dtOnFire, "dtOnFire"},
|
||||
{ dtFireContact, "dtFireContact"},
|
||||
{ dtInVoid, "dtInVoid"},
|
||||
@ -433,6 +435,7 @@ eDamageType StringToDamageType(const AString & a_DamageTypeString)
|
||||
{ dtCactusContact, "dtCacti"},
|
||||
{ dtLavaContact, "dtLava"},
|
||||
{ dtPoisoning, "dtPoison"},
|
||||
{ dtWithering, "dtWither"},
|
||||
{ dtOnFire, "dtBurning"},
|
||||
{ dtFireContact, "dtInFire"},
|
||||
{ dtAdmin, "dtPlugin"},
|
||||
|
@ -319,7 +319,8 @@ enum ENUM_ITEM_ID
|
||||
E_ITEM_GHAST_TEAR = 370,
|
||||
E_ITEM_GOLD_NUGGET = 371,
|
||||
E_ITEM_NETHER_WART = 372,
|
||||
E_ITEM_POTIONS = 373,
|
||||
E_ITEM_POTION = 373,
|
||||
E_ITEM_POTIONS = 373, // OBSOLETE, use E_ITEM_POTION instead
|
||||
E_ITEM_GLASS_BOTTLE = 374,
|
||||
E_ITEM_SPIDER_EYE = 375,
|
||||
E_ITEM_FERMENTED_SPIDER_EYE = 376,
|
||||
@ -811,6 +812,7 @@ enum eDamageType
|
||||
dtCactusContact, // Contact with a cactus block
|
||||
dtLavaContact, // Contact with a lava block
|
||||
dtPoisoning, // Having the poison effect
|
||||
dtWithering, // Having the wither effect
|
||||
dtOnFire, // Being on fire
|
||||
dtFireContact, // Standing inside a fire block
|
||||
dtInVoid, // Falling into the Void (Y < 0)
|
||||
@ -837,6 +839,7 @@ enum eDamageType
|
||||
dtCacti = dtCactusContact,
|
||||
dtLava = dtLavaContact,
|
||||
dtPoison = dtPoisoning,
|
||||
dtWither = dtWithering,
|
||||
dtBurning = dtOnFire,
|
||||
dtInFire = dtFireContact,
|
||||
dtPlugin = dtAdmin,
|
||||
|
@ -43,7 +43,7 @@ set(BINDING_DEPENDECIES
|
||||
Cuboid.h
|
||||
Defines.h
|
||||
Enchantments.h
|
||||
Entities/Effects.h
|
||||
Entities/EntityEffect.h
|
||||
Entities/Entity.h
|
||||
Entities/Floater.h
|
||||
Entities/Pawn.h
|
||||
|
@ -877,7 +877,7 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB
|
||||
case DIG_STATUS_SHOOT_EAT:
|
||||
{
|
||||
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem());
|
||||
if (ItemHandler->IsFood())
|
||||
if (ItemHandler->IsFood() || ItemHandler->IsDrinkable(m_Player->GetEquippedItem().m_ItemDamage))
|
||||
{
|
||||
m_Player->AbortEating();
|
||||
return;
|
||||
@ -1202,15 +1202,16 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
||||
return;
|
||||
}
|
||||
|
||||
short EquippedDamage = Equipped.m_ItemDamage;
|
||||
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(Equipped.m_ItemType);
|
||||
|
||||
if (ItemHandler->IsPlaceable() && (a_BlockFace != BLOCK_FACE_NONE))
|
||||
{
|
||||
HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler);
|
||||
}
|
||||
else if (ItemHandler->IsFood() && !m_Player->IsGameModeCreative())
|
||||
else if ((ItemHandler->IsFood() || ItemHandler->IsDrinkable(EquippedDamage)) && !m_Player->IsGameModeCreative())
|
||||
{
|
||||
if (m_Player->IsSatiated())
|
||||
if (m_Player->IsSatiated() && !ItemHandler->IsDrinkable(EquippedDamage))
|
||||
{
|
||||
// The player is satiated, they cannot eat
|
||||
return;
|
||||
|
@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// tolua_begin
|
||||
enum ENUM_ENTITY_EFFECT
|
||||
{
|
||||
E_EFFECT_SPEED = 1,
|
||||
E_EFFECT_SLOWNESS = 2,
|
||||
E_EFFECT_HASTE = 3,
|
||||
E_EFFECT_MINING_FATIGUE = 4,
|
||||
E_EFFECT_STENGTH = 5,
|
||||
E_EFFECT_INSTANT_HEALTH = 6,
|
||||
E_EFFECT_INSTANT_DAMAGE = 7,
|
||||
E_EFFECT_JUMP_BOOST = 8,
|
||||
E_EFFECT_NAUSEA = 9,
|
||||
E_EFFECT_REGENERATION = 10,
|
||||
E_EFFECT_RESISTANCE = 11,
|
||||
E_EFFECT_FIRE_RESISTANCE = 12,
|
||||
E_EFFECT_WATER_BREATHING = 13,
|
||||
E_EFFECT_INVISIBILITY = 14,
|
||||
E_EFFECT_BLINDNESS = 15,
|
||||
E_EFFECT_NIGHT_VISION = 16,
|
||||
E_EFFECT_HUNGER = 17,
|
||||
E_EFFECT_WEAKNESS = 18,
|
||||
E_EFFECT_POISON = 19,
|
||||
E_EFFECT_WITHER = 20,
|
||||
E_EFFECT_HEALTH_BOOST = 21,
|
||||
E_EFFECT_ABSORPTION = 22,
|
||||
E_EFFECT_SATURATION = 23,
|
||||
} ;
|
||||
// tolua_end
|
@ -310,11 +310,15 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
cPlayer * Player = (cPlayer *)a_TDI.Attacker;
|
||||
|
||||
// IsOnGround() only is false if the player is moving downwards
|
||||
if (!Player->IsOnGround()) // TODO: Better damage increase, and check for enchantments (and use magic critical instead of plain)
|
||||
// TODO: Better damage increase, and check for enchantments (and use magic critical instead of plain)
|
||||
if (!Player->IsOnGround())
|
||||
{
|
||||
if ((a_TDI.DamageType == dtAttack) || (a_TDI.DamageType == dtArrowAttack))
|
||||
{
|
||||
a_TDI.FinalDamage += 2;
|
||||
m_World->BroadcastEntityAnimation(*this, 4); // Critical hit
|
||||
}
|
||||
}
|
||||
|
||||
Player->GetStatManager().AddValue(statDamageDealt, (StatValue)floor(a_TDI.FinalDamage * 10 + 0.5));
|
||||
}
|
||||
@ -431,6 +435,7 @@ bool cEntity::ArmorCoversAgainst(eDamageType a_DamageType)
|
||||
case dtStarving:
|
||||
case dtInVoid:
|
||||
case dtPoisoning:
|
||||
case dtWithering:
|
||||
case dtPotionOfHarming:
|
||||
case dtFalling:
|
||||
case dtLightning:
|
||||
|
@ -158,6 +158,7 @@ public:
|
||||
bool IsPlayer (void) const { return (m_EntityType == etPlayer); }
|
||||
bool IsPickup (void) const { return (m_EntityType == etPickup); }
|
||||
bool IsMob (void) const { return (m_EntityType == etMonster); }
|
||||
bool IsPawn (void) const { return (IsMob() || IsPlayer()); }
|
||||
bool IsFallingBlock(void) const { return (m_EntityType == etFallingBlock); }
|
||||
bool IsMinecart (void) const { return (m_EntityType == etMinecart); }
|
||||
bool IsBoat (void) const { return (m_EntityType == etBoat); }
|
||||
@ -315,7 +316,7 @@ public:
|
||||
virtual void Killed(cEntity * a_Victim) {}
|
||||
|
||||
/// Heals the specified amount of HPs
|
||||
void Heal(int a_HitPoints);
|
||||
virtual void Heal(int a_HitPoints);
|
||||
|
||||
/// Returns the health of this entity
|
||||
int GetHealth(void) const { return m_Health; }
|
||||
|
287
src/Entities/EntityEffect.cpp
Normal file
287
src/Entities/EntityEffect.cpp
Normal file
@ -0,0 +1,287 @@
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "EntityEffect.h"
|
||||
#include "../Mobs/Monster.h"
|
||||
#include "Player.h"
|
||||
|
||||
|
||||
|
||||
|
||||
cEntityEffect::cEntityEffect():
|
||||
m_Ticks(0),
|
||||
m_Duration(0),
|
||||
m_Intensity(0),
|
||||
m_DistanceModifier(1)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cEntityEffect::cEntityEffect(int a_Duration, short a_Intensity, double a_DistanceModifier):
|
||||
m_Ticks(0),
|
||||
m_Duration(a_Duration),
|
||||
m_Intensity(a_Intensity),
|
||||
m_DistanceModifier(a_DistanceModifier)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cEntityEffect::cEntityEffect(const cEntityEffect & a_OtherEffect):
|
||||
m_Ticks(a_OtherEffect.m_Ticks),
|
||||
m_Duration(a_OtherEffect.m_Duration),
|
||||
m_Intensity(a_OtherEffect.m_Intensity),
|
||||
m_DistanceModifier(a_OtherEffect.m_DistanceModifier)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cEntityEffect & cEntityEffect::operator=(cEntityEffect a_OtherEffect)
|
||||
{
|
||||
std::swap(m_Ticks, a_OtherEffect.m_Ticks);
|
||||
std::swap(m_Duration, a_OtherEffect.m_Duration);
|
||||
std::swap(m_Intensity, a_OtherEffect.m_Intensity);
|
||||
std::swap(m_DistanceModifier, a_OtherEffect.m_DistanceModifier);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cEntityEffect * cEntityEffect::CreateEntityEffect(cEntityEffect::eType a_EffectType, int a_Duration, short a_Intensity, double a_DistanceModifier)
|
||||
{
|
||||
switch (a_EffectType)
|
||||
{
|
||||
case cEntityEffect::effNoEffect: return new cEntityEffect (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
|
||||
case cEntityEffect::effAbsorption: return new cEntityEffectAbsorption (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effBlindness: return new cEntityEffectBlindness (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effFireResistance: return new cEntityEffectFireResistance(a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effHaste: return new cEntityEffectHaste (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effHealthBoost: return new cEntityEffectHealthBoost (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effHunger: return new cEntityEffectHunger (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effInstantDamage: return new cEntityEffectInstantDamage (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effInstantHealth: return new cEntityEffectInstantHealth (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effInvisibility: return new cEntityEffectInvisibility (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effJumpBoost: return new cEntityEffectJumpBoost (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effMiningFatigue: return new cEntityEffectMiningFatigue (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effNausea: return new cEntityEffectNausea (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effNightVision: return new cEntityEffectNightVision (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effPoison: return new cEntityEffectPoison (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effRegeneration: return new cEntityEffectRegeneration (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effResistance: return new cEntityEffectResistance (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effSaturation: return new cEntityEffectSaturation (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effSlowness: return new cEntityEffectSlowness (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effSpeed: return new cEntityEffectSpeed (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effStrength: return new cEntityEffectStrength (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effWaterBreathing: return new cEntityEffectWaterBreathing(a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effWeakness: return new cEntityEffectWeakness (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
case cEntityEffect::effWither: return new cEntityEffectWither (a_Duration, a_Intensity, a_DistanceModifier);
|
||||
}
|
||||
|
||||
ASSERT(!"Unhandled entity effect type!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cEntityEffect::OnTick(cPawn & a_Target)
|
||||
{
|
||||
// Reduce the effect's duration
|
||||
++m_Ticks;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// cEntityEffectInstantHealth:
|
||||
|
||||
void cEntityEffectInstantHealth::OnActivate(cPawn & a_Target)
|
||||
{
|
||||
// Base amount = 6, doubles for every increase in intensity
|
||||
int amount = (int)(6 * (1 << m_Intensity) * m_DistanceModifier);
|
||||
|
||||
if (a_Target.IsMob() && ((cMonster &) a_Target).IsUndead())
|
||||
{
|
||||
a_Target.TakeDamage(dtPotionOfHarming, NULL, amount, 0); // TODO: Store attacker in a pointer-safe way, pass to TakeDamage
|
||||
return;
|
||||
}
|
||||
a_Target.Heal(amount);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// cEntityEffectInstantDamage:
|
||||
|
||||
void cEntityEffectInstantDamage::OnActivate(cPawn & a_Target)
|
||||
{
|
||||
// Base amount = 6, doubles for every increase in intensity
|
||||
int amount = (int)(6 * (1 << m_Intensity) * m_DistanceModifier);
|
||||
|
||||
if (a_Target.IsMob() && ((cMonster &) a_Target).IsUndead())
|
||||
{
|
||||
a_Target.Heal(amount);
|
||||
return;
|
||||
}
|
||||
a_Target.TakeDamage(dtPotionOfHarming, NULL, amount, 0); // TODO: Store attacker in a pointer-safe way, pass to TakeDamage
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// cEntityEffectRegeneration:
|
||||
|
||||
void cEntityEffectRegeneration::OnTick(cPawn & a_Target)
|
||||
{
|
||||
super::OnTick(a_Target);
|
||||
|
||||
if (a_Target.IsMob() && ((cMonster &) a_Target).IsUndead())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Regen frequency = 50 ticks, divided by potion level (Regen II = 25 ticks)
|
||||
int frequency = (int) std::floor(50.0 / (double)(m_Intensity + 1));
|
||||
|
||||
if ((m_Ticks % frequency) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
a_Target.Heal(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// cEntityEffectHunger:
|
||||
|
||||
void cEntityEffectHunger::OnTick(cPawn & a_Target)
|
||||
{
|
||||
super::OnTick(a_Target);
|
||||
|
||||
if (a_Target.IsPlayer())
|
||||
{
|
||||
cPlayer & Target = (cPlayer &) a_Target;
|
||||
Target.SetFoodExhaustionLevel(Target.GetFoodExhaustionLevel() + 0.025); // 0.5 per second = 0.025 per tick
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// cEntityEffectWeakness:
|
||||
|
||||
void cEntityEffectWeakness::OnTick(cPawn & a_Target)
|
||||
{
|
||||
super::OnTick(a_Target);
|
||||
|
||||
// Damage reduction = 0.5 damage, multiplied by potion level (Weakness II = 1 damage)
|
||||
// double dmg_reduc = 0.5 * (a_Effect.GetIntensity() + 1);
|
||||
|
||||
// TODO: Implement me!
|
||||
// TODO: Weakened villager zombies can be turned back to villagers with the god apple
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// cEntityEffectPoison:
|
||||
|
||||
void cEntityEffectPoison::OnTick(cPawn & a_Target)
|
||||
{
|
||||
super::OnTick(a_Target);
|
||||
|
||||
if (a_Target.IsMob())
|
||||
{
|
||||
cMonster & Target = (cMonster &) a_Target;
|
||||
|
||||
// Doesn't effect undead mobs, spiders
|
||||
if (
|
||||
Target.IsUndead() ||
|
||||
(Target.GetMobType() == cMonster::mtSpider) ||
|
||||
(Target.GetMobType() == cMonster::mtCaveSpider)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Poison frequency = 25 ticks, divided by potion level (Poison II = 12 ticks)
|
||||
int frequency = (int) std::floor(25.0 / (double)(m_Intensity + 1));
|
||||
|
||||
if ((m_Ticks % frequency) == 0)
|
||||
{
|
||||
// Cannot take poison damage when health is at 1
|
||||
if (a_Target.GetHealth() > 1)
|
||||
{
|
||||
a_Target.TakeDamage(dtPoisoning, NULL, 1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// cEntityEffectWither:
|
||||
|
||||
void cEntityEffectWither::OnTick(cPawn & a_Target)
|
||||
{
|
||||
super::OnTick(a_Target);
|
||||
|
||||
// Damage frequency = 40 ticks, divided by effect level (Wither II = 20 ticks)
|
||||
int frequency = (int) std::floor(25.0 / (double)(m_Intensity + 1));
|
||||
|
||||
if ((m_Ticks % frequency) == 0)
|
||||
{
|
||||
a_Target.TakeDamage(dtWither, NULL, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// cEntityEffectSaturation:
|
||||
|
||||
void cEntityEffectSaturation::OnTick(cPawn & a_Target)
|
||||
{
|
||||
if (a_Target.IsPlayer())
|
||||
{
|
||||
cPlayer & Target = (cPlayer &) a_Target;
|
||||
Target.SetFoodSaturationLevel(Target.GetFoodSaturationLevel() + (1 + m_Intensity)); // Increase saturation 1 per tick, adds 1 for every increase in level
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
476
src/Entities/EntityEffect.h
Normal file
476
src/Entities/EntityEffect.h
Normal file
@ -0,0 +1,476 @@
|
||||
#pragma once
|
||||
|
||||
class cPawn;
|
||||
|
||||
// tolua_begin
|
||||
class cEntityEffect
|
||||
{
|
||||
public:
|
||||
|
||||
/** All types of entity effects (numbers correspond to protocol / storage types) */
|
||||
enum eType
|
||||
{
|
||||
effNoEffect = 0,
|
||||
effSpeed = 1,
|
||||
effSlowness = 2,
|
||||
effHaste = 3,
|
||||
effMiningFatigue = 4,
|
||||
effStrength = 5,
|
||||
effInstantHealth = 6,
|
||||
effInstantDamage = 7,
|
||||
effJumpBoost = 8,
|
||||
effNausea = 9,
|
||||
effRegeneration = 10,
|
||||
effResistance = 11,
|
||||
effFireResistance = 12,
|
||||
effWaterBreathing = 13,
|
||||
effInvisibility = 14,
|
||||
effBlindness = 15,
|
||||
effNightVision = 16,
|
||||
effHunger = 17,
|
||||
effWeakness = 18,
|
||||
effPoison = 19,
|
||||
effWither = 20,
|
||||
effHealthBoost = 21,
|
||||
effAbsorption = 22,
|
||||
effSaturation = 23,
|
||||
} ;
|
||||
|
||||
// tolua_end
|
||||
|
||||
/** Creates an empty entity effect */
|
||||
cEntityEffect(void);
|
||||
|
||||
/** Creates an entity effect of the specified type
|
||||
@param a_Duration How long this effect will last, in ticks
|
||||
@param a_Intensity How strong the effect will be applied
|
||||
@param a_DistanceModifier The distance modifier for affecting potency, defaults to 1 */
|
||||
cEntityEffect(int a_Duration, short a_Intensity, double a_DistanceModifier = 1);
|
||||
|
||||
/** Creates an entity effect by copying another
|
||||
@param a_OtherEffect The other effect to copy */
|
||||
cEntityEffect(const cEntityEffect & a_OtherEffect);
|
||||
|
||||
/** Creates an entity effect by copying another
|
||||
@param a_OtherEffect The other effect to copy */
|
||||
cEntityEffect & operator=(cEntityEffect a_OtherEffect);
|
||||
|
||||
virtual ~cEntityEffect(void) {};
|
||||
|
||||
/** Creates a pointer to the proper entity effect from the effect type
|
||||
@warning This function creates raw pointers that must be manually managed.
|
||||
@param a_EffectType The effect type to create the effect from
|
||||
@param a_Duration How long this effect will last, in ticks
|
||||
@param a_Intensity How strong the effect will be applied
|
||||
@param a_DistanceModifier The distance modifier for affecting potency, defaults to 1 */
|
||||
static cEntityEffect * CreateEntityEffect(cEntityEffect::eType a_EffectType, int a_Duration, short a_Intensity, double a_DistanceModifier);
|
||||
|
||||
/** Returns how many ticks this effect has been active for */
|
||||
int GetTicks(void) const { return m_Ticks; }
|
||||
|
||||
/** Returns the duration of the effect */
|
||||
int GetDuration(void) const { return m_Duration; }
|
||||
|
||||
/** Returns how strong the effect will be applied */
|
||||
short GetIntensity(void) const { return m_Intensity; }
|
||||
|
||||
/** Returns the distance modifier for affecting potency */
|
||||
double GetDistanceModifier(void) const { return m_DistanceModifier; }
|
||||
|
||||
void SetTicks(int a_Ticks) { m_Ticks = a_Ticks; }
|
||||
void SetDuration(int a_Duration) { m_Duration = a_Duration; }
|
||||
void SetIntensity(short a_Intensity) { m_Intensity = a_Intensity; }
|
||||
void SetDistanceModifier(double a_DistanceModifier) { m_DistanceModifier = a_DistanceModifier; }
|
||||
|
||||
/** Called on each tick.
|
||||
By default increases the m_Ticks, descendants may override to provide additional processing. */
|
||||
virtual void OnTick(cPawn & a_Target);
|
||||
|
||||
/** Called when the effect is first added to an entity */
|
||||
virtual void OnActivate(cPawn & a_Target) { }
|
||||
|
||||
/** Called when the effect is removed from an entity */
|
||||
virtual void OnDeactivate(cPawn & a_Target) { }
|
||||
|
||||
protected:
|
||||
/** How many ticks this effect has been active for */
|
||||
int m_Ticks;
|
||||
|
||||
/** How long this effect will last, in ticks */
|
||||
int m_Duration;
|
||||
|
||||
/** How strong the effect will be applied */
|
||||
short m_Intensity;
|
||||
|
||||
/** The distance modifier for affecting potency */
|
||||
double m_DistanceModifier;
|
||||
}; // tolua_export
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectSpeed:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectSpeed(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectSlowness:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectSlowness(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectHaste:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectHaste(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectMiningFatigue:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectMiningFatigue(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectStrength:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectStrength(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectInstantHealth:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectInstantHealth(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void OnActivate(cPawn & a_Target) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectInstantDamage:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectInstantDamage(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void OnActivate(cPawn & a_Target) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectJumpBoost:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectJumpBoost(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectNausea:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectNausea(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectRegeneration:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectRegeneration(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void OnTick(cPawn & a_Target) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectResistance:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectResistance(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectFireResistance:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectFireResistance(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectWaterBreathing:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectWaterBreathing(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectInvisibility:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectInvisibility(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectBlindness:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectBlindness(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectNightVision:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectNightVision(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectHunger:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectHunger(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
|
||||
// cEntityEffect overrides:
|
||||
virtual void OnTick(cPawn & a_Target) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectWeakness:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectWeakness(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
|
||||
// cEntityEffect overrides:
|
||||
virtual void OnTick(cPawn & a_Target) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectPoison:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectPoison(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
|
||||
// cEntityEffect overrides:
|
||||
virtual void OnTick(cPawn & a_Target) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectWither:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectWither(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
|
||||
// cEntityEffect overrides:
|
||||
virtual void OnTick(cPawn & a_Target) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectHealthBoost:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectHealthBoost(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectAbsorption:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectAbsorption(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntityEffectSaturation:
|
||||
public cEntityEffect
|
||||
{
|
||||
typedef cEntityEffect super;
|
||||
public:
|
||||
cEntityEffectSaturation(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
|
||||
super(a_Duration, a_Intensity, a_DistanceModifier)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void OnTick(cPawn & a_Target) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
@ -2,14 +2,16 @@
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "Pawn.h"
|
||||
#include "../World.h"
|
||||
#include "../Bindings/PluginManager.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cPawn::cPawn(eEntityType a_EntityType, double a_Width, double a_Height)
|
||||
: cEntity(a_EntityType, 0, 0, 0, a_Width, a_Height)
|
||||
, m_bBurnable(true)
|
||||
cPawn::cPawn(eEntityType a_EntityType, double a_Width, double a_Height):
|
||||
super(a_EntityType, 0, 0, 0, a_Width, a_Height),
|
||||
m_EntityEffects(tEffectMap())
|
||||
{
|
||||
}
|
||||
|
||||
@ -17,3 +19,95 @@ cPawn::cPawn(eEntityType a_EntityType, double a_Width, double a_Height)
|
||||
|
||||
|
||||
|
||||
void cPawn::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
// Iterate through this entity's applied effects
|
||||
for (tEffectMap::iterator iter = m_EntityEffects.begin(); iter != m_EntityEffects.end();)
|
||||
{
|
||||
// Copies values to prevent pesky wrong accesses and erasures
|
||||
cEntityEffect::eType EffectType = iter->first;
|
||||
cEntityEffect * Effect = iter->second;
|
||||
|
||||
Effect->OnTick(*this);
|
||||
|
||||
// Iterates (must be called before any possible erasure)
|
||||
++iter;
|
||||
|
||||
// Remove effect if duration has elapsed
|
||||
if (Effect->GetDuration() - Effect->GetTicks() <= 0)
|
||||
{
|
||||
RemoveEntityEffect(EffectType);
|
||||
}
|
||||
|
||||
// TODO: Check for discrepancies between client and server effect values
|
||||
}
|
||||
|
||||
super::Tick(a_Dt, a_Chunk);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPawn::KilledBy(TakeDamageInfo & a_TDI)
|
||||
{
|
||||
ClearEntityEffects();
|
||||
super::KilledBy(a_TDI);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPawn::AddEntityEffect(cEntityEffect::eType a_EffectType, int a_Duration, short a_Intensity, double a_DistanceModifier)
|
||||
{
|
||||
// Check if the plugins allow the addition:
|
||||
if (cPluginManager::Get()->CallHookEntityAddEffect(*this, a_EffectType, a_Duration, a_Intensity, a_DistanceModifier))
|
||||
{
|
||||
// A plugin disallows the addition, bail out.
|
||||
return;
|
||||
}
|
||||
|
||||
// No need to add empty effects:
|
||||
if (a_EffectType == cEntityEffect::effNoEffect)
|
||||
{
|
||||
return;
|
||||
}
|
||||
a_Duration = (int)(a_Duration * a_DistanceModifier);
|
||||
|
||||
m_EntityEffects[a_EffectType] = cEntityEffect::CreateEntityEffect(a_EffectType, a_Duration, a_Intensity, a_DistanceModifier);
|
||||
m_World->BroadcastEntityEffect(*this, a_EffectType, a_Intensity, a_Duration);
|
||||
m_EntityEffects[a_EffectType]->OnActivate(*this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPawn::RemoveEntityEffect(cEntityEffect::eType a_EffectType)
|
||||
{
|
||||
m_World->BroadcastRemoveEntityEffect(*this, a_EffectType);
|
||||
m_EntityEffects[a_EffectType]->OnDeactivate(*this);
|
||||
delete m_EntityEffects[a_EffectType];
|
||||
m_EntityEffects.erase(a_EffectType);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPawn::ClearEntityEffects()
|
||||
{
|
||||
// Iterate through this entity's applied effects
|
||||
for (tEffectMap::iterator iter = m_EntityEffects.begin(); iter != m_EntityEffects.end();)
|
||||
{
|
||||
// Copy values to prevent pesky wrong erasures
|
||||
cEntityEffect::eType EffectType = iter->first;
|
||||
|
||||
// Iterates (must be called before any possible erasure)
|
||||
++iter;
|
||||
|
||||
// Remove effect
|
||||
RemoveEntityEffect(EffectType);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Entity.h"
|
||||
#include "EntityEffect.h"
|
||||
|
||||
|
||||
|
||||
@ -19,8 +20,33 @@ public:
|
||||
|
||||
cPawn(eEntityType a_EntityType, double a_Width, double a_Height);
|
||||
|
||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
virtual void KilledBy(TakeDamageInfo & a_TDI) override;
|
||||
|
||||
// tolua_begin
|
||||
|
||||
/** Applies an entity effect
|
||||
Checks with plugins if they allow the addition.
|
||||
@param a_EffectType The entity effect to apply
|
||||
@param a_EffectDurationTicks The duration of the effect
|
||||
@param a_EffectIntensity The level of the effect (0 = Potion I, 1 = Potion II, etc)
|
||||
@param a_DistanceModifier The scalar multiplied to the potion duration, only applies to splash potions)
|
||||
*/
|
||||
void AddEntityEffect(cEntityEffect::eType a_EffectType, int a_EffectDurationTicks, short a_EffectIntensity, double a_DistanceModifier = 1);
|
||||
|
||||
/** Removes a currently applied entity effect
|
||||
@param a_EffectType The entity effect to remove
|
||||
*/
|
||||
void RemoveEntityEffect(cEntityEffect::eType a_EffectType);
|
||||
|
||||
/** Removes all currently applied entity effects (used when drinking milk) */
|
||||
void ClearEntityEffects(void);
|
||||
|
||||
// tolua_end
|
||||
|
||||
protected:
|
||||
bool m_bBurnable;
|
||||
typedef std::map<cEntityEffect::eType, cEntityEffect *> tEffectMap;
|
||||
tEffectMap m_EntityEffects;
|
||||
} ; // tolua_export
|
||||
|
||||
|
||||
|
@ -41,7 +41,6 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) :
|
||||
m_FoodSaturationLevel(5.0),
|
||||
m_FoodTickTimer(0),
|
||||
m_FoodExhaustionLevel(0.0),
|
||||
m_FoodPoisonedTicksRemaining(0),
|
||||
m_LastJumpHeight(0),
|
||||
m_LastGroundHeight(0),
|
||||
m_bTouchGround(false),
|
||||
@ -563,18 +562,9 @@ void cPlayer::SetFoodExhaustionLevel(double a_FoodExhaustionLevel)
|
||||
|
||||
|
||||
|
||||
void cPlayer::SetFoodPoisonedTicksRemaining(int a_FoodPoisonedTicksRemaining)
|
||||
{
|
||||
m_FoodPoisonedTicksRemaining = a_FoodPoisonedTicksRemaining;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cPlayer::Feed(int a_Food, double a_Saturation)
|
||||
{
|
||||
if (m_FoodLevel >= MAX_FOOD_LEVEL)
|
||||
if (IsSatiated())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -590,17 +580,7 @@ bool cPlayer::Feed(int a_Food, double a_Saturation)
|
||||
|
||||
void cPlayer::FoodPoison(int a_NumTicks)
|
||||
{
|
||||
bool HasBeenFoodPoisoned = (m_FoodPoisonedTicksRemaining > 0);
|
||||
m_FoodPoisonedTicksRemaining = std::max(m_FoodPoisonedTicksRemaining, a_NumTicks);
|
||||
if (!HasBeenFoodPoisoned)
|
||||
{
|
||||
m_World->BroadcastRemoveEntityEffect(*this, E_EFFECT_HUNGER);
|
||||
SendHealth();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_World->BroadcastEntityEffect(*this, E_EFFECT_HUNGER, 0, 400); // Give the player the "Hunger" effect for 20 seconds.
|
||||
}
|
||||
AddEntityEffect(cEntityEffect::effHunger, a_NumTicks, 0, NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -2015,17 +1995,6 @@ void cPlayer::HandleFood(void)
|
||||
}
|
||||
}
|
||||
|
||||
// Apply food poisoning food exhaustion:
|
||||
if (m_FoodPoisonedTicksRemaining > 0)
|
||||
{
|
||||
m_FoodPoisonedTicksRemaining--;
|
||||
m_FoodExhaustionLevel += 0.025; // 0.5 per second = 0.025 per tick
|
||||
}
|
||||
else
|
||||
{
|
||||
m_World->BroadcastRemoveEntityEffect(*this, E_EFFECT_HUNGER); // Remove the "Hunger" effect.
|
||||
}
|
||||
|
||||
// Apply food exhaustion that has accumulated:
|
||||
if (m_FoodExhaustionLevel >= 4.0)
|
||||
{
|
||||
|
@ -265,13 +265,12 @@ public:
|
||||
void TossPickup(const cItem & a_Item);
|
||||
|
||||
/** Heals the player by the specified amount of HPs (positive only); sends health update */
|
||||
void Heal(int a_Health);
|
||||
virtual void Heal(int a_Health) override;
|
||||
|
||||
int GetFoodLevel (void) const { return m_FoodLevel; }
|
||||
double GetFoodSaturationLevel (void) const { return m_FoodSaturationLevel; }
|
||||
int GetFoodTickTimer (void) const { return m_FoodTickTimer; }
|
||||
double GetFoodExhaustionLevel (void) const { return m_FoodExhaustionLevel; }
|
||||
int GetFoodPoisonedTicksRemaining(void) const { return m_FoodPoisonedTicksRemaining; }
|
||||
|
||||
/** Returns true if the player is satiated, i. e. their foodlevel is at the max and they cannot eat anymore */
|
||||
bool IsSatiated(void) const { return (m_FoodLevel >= MAX_FOOD_LEVEL); }
|
||||
@ -280,7 +279,6 @@ public:
|
||||
void SetFoodSaturationLevel (double a_FoodSaturationLevel);
|
||||
void SetFoodTickTimer (int a_FoodTickTimer);
|
||||
void SetFoodExhaustionLevel (double a_FoodExhaustionLevel);
|
||||
void SetFoodPoisonedTicksRemaining(int a_FoodPoisonedTicksRemaining);
|
||||
|
||||
/** Adds to FoodLevel and FoodSaturationLevel, returns true if any food has been consumed, false if player "full" */
|
||||
bool Feed(int a_Food, double a_Saturation);
|
||||
@ -291,7 +289,7 @@ public:
|
||||
m_FoodExhaustionLevel += a_Exhaustion;
|
||||
}
|
||||
|
||||
/** Starts the food poisoning for the specified amount of ticks; if already foodpoisoned, sets FoodPoisonedTicksRemaining to the larger of the two */
|
||||
/** Starts the food poisoning for the specified amount of ticks */
|
||||
void FoodPoison(int a_NumTicks);
|
||||
|
||||
/** Returns true if the player is currently in the process of eating the currently equipped item */
|
||||
@ -454,9 +452,6 @@ protected:
|
||||
/** A "buffer" which adds up hunger before it is substracted from m_FoodSaturationLevel or m_FoodLevel. Each action adds a little */
|
||||
double m_FoodExhaustionLevel;
|
||||
|
||||
/** Number of ticks remaining for the foodpoisoning effect; zero if not foodpoisoned */
|
||||
int m_FoodPoisonedTicksRemaining;
|
||||
|
||||
float m_LastJumpHeight;
|
||||
float m_LastGroundHeight;
|
||||
bool m_bTouchGround;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "FireChargeEntity.h"
|
||||
#include "FireworkEntity.h"
|
||||
#include "GhastFireballEntity.h"
|
||||
#include "WitherSkullEntity.h"
|
||||
#include "Player.h"
|
||||
|
||||
|
||||
@ -260,6 +261,7 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator,
|
||||
case pkGhastFireball: return new cGhastFireballEntity (a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
case pkFireCharge: return new cFireChargeEntity (a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
case pkExpBottle: return new cExpBottleEntity (a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
case pkWitherSkull: return new cWitherSkullEntity (a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
case pkFirework:
|
||||
{
|
||||
ASSERT(a_Item != NULL);
|
||||
@ -311,7 +313,7 @@ AString cProjectileEntity::GetMCAClassName(void) const
|
||||
case pkFireCharge: return "SmallFireball";
|
||||
case pkEnderPearl: return "ThrownEnderpearl";
|
||||
case pkExpBottle: return "ThrownExpBottle";
|
||||
case pkSplashPotion: return "ThrownPotion";
|
||||
case pkSplashPotion: return "SplashPotion";
|
||||
case pkWitherSkull: return "WitherSkull";
|
||||
case pkFirework: return "Firework";
|
||||
case pkFishingFloat: return ""; // Unknown, perhaps MC doesn't save this?
|
||||
|
120
src/Entities/SplashPotionEntity.cpp
Normal file
120
src/Entities/SplashPotionEntity.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "SplashPotionEntity.h"
|
||||
#include "Pawn.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cSplashPotionEntityCallback:
|
||||
|
||||
/** Used to distribute the splashed potion effect among nearby entities */
|
||||
class cSplashPotionCallback :
|
||||
public cEntityCallback
|
||||
{
|
||||
public:
|
||||
/** Creates the callback.
|
||||
@param a_HitPos The position where the splash potion has splashed
|
||||
@param a_EntityEffectType The effect type of the potion
|
||||
@param a_EntityEffect The effect description */
|
||||
cSplashPotionCallback(const Vector3d & a_HitPos, cEntityEffect::eType a_EntityEffectType, const cEntityEffect & a_EntityEffect) :
|
||||
m_HitPos(a_HitPos),
|
||||
m_EntityEffectType(a_EntityEffectType),
|
||||
m_EntityEffect(a_EntityEffect)
|
||||
{
|
||||
}
|
||||
|
||||
/** Called by cWorld::ForEachEntity(), adds the stored entity effect to the entity, if it is close enough. */
|
||||
virtual bool Item(cEntity * a_Entity) override
|
||||
{
|
||||
double SplashDistance = (a_Entity->GetPosition() - m_HitPos).Length();
|
||||
if (SplashDistance >= 20)
|
||||
{
|
||||
// Too far away
|
||||
return false;
|
||||
}
|
||||
if (!a_Entity->IsPawn())
|
||||
{
|
||||
// Not an entity that can take effects
|
||||
return false;
|
||||
}
|
||||
|
||||
// y = -0.25x + 1, where x is the distance from the player. Approximation for potion splash.
|
||||
// TODO: better equation
|
||||
double Reduction = -0.25 * SplashDistance + 1.0;
|
||||
if (Reduction < 0)
|
||||
{
|
||||
Reduction = 0;
|
||||
}
|
||||
|
||||
((cPawn *) a_Entity)->AddEntityEffect(m_EntityEffectType, m_EntityEffect.GetDuration(), m_EntityEffect.GetIntensity(), Reduction);
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
const Vector3d & m_HitPos;
|
||||
cEntityEffect::eType m_EntityEffectType;
|
||||
const cEntityEffect & m_EntityEffect;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cSplashPotionEntity:
|
||||
|
||||
cSplashPotionEntity::cSplashPotionEntity(
|
||||
cEntity * a_Creator,
|
||||
double a_X, double a_Y, double a_Z,
|
||||
const Vector3d & a_Speed,
|
||||
cEntityEffect::eType a_EntityEffectType,
|
||||
cEntityEffect a_EntityEffect,
|
||||
int a_PotionParticleType
|
||||
) :
|
||||
super(pkSplashPotion, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25),
|
||||
m_EntityEffectType(a_EntityEffectType),
|
||||
m_EntityEffect(a_EntityEffect),
|
||||
m_PotionParticleType(a_PotionParticleType)
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSplashPotionEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||
{
|
||||
Splash(a_HitPos);
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSplashPotionEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
{
|
||||
a_EntityHit.TakeDamage(dtRangedAttack, this, 0, 1);
|
||||
Splash(a_HitPos);
|
||||
Destroy(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSplashPotionEntity::Splash(const Vector3d & a_HitPos)
|
||||
{
|
||||
cSplashPotionCallback Callback(a_HitPos, m_EntityEffectType, m_EntityEffect);
|
||||
m_World->ForEachEntity(Callback);
|
||||
|
||||
m_World->BroadcastSoundParticleEffect(2002, (int)a_HitPos.x, (int)a_HitPos.y, (int)a_HitPos.z, m_PotionParticleType);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
59
src/Entities/SplashPotionEntity.h
Normal file
59
src/Entities/SplashPotionEntity.h
Normal file
@ -0,0 +1,59 @@
|
||||
//
|
||||
// SplashPotionEntity.h
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ProjectileEntity.h"
|
||||
#include "EntityEffect.h"
|
||||
#include "../World.h"
|
||||
#include "Entity.h"
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
class cSplashPotionEntity :
|
||||
public cProjectileEntity
|
||||
{
|
||||
typedef cProjectileEntity super;
|
||||
|
||||
public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
CLASS_PROTODEF(cSplashPotionEntity);
|
||||
|
||||
cSplashPotionEntity(
|
||||
cEntity * a_Creator,
|
||||
double a_X, double a_Y, double a_Z,
|
||||
const Vector3d & a_Speed,
|
||||
cEntityEffect::eType a_EntityEffectType,
|
||||
cEntityEffect a_EntityEffect,
|
||||
int a_PotionParticleType
|
||||
);
|
||||
|
||||
cEntityEffect::eType GetEntityEffectType (void) const { return m_EntityEffectType; }
|
||||
cEntityEffect GetEntityEffect (void) const { return m_EntityEffect; }
|
||||
int GetPotionParticleType(void) const { return m_PotionParticleType; }
|
||||
|
||||
void SetEntityEffectType(cEntityEffect::eType a_EntityEffectType) { m_EntityEffectType = a_EntityEffectType; }
|
||||
void SetEntityEffect(cEntityEffect a_EntityEffect) { m_EntityEffect = a_EntityEffect; }
|
||||
void SetPotionParticleType(int a_PotionParticleType) { m_PotionParticleType = a_PotionParticleType; }
|
||||
|
||||
protected:
|
||||
|
||||
cEntityEffect::eType m_EntityEffectType;
|
||||
cEntityEffect m_EntityEffect;
|
||||
int m_PotionParticleType;
|
||||
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||
|
||||
/** Splashes the potion, fires its particle effects and sounds
|
||||
@param a_HitPos The position where the potion will splash */
|
||||
void Splash(const Vector3d & a_HitPos);
|
||||
} ; // tolua_export
|
49
src/Entities/WitherSkullEntity.cpp
Normal file
49
src/Entities/WitherSkullEntity.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
|
||||
// WitherSkullEntity.cpp
|
||||
|
||||
// Implements the cWitherSkullEntity class representing the entity used by both blue and black wither skulls
|
||||
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "WitherSkullEntity.h"
|
||||
#include "../World.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cWitherSkullEntity::cWitherSkullEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||
super(pkWitherSkull, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWitherSkullEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||
{
|
||||
// TODO: Explode
|
||||
// TODO: Apply wither effect to entities nearby
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWitherSkullEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
{
|
||||
// TODO: If entity is Ender Crystal, destroy it
|
||||
a_EntityHit.TakeDamage(dtRangedAttack, this, 0, 1);
|
||||
|
||||
// TODO: Explode
|
||||
// TODO: Apply wither effect to entity and others nearby
|
||||
|
||||
Destroy(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
35
src/Entities/WitherSkullEntity.h
Normal file
35
src/Entities/WitherSkullEntity.h
Normal file
@ -0,0 +1,35 @@
|
||||
|
||||
// WitherSkullEntity.h
|
||||
|
||||
// Declares the cWitherSkullEntity class representing the entity used by both blue and black wither skulls
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ProjectileEntity.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
class cWitherSkullEntity :
|
||||
public cProjectileEntity
|
||||
{
|
||||
typedef cProjectileEntity super;
|
||||
|
||||
public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
CLASS_PROTODEF(cWitherSkullEntity);
|
||||
|
||||
cWitherSkullEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||
|
||||
protected:
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||
|
||||
} ; // tolua_export
|
@ -383,6 +383,5 @@ T Clamp(T a_Value, T a_Min, T a_Max)
|
||||
#include "BiomeDef.h"
|
||||
#include "BlockID.h"
|
||||
#include "BlockInfo.h"
|
||||
#include "Entities/Effects.h"
|
||||
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "ItemCloth.h"
|
||||
#include "ItemComparator.h"
|
||||
#include "ItemDoor.h"
|
||||
#include "ItemMilk.h"
|
||||
#include "ItemDye.h"
|
||||
#include "ItemEmptyMap.h"
|
||||
#include "ItemFishingRod.h"
|
||||
@ -34,6 +35,7 @@
|
||||
#include "ItemNetherWart.h"
|
||||
#include "ItemPainting.h"
|
||||
#include "ItemPickaxe.h"
|
||||
#include "ItemPotion.h"
|
||||
#include "ItemThrowable.h"
|
||||
#include "ItemRedstoneDust.h"
|
||||
#include "ItemRedstoneRepeater.h"
|
||||
@ -120,9 +122,11 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
|
||||
case E_ITEM_FLOWER_POT: return new cItemFlowerPotHandler(a_ItemType);
|
||||
case E_BLOCK_LILY_PAD: return new cItemLilypadHandler(a_ItemType);
|
||||
case E_ITEM_MAP: return new cItemMapHandler();
|
||||
case E_ITEM_MILK: return new cItemMilkHandler();
|
||||
case E_ITEM_ITEM_FRAME: return new cItemItemFrameHandler(a_ItemType);
|
||||
case E_ITEM_NETHER_WART: return new cItemNetherWartHandler(a_ItemType);
|
||||
case E_ITEM_PAINTING: return new cItemPaintingHandler(a_ItemType);
|
||||
case E_ITEM_POTIONS: return new cItemPotionHandler();
|
||||
case E_ITEM_REDSTONE_DUST: return new cItemRedstoneDustHandler(a_ItemType);
|
||||
case E_ITEM_REDSTONE_REPEATER: return new cItemRedstoneRepeaterHandler(a_ItemType);
|
||||
case E_ITEM_SHEARS: return new cItemShearsHandler(a_ItemType);
|
||||
@ -470,33 +474,17 @@ bool cItemHandler::IsTool()
|
||||
|
||||
bool cItemHandler::IsFood(void)
|
||||
{
|
||||
switch (m_ItemType)
|
||||
{
|
||||
case E_ITEM_RED_APPLE:
|
||||
case E_ITEM_GOLDEN_APPLE:
|
||||
case E_ITEM_MUSHROOM_SOUP:
|
||||
case E_ITEM_BREAD:
|
||||
case E_ITEM_RAW_PORKCHOP:
|
||||
case E_ITEM_COOKED_PORKCHOP:
|
||||
case E_ITEM_MILK:
|
||||
case E_ITEM_RAW_FISH:
|
||||
case E_ITEM_COOKED_FISH:
|
||||
case E_ITEM_COOKIE:
|
||||
case E_ITEM_MELON_SLICE:
|
||||
case E_ITEM_RAW_BEEF:
|
||||
case E_ITEM_STEAK:
|
||||
case E_ITEM_RAW_CHICKEN:
|
||||
case E_ITEM_COOKED_CHICKEN:
|
||||
case E_ITEM_ROTTEN_FLESH:
|
||||
case E_ITEM_SPIDER_EYE:
|
||||
case E_ITEM_CARROT:
|
||||
case E_ITEM_POTATO:
|
||||
case E_ITEM_BAKED_POTATO:
|
||||
case E_ITEM_POISONOUS_POTATO:
|
||||
{
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
} // switch (m_ItemType)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cItemHandler::IsDrinkable(short a_ItemDamage)
|
||||
{
|
||||
UNUSED(a_ItemDamage);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -580,7 +568,7 @@ bool cItemHandler::EatItem(cPlayer * a_Player, cItem * a_Item)
|
||||
cFastRandom r1;
|
||||
if ((r1.NextInt(100, a_Player->GetUniqueID()) - Info.PoisonChance) <= 0)
|
||||
{
|
||||
a_Player->FoodPoison(300);
|
||||
a_Player->FoodPoison(600); // Give the player food poisoning for 30 seconds.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,9 @@ public:
|
||||
/** Indicates if this item is food */
|
||||
virtual bool IsFood(void);
|
||||
|
||||
/** Indicates if this item is drinkable */
|
||||
virtual bool IsDrinkable(short a_ItemDamage);
|
||||
|
||||
/** Blocks simply get placed */
|
||||
virtual bool IsPlaceable(void);
|
||||
|
||||
@ -99,7 +102,7 @@ public:
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
);
|
||||
|
||||
/** Returns whether this tool/item can harvest a specific block (e.g. wooden pickaxe can harvest stone, but wood can<EFBFBD>t) DEFAULT: False */
|
||||
/** Returns whether this tool/item can harvest a specific block (e.g. wooden pickaxe can harvest stone, but wood can't) DEFAULT: False */
|
||||
virtual bool CanHarvestBlock(BLOCKTYPE a_BlockType);
|
||||
|
||||
static cItemHandler * GetItemHandler(int a_ItemType);
|
||||
|
28
src/Items/ItemMilk.h
Normal file
28
src/Items/ItemMilk.h
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
class cItemMilkHandler:
|
||||
public cItemHandler
|
||||
{
|
||||
typedef cItemHandler super;
|
||||
public:
|
||||
cItemMilkHandler():
|
||||
super(E_ITEM_MILK)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool IsDrinkable(short a_ItemDamage) override
|
||||
{
|
||||
UNUSED(a_ItemDamage);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool EatItem(cPlayer * a_Player, cItem * a_Item) override
|
||||
{
|
||||
UNUSED(a_Item);
|
||||
a_Player->ClearEntityEffects();
|
||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||
a_Player->GetInventory().AddItem(E_ITEM_BUCKET);
|
||||
return true;
|
||||
}
|
||||
};
|
199
src/Items/ItemPotion.h
Normal file
199
src/Items/ItemPotion.h
Normal file
@ -0,0 +1,199 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Entities/EntityEffect.h"
|
||||
#include "../Entities/SplashPotionEntity.h"
|
||||
|
||||
class cItemPotionHandler:
|
||||
public cItemHandler
|
||||
{
|
||||
typedef cItemHandler super;
|
||||
|
||||
public:
|
||||
|
||||
cItemPotionHandler():
|
||||
super(E_ITEM_POTION)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/** Returns the potion particle type (used by the client for visuals), based on the potion's damage value */
|
||||
static int GetPotionParticleType(short a_ItemDamage)
|
||||
{
|
||||
// Lowest six bits
|
||||
return (a_ItemDamage & 0x3f);
|
||||
}
|
||||
|
||||
|
||||
/** Translates the potion's damage value into the entity effect that the potion gives */
|
||||
static cEntityEffect::eType GetEntityEffectType(short a_ItemDamage)
|
||||
{
|
||||
// Lowest four bits
|
||||
// Potion effect bits are different from entity effect values
|
||||
// For reference: http://minecraft.gamepedia.com/Data_values#.22Potion_effect.22_bits
|
||||
switch (a_ItemDamage & 0x0f)
|
||||
{
|
||||
case 0x01: return cEntityEffect::effRegeneration;
|
||||
case 0x02: return cEntityEffect::effSpeed;
|
||||
case 0x03: return cEntityEffect::effFireResistance;
|
||||
case 0x04: return cEntityEffect::effPoison;
|
||||
case 0x05: return cEntityEffect::effInstantHealth;
|
||||
case 0x06: return cEntityEffect::effNightVision;
|
||||
case 0x08: return cEntityEffect::effWeakness;
|
||||
case 0x09: return cEntityEffect::effStrength;
|
||||
case 0x0a: return cEntityEffect::effSlowness;
|
||||
case 0x0c: return cEntityEffect::effInstantDamage;
|
||||
case 0x0d: return cEntityEffect::effWaterBreathing;
|
||||
case 0x0e: return cEntityEffect::effInvisibility;
|
||||
|
||||
// No effect potions
|
||||
case 0x00:
|
||||
case 0x07:
|
||||
case 0x0b: // Will be potion of leaping in 1.8
|
||||
case 0x0f:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return cEntityEffect::effNoEffect;
|
||||
}
|
||||
|
||||
|
||||
/** Retrieves the intensity level from the potion's damage value.
|
||||
Returns 0 for level I potions, 1 for level II potions. */
|
||||
static short GetEntityEffectIntensity(short a_ItemDamage)
|
||||
{
|
||||
// Level II potion if the fifth lowest bit is set
|
||||
return ((a_ItemDamage & 0x20) != 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
/** Returns the effect duration, in ticks, based on the potion's damage value */
|
||||
static int GetEntityEffectDuration(short a_ItemDamage)
|
||||
{
|
||||
// Base duration in ticks
|
||||
int base = 0;
|
||||
double TierCoeff = 1, ExtCoeff = 1, SplashCoeff = 1;
|
||||
|
||||
switch (GetEntityEffectType(a_ItemDamage))
|
||||
{
|
||||
case cEntityEffect::effRegeneration:
|
||||
case cEntityEffect::effPoison:
|
||||
{
|
||||
base = 900;
|
||||
break;
|
||||
}
|
||||
|
||||
case cEntityEffect::effSpeed:
|
||||
case cEntityEffect::effFireResistance:
|
||||
case cEntityEffect::effNightVision:
|
||||
case cEntityEffect::effStrength:
|
||||
case cEntityEffect::effWaterBreathing:
|
||||
case cEntityEffect::effInvisibility:
|
||||
{
|
||||
base = 3600;
|
||||
break;
|
||||
}
|
||||
|
||||
case cEntityEffect::effWeakness:
|
||||
case cEntityEffect::effSlowness:
|
||||
{
|
||||
base = 1800;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If potion is level II, half the duration. If not, stays the same
|
||||
TierCoeff = (GetEntityEffectIntensity(a_ItemDamage) > 0) ? 0.5 : 1;
|
||||
|
||||
// If potion is extended, multiply duration by 8/3. If not, stays the same
|
||||
// Extended potion if sixth lowest bit is set
|
||||
ExtCoeff = (a_ItemDamage & 0x40) ? (8.0 / 3.0) : 1;
|
||||
|
||||
// If potion is splash potion, multiply duration by 3/4. If not, stays the same
|
||||
SplashCoeff = IsPotionDrinkable(a_ItemDamage) ? 1 : 0.75;
|
||||
|
||||
// Ref.:
|
||||
// http://minecraft.gamepedia.com/Data_values#.22Tier.22_bit
|
||||
// http://minecraft.gamepedia.com/Data_values#.22Extended_duration.22_bit
|
||||
// http://minecraft.gamepedia.com/Data_values#.22Splash_potion.22_bit
|
||||
|
||||
return (int)(base * TierCoeff * ExtCoeff * SplashCoeff);
|
||||
}
|
||||
|
||||
|
||||
/** Returns true if the potion with the given damage is drinkable */
|
||||
static bool IsPotionDrinkable(short a_ItemDamage)
|
||||
{
|
||||
// Drinkable potion if 13th lowest bit is set
|
||||
// Ref.: http://minecraft.gamepedia.com/Potions#Data_value_table
|
||||
return ((a_ItemDamage & 0x2000) != 0);
|
||||
}
|
||||
|
||||
|
||||
// cItemHandler overrides:
|
||||
virtual bool IsDrinkable(short a_ItemDamage) override
|
||||
{
|
||||
// Drinkable potion if 13th lowest bit is set
|
||||
// Ref.: http://minecraft.gamepedia.com/Potions#Data_value_table
|
||||
return IsPotionDrinkable(a_ItemDamage);
|
||||
}
|
||||
|
||||
|
||||
virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override
|
||||
{
|
||||
short PotionDamage = a_Item.m_ItemDamage;
|
||||
|
||||
// Do not throw non-splash potions:
|
||||
if (IsPotionDrinkable(PotionDamage))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector3d Pos = a_Player->GetThrowStartPos();
|
||||
Vector3d Speed = a_Player->GetLookVector() * 7;
|
||||
|
||||
cSplashPotionEntity * Projectile = new cSplashPotionEntity(
|
||||
a_Player, Pos.x, Pos.y, Pos.z, Speed,
|
||||
GetEntityEffectType(PotionDamage), cEntityEffect(GetEntityEffectDuration(PotionDamage),
|
||||
GetEntityEffectIntensity(PotionDamage)), GetPotionParticleType(PotionDamage)
|
||||
);
|
||||
if (Projectile == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!Projectile->Initialize(*a_World))
|
||||
{
|
||||
delete Projectile;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!a_Player->IsGameModeCreative())
|
||||
{
|
||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
virtual bool EatItem(cPlayer * a_Player, cItem * a_Item) override
|
||||
{
|
||||
short PotionDamage = a_Item->m_ItemDamage;
|
||||
|
||||
// Do not drink undrinkable potions:
|
||||
if (!IsDrinkable(a_Item->m_ItemDamage))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
a_Player->AddEntityEffect(GetEntityEffectType(PotionDamage), GetEntityEffectDuration(PotionDamage), GetEntityEffectIntensity(PotionDamage));
|
||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||
a_Player->GetInventory().AddItem(E_ITEM_GLASS_BOTTLE);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
@ -95,13 +95,15 @@ void cAggressiveMonster::Attack(float a_Dt)
|
||||
{
|
||||
m_AttackInterval += a_Dt * m_AttackRate;
|
||||
|
||||
if ((m_Target != NULL) && (m_AttackInterval > 3.0))
|
||||
if ((m_Target == NULL) || (m_AttackInterval < 3.0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Setting this higher gives us more wiggle room for attackrate
|
||||
m_AttackInterval = 0.0;
|
||||
m_Target->TakeDamage(dtMobAttack, this, m_AttackDamage, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -27,6 +27,21 @@ void cCaveSpider::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
|
||||
|
||||
|
||||
void cCaveSpider::Attack(float a_Dt)
|
||||
{
|
||||
super::Attack(a_Dt);
|
||||
|
||||
if (m_Target->IsPawn())
|
||||
{
|
||||
// TODO: Easy = no poison, Medium = 7 seconds, Hard = 15 seconds
|
||||
((cPawn *) m_Target)->AddEntityEffect(cEntityEffect::effPoison, 7 * 20, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCaveSpider::GetDrops(cItems & a_Drops, cEntity * a_Killer)
|
||||
{
|
||||
int LootingLevel = 0;
|
||||
|
@ -17,6 +17,7 @@ public:
|
||||
CLASS_PROTODEF(cCaveSpider);
|
||||
|
||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
virtual void Attack(float a_Dt) override;
|
||||
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
|
||||
} ;
|
||||
|
||||
|
@ -435,6 +435,7 @@ void cMonster::HandleFalling()
|
||||
|
||||
|
||||
|
||||
|
||||
int cMonster::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ)
|
||||
{
|
||||
int PosY = POSY_TOINT;
|
||||
@ -706,6 +707,25 @@ void cMonster::GetMonsterConfig(const AString & a_Name)
|
||||
|
||||
|
||||
|
||||
bool cMonster::IsUndead(void)
|
||||
{
|
||||
switch (GetMobType())
|
||||
{
|
||||
case mtZombie:
|
||||
case mtZombiePigman:
|
||||
case mtSkeleton:
|
||||
case mtWither:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AString cMonster::MobTypeToString(cMonster::eType a_MobType)
|
||||
{
|
||||
// Mob types aren't sorted, so we need to search linearly:
|
||||
|
@ -107,6 +107,9 @@ public:
|
||||
/// Reads the monster configuration for the specified monster name and assigns it to this object.
|
||||
void GetMonsterConfig(const AString & a_Name);
|
||||
|
||||
/** Returns whether this mob is undead (skeleton, zombie, etc.) */
|
||||
bool IsUndead(void);
|
||||
|
||||
virtual void EventLosePlayer(void);
|
||||
virtual void CheckEventLostPlayer(void);
|
||||
|
||||
@ -178,6 +181,7 @@ protected:
|
||||
|
||||
/** Stores if mobile is currently moving towards the ultimate, final destination */
|
||||
bool m_bMovingToDestination;
|
||||
|
||||
/** Finds the first non-air block position (not the highest, as cWorld::GetHeight does)
|
||||
If current Y is nonsolid, goes down to try to find a solid block, then returns that + 1
|
||||
If current Y is solid, goes up to find first nonsolid block, and returns that */
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "../Entities/Minecart.h"
|
||||
#include "../Entities/Pickup.h"
|
||||
#include "../Entities/ArrowEntity.h"
|
||||
#include "../Entities/SplashPotionEntity.h"
|
||||
#include "../Entities/TNTEntity.h"
|
||||
#include "../Entities/ExpOrb.h"
|
||||
#include "../Entities/HangingEntity.h"
|
||||
@ -604,6 +605,16 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile)
|
||||
m_Writer.AddDouble("damage", Arrow->GetDamageCoeff());
|
||||
break;
|
||||
}
|
||||
case cProjectileEntity::pkSplashPotion:
|
||||
{
|
||||
cSplashPotionEntity * Potion = (cSplashPotionEntity *)a_Projectile;
|
||||
|
||||
m_Writer.AddInt("EffectType", (Int16)Potion->GetEntityEffectType());
|
||||
m_Writer.AddInt("EffectDuration", (Int16)Potion->GetEntityEffect().GetDuration());
|
||||
m_Writer.AddShort("EffectIntensity", Potion->GetEntityEffect().GetIntensity());
|
||||
m_Writer.AddDouble("EffectDistanceModifier", Potion->GetEntityEffect().GetDistanceModifier());
|
||||
m_Writer.AddInt("PotionName", Potion->GetPotionParticleType());
|
||||
}
|
||||
case cProjectileEntity::pkGhastFireball:
|
||||
{
|
||||
m_Writer.AddInt("ExplosionPower", 1);
|
||||
|
@ -46,6 +46,7 @@ class cTNTEntity;
|
||||
class cExpOrb;
|
||||
class cHangingEntity;
|
||||
class cItemFrame;
|
||||
class cEntityEffect;
|
||||
|
||||
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "../Entities/Minecart.h"
|
||||
#include "../Entities/Pickup.h"
|
||||
#include "../Entities/ArrowEntity.h"
|
||||
#include "../Entities/SplashPotionEntity.h"
|
||||
#include "../Entities/ThrownEggEntity.h"
|
||||
#include "../Entities/ThrownEnderPearlEntity.h"
|
||||
#include "../Entities/ThrownSnowballEntity.h"
|
||||
@ -1156,6 +1157,10 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
|
||||
{
|
||||
LoadArrowFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||
}
|
||||
else if (strncmp(a_IDTag, "SplashPotion", a_IDTagLength) == 0)
|
||||
{
|
||||
LoadSplashPotionFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||
}
|
||||
else if (strncmp(a_IDTag, "Snowball", a_IDTagLength) == 0)
|
||||
{
|
||||
LoadSnowballFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||
@ -1662,6 +1667,29 @@ void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadSplashPotionFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
{
|
||||
std::auto_ptr<cSplashPotionEntity> SplashPotion(new cSplashPotionEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0), cEntityEffect::effNoEffect, cEntityEffect(), 0));
|
||||
if (!LoadProjectileBaseFromNBT(*SplashPotion.get(), a_NBT, a_TagIdx))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int EffectDuration = a_NBT.FindChildByName(a_TagIdx, "EffectDuration");
|
||||
int EffectIntensity = a_NBT.FindChildByName(a_TagIdx, "EffectIntensity");
|
||||
int EffectDistanceModifier = a_NBT.FindChildByName(a_TagIdx, "EffectDistanceModifier");
|
||||
|
||||
SplashPotion->SetEntityEffectType((cEntityEffect::eType) a_NBT.FindChildByName(a_TagIdx, "EffectType"));
|
||||
SplashPotion->SetEntityEffect(cEntityEffect(EffectDuration, EffectIntensity, EffectDistanceModifier));
|
||||
SplashPotion->SetPotionParticleType(a_NBT.FindChildByName(a_TagIdx, "PotionName"));
|
||||
|
||||
// Store the new splash potion in the entities list:
|
||||
a_Entities.push_back(SplashPotion.release());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadSnowballFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
{
|
||||
|
@ -163,6 +163,7 @@ protected:
|
||||
void LoadMinecartHFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
|
||||
void LoadArrowFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadSplashPotionFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadSnowballFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadEggFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadFireballFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
|
Loading…
Reference in New Issue
Block a user