That's one heck of a commit you've got there...
I may have got a bit behind with version control. A lot behind, in fact. Maybe I'll go back and split this sometime - then again, I probably won't. But hey, at least it's here!
This commit is contained in:
@@ -0,0 +1,234 @@
|
||||
package electroblob.wizardry.util;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.data.WizardData;
|
||||
import electroblob.wizardry.registry.WizardryPotions;
|
||||
import electroblob.wizardry.spell.MindControl;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.IEntityOwnable;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraftforge.common.util.FakePlayer;
|
||||
import net.minecraftforge.event.entity.living.LivingAttackEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
|
||||
/**
|
||||
* Contains some useful static methods for interacting with the ally designation system. Also handles the friendly fire
|
||||
* setting. This was split off from {@link WizardryUtilities} as of wizardry 4.2 in an effort to make the code easier to
|
||||
* navigate.
|
||||
*/
|
||||
@Mod.EventBusSubscriber
|
||||
public final class AllyDesignationSystem {
|
||||
|
||||
private AllyDesignationSystem(){} // No instances!
|
||||
|
||||
/** Set of constants for each of the four friendly fire settings. */
|
||||
public enum FriendlyFire {
|
||||
|
||||
ALL("All", false, false),
|
||||
ONLY_PLAYERS("Only players", false, true),
|
||||
ONLY_OWNED("Only summoned/tamed creatures", true, false),
|
||||
NONE("None", true, true);
|
||||
|
||||
/** Constant array storing the names of each of the constants, in the order they are declared. */
|
||||
public static final String[] names;
|
||||
|
||||
static {
|
||||
names = new String[values().length];
|
||||
for(FriendlyFire setting : values()){
|
||||
names[setting.ordinal()] = setting.name;
|
||||
}
|
||||
}
|
||||
|
||||
/** The readable name for this friendly fire setting that will be displayed on the button in the config GUI. */
|
||||
public final String name;
|
||||
public final boolean blockPlayers;
|
||||
public final boolean blockOwned;
|
||||
|
||||
FriendlyFire(String name, boolean blockPlayers, boolean blockOwned){
|
||||
this.name = name;
|
||||
this.blockPlayers = blockPlayers;
|
||||
this.blockOwned = blockOwned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a friendly fire setting from its string name (ignoring case), or ALL if the given name is not a valid
|
||||
* setting.
|
||||
*/
|
||||
public static FriendlyFire fromName(String name){
|
||||
|
||||
for(FriendlyFire setting : values()){
|
||||
if(setting.name.equalsIgnoreCase(name)) return setting;
|
||||
}
|
||||
|
||||
Wizardry.logger.info("Invalid string for the friendly fire setting. Using default (all) instead.");
|
||||
return ALL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given target can be attacked by the given attacker. It is up to the caller of this method to
|
||||
* work out what this means; it doesn't necessarily mean the target is completely immune (for example, revenge
|
||||
* targeting might reasonably bypass this). This method is intended for use where the damage is indirect and/or
|
||||
* unavoidable; direct attacks should not check this method. Currently this means the following situations check
|
||||
* this method:
|
||||
* <p></p>
|
||||
* - AI targeting for summoned creatures<br>
|
||||
* - AI targeting for mind-controlled creatures<br>
|
||||
* - Constructs with an area of effect<br>
|
||||
* - Instantaneous spells with an area of effect around the caster (e.g. forest's curse, thunderstorm)<br>
|
||||
* - Any lightning chaining effects<br>
|
||||
* - Any projectiles which seek targets
|
||||
* <p></p>
|
||||
* Also note that the friendly fire option is dealt with in the event handler. This method acts as a sort of wrapper
|
||||
* for all the AllyDesignationSystem stuff in {@link WizardData}; more details about the ally designation system can be found there.
|
||||
*
|
||||
* @param attacker The entity that cast the spell originally
|
||||
* @param target The entity being attacked
|
||||
*
|
||||
* @return False under any of the following circumstances, true otherwise:
|
||||
* <p></p>
|
||||
* - The target is null
|
||||
* <p></p>
|
||||
* - The target is the attacker (this isn't as stupid as it sounds - anything with an AoE might cause this
|
||||
* to be true, as can summoned creatures)
|
||||
* <p></p>
|
||||
* - The target and the attacker are both players and the target is an ally of the attacker (but the
|
||||
* attacker need not be an ally of the target)
|
||||
* <p></p>
|
||||
* - The target is a creature that was summoned/controlled by the attacker or by an ally of the attacker.
|
||||
* <p></p>
|
||||
* - The target is a creature that was tamed by the attacker or by an ally of the attacker
|
||||
* (see {@link net.minecraft.entity.IEntityOwnable}).
|
||||
* <p></p>
|
||||
* <i>As of wizardry 4.1.2, this method now returns <b>true</b> instead of false if the attacker is null. This
|
||||
* is because in the vast majority of cases, it makes more sense this way: if a construct has no caster, it
|
||||
* should affect all entities; if a minion has no caster it should target all entities; etc.</i>
|
||||
*/
|
||||
public static boolean isValidTarget(Entity attacker, Entity target){
|
||||
|
||||
// Always return true if the attacker is null
|
||||
if(attacker == null) return true;
|
||||
|
||||
// Always return false if the target is null
|
||||
if(target == null) return false;
|
||||
|
||||
// Tests whether the target is the attacker
|
||||
if(target == attacker) return false;
|
||||
|
||||
// I really shouldn't need to do this, but fake players seem to break stuff...
|
||||
if(target instanceof FakePlayer) return false;
|
||||
|
||||
// Tests whether the target is a creature that was summoned by the attacker
|
||||
// if(target instanceof ISummonedCreature && ((ISummonedCreature)target).getCaster() == attacker){
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// Tests whether the target is a creature that was summoned/tamed (or is otherwise owned) by the attacker
|
||||
if(target instanceof IEntityOwnable && ((IEntityOwnable)target).getOwner() == attacker){
|
||||
return false;
|
||||
}
|
||||
|
||||
// Tests whether the target is a creature that was mind controlled by the attacker
|
||||
if(target instanceof EntityLiving && ((EntityLivingBase)target).isPotionActive(WizardryPotions.mind_control)){
|
||||
|
||||
NBTTagCompound entityNBT = target.getEntityData();
|
||||
|
||||
if(entityNBT != null && entityNBT.hasUniqueId(MindControl.NBT_KEY)){
|
||||
if(attacker == WizardryUtilities.getEntityByUUID(target.world,
|
||||
entityNBT.getUniqueId(MindControl.NBT_KEY))){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ally section
|
||||
if(attacker instanceof EntityPlayer && WizardData.get((EntityPlayer)attacker) != null){
|
||||
|
||||
if(target instanceof EntityPlayer){
|
||||
// Tests whether the target is an ally of the attacker
|
||||
if(WizardData.get((EntityPlayer)attacker).isPlayerAlly((EntityPlayer)target)){
|
||||
return false;
|
||||
}
|
||||
|
||||
// }else if(target instanceof ISummonedCreature){
|
||||
// // Tests whether the target is a creature that was summoned by an ally of the attacker
|
||||
// if(((ISummonedCreature)target).getCaster() instanceof EntityPlayer && WizardData.get((EntityPlayer)attacker)
|
||||
// .isPlayerAlly((EntityPlayer)((ISummonedCreature)target).getCaster())){
|
||||
// return false;
|
||||
// }
|
||||
|
||||
}else if(target instanceof IEntityOwnable){
|
||||
// Tests whether the target is a creature that was summoned/tamed by an ally of the attacker
|
||||
if(isOwnerAlly((EntityPlayer)attacker, (IEntityOwnable)target));
|
||||
|
||||
}else if(target instanceof EntityLiving && ((EntityLivingBase)target).isPotionActive(WizardryPotions.mind_control)){
|
||||
// Tests whether the target is a creature that was mind controlled by an ally of the attacker
|
||||
NBTTagCompound entityNBT = target.getEntityData();
|
||||
|
||||
if(entityNBT != null && entityNBT.hasKey(MindControl.NBT_KEY)){
|
||||
|
||||
Entity controller = WizardryUtilities.getEntityByUUID(target.world, entityNBT.getUniqueId(MindControl.NBT_KEY));
|
||||
|
||||
if(controller instanceof EntityPlayer && WizardData.get((EntityPlayer)attacker).isPlayerAlly((EntityPlayer)controller)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Umbrella method that covers both {@link AllyDesignationSystem#isPlayerAlly(EntityPlayer, EntityPlayer)} and
|
||||
* {@link AllyDesignationSystem#isOwnerAlly(EntityPlayer, IEntityOwnable)}, returning true if the given
|
||||
* {@link EntityLivingBase} is either owned by the given player, an ally of the given player or owned by an ally
|
||||
* of the given player. This is generally used to determine targets for healing or other group buffs. */
|
||||
public static boolean isAllied(EntityPlayer allyOf, EntityLivingBase possibleAlly){
|
||||
return (possibleAlly instanceof EntityPlayer && isPlayerAlly(allyOf, (EntityPlayer)possibleAlly))
|
||||
|| (possibleAlly instanceof IEntityOwnable && (((IEntityOwnable)possibleAlly).getOwner() == allyOf
|
||||
|| isOwnerAlly(allyOf, (IEntityOwnable)possibleAlly)));
|
||||
}
|
||||
|
||||
/** Helper method for testing if the second player is an ally of the first player. Makes the code neater.
|
||||
* @see AllyDesignationSystem#isOwnerAlly(EntityPlayer, IEntityOwnable) */
|
||||
public static boolean isPlayerAlly(EntityPlayer allyOf, EntityPlayer possibleAlly){
|
||||
WizardData data = WizardData.get(allyOf);
|
||||
return data != null && data.isPlayerAlly(possibleAlly);
|
||||
}
|
||||
|
||||
/** Helper method for testing if the given {@link net.minecraft.entity.IEntityOwnable}'s owner is an ally of the
|
||||
* given player. This works even when the owner is not logged in, though it may not correctly respect teams when
|
||||
* that is the case. */
|
||||
public static boolean isOwnerAlly(EntityPlayer allyOf, IEntityOwnable ownable){
|
||||
WizardData data = WizardData.get(allyOf);
|
||||
if(data == null) return false;
|
||||
Entity owner = ownable.getOwner();
|
||||
return owner instanceof EntityPlayer ? data.isPlayerAlly((EntityPlayer)owner) : data.isPlayerAlly(ownable.getOwnerId());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onLivingAttackEvent(LivingAttackEvent event){
|
||||
|
||||
if(event.getSource() != null && event.getSource().getTrueSource() instanceof EntityPlayer
|
||||
&& event.getSource() instanceof IElementalDamage){
|
||||
|
||||
if(event.getEntity() instanceof EntityPlayer){
|
||||
// Prevents any magic damage to allied players if friendly fire is disabled for players
|
||||
if(Wizardry.settings.friendlyFire.blockPlayers && isPlayerAlly((EntityPlayer)event.getSource().getTrueSource(), (EntityPlayer)event.getEntity())){
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}else{
|
||||
// Prevents any magic damage to entities owned by allied players if friendly fire is disabled for owned creatures
|
||||
// Since we're dealing with players separately we might as well just use isAllied
|
||||
if(Wizardry.settings.friendlyFire.blockOwned && isAllied((EntityPlayer)event.getSource().getTrueSource(), event.getEntityLiving())){
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user