|
|
|
|
@ -1,7 +1,14 @@
|
|
|
|
|
package com.zivilon.cinder_loe.character;
|
|
|
|
|
|
|
|
|
|
import cpw.mods.fml.common.FMLCommonHandler;
|
|
|
|
|
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
|
|
|
|
import cpw.mods.fml.common.eventhandler.EventPriority;
|
|
|
|
|
import cpw.mods.fml.common.gameevent.TickEvent;
|
|
|
|
|
import lotr.common.LOTRLevelData;
|
|
|
|
|
import lotr.common.entity.npc.*;
|
|
|
|
|
import net.minecraft.entity.Entity;
|
|
|
|
|
import net.minecraft.util.ChatComponentText;
|
|
|
|
|
import net.minecraft.util.EnumChatFormatting;
|
|
|
|
|
import net.minecraftforge.common.MinecraftForge;
|
|
|
|
|
import net.minecraftforge.event.entity.living.LivingHurtEvent;
|
|
|
|
|
|
|
|
|
|
@ -12,9 +19,8 @@ import net.minecraft.entity.player.EntityPlayerMP;
|
|
|
|
|
import net.minecraft.util.AxisAlignedBB;
|
|
|
|
|
import net.minecraft.world.World;
|
|
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.UUID;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
import com.zivilon.cinder_loe.entity.npc.radagast.FangornAnimal;
|
|
|
|
|
|
|
|
|
|
@ -23,8 +29,141 @@ public class CharacterEventListener {
|
|
|
|
|
public CharacterEventListener() {
|
|
|
|
|
// Register the event listener
|
|
|
|
|
MinecraftForge.EVENT_BUS.register(this);
|
|
|
|
|
FMLCommonHandler.instance().bus().register(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Mouth of Sauron statics
|
|
|
|
|
private static final int HIRE_INTERVAL = 600; // every 30s 600 ticks
|
|
|
|
|
private static final double HIRE_RADIUS = 50.0D; // 50 blocks
|
|
|
|
|
private static final int MAX_HIRED = 10;
|
|
|
|
|
|
|
|
|
|
// tick counter
|
|
|
|
|
private static final Map<UUID, Integer> tickCounters = new HashMap<>();
|
|
|
|
|
//command check
|
|
|
|
|
public static final Set<UUID> hiringEnabled = new HashSet<>();
|
|
|
|
|
|
|
|
|
|
//Mouth of Sauron event handler
|
|
|
|
|
@SubscribeEvent
|
|
|
|
|
public void onPlayerTick(TickEvent.PlayerTickEvent event) {
|
|
|
|
|
if (event.phase != TickEvent.Phase.END || event.player.worldObj.isRemote) return;
|
|
|
|
|
|
|
|
|
|
EntityPlayerMP player = (EntityPlayerMP) event.player;
|
|
|
|
|
UUID id = player.getUniqueID();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Only “MouthOfSauron” gets this ability
|
|
|
|
|
if (!CharacterRoleAPI.getCharacterRoleUUID("MouthOfSauron").equals(id)) {
|
|
|
|
|
tickCounters.remove(id);
|
|
|
|
|
hiringEnabled.remove(id);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!hiringEnabled.contains(id)) {
|
|
|
|
|
tickCounters.remove(id);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Tick up, and only run when we hit the interval
|
|
|
|
|
int count = tickCounters.getOrDefault(id, 0) + 1;
|
|
|
|
|
if (count < HIRE_INTERVAL) {
|
|
|
|
|
tickCounters.put(id, count);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
tickCounters.put(id, 0);
|
|
|
|
|
//player.addChatMessage(new ChatComponentText("[DEBUG] tryHireNPCs called"));
|
|
|
|
|
|
|
|
|
|
tryHireNPCs(player);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void tryHireNPCs(EntityPlayerMP player) {
|
|
|
|
|
World world = player.worldObj;
|
|
|
|
|
UUID playerId = player.getUniqueID();
|
|
|
|
|
|
|
|
|
|
// Search box
|
|
|
|
|
AxisAlignedBB box = AxisAlignedBB.getBoundingBox(
|
|
|
|
|
player.posX - HIRE_RADIUS, player.posY - HIRE_RADIUS, player.posZ - HIRE_RADIUS,
|
|
|
|
|
player.posX + HIRE_RADIUS, player.posY + HIRE_RADIUS, player.posZ + HIRE_RADIUS
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// 1) Grab all NPCs in the box
|
|
|
|
|
List<LOTREntityNPC> allNPCs = world.getEntitiesWithinAABB(LOTREntityNPC.class, box);
|
|
|
|
|
|
|
|
|
|
// 2) Figure out which ones this player already has hired
|
|
|
|
|
List<LOTREntityNPC> alreadyHired = new ArrayList<>();
|
|
|
|
|
for (LOTREntityNPC npc : allNPCs) {
|
|
|
|
|
if (npc.hiredNPCInfo != null
|
|
|
|
|
&& playerId.equals(npc.hiredNPCInfo.getHiringPlayerUUID())) {
|
|
|
|
|
alreadyHired.add(npc);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (alreadyHired.size() >= MAX_HIRED) {
|
|
|
|
|
return; // at cap
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3) Filter into candidates (correct type & not already hired)
|
|
|
|
|
List<LOTREntityNPC> candidates = new ArrayList<>();
|
|
|
|
|
for (LOTREntityNPC npc : allNPCs) {
|
|
|
|
|
boolean isCorrectType =
|
|
|
|
|
npc instanceof LOTREntityOrc
|
|
|
|
|
|| npc instanceof LOTREntityWarg
|
|
|
|
|
|| npc instanceof LOTREntityTroll;
|
|
|
|
|
|
|
|
|
|
boolean notAlreadyHired =
|
|
|
|
|
npc.hiredNPCInfo == null
|
|
|
|
|
|| !playerId.equals(npc.hiredNPCInfo.getHiringPlayerUUID());
|
|
|
|
|
|
|
|
|
|
if (isCorrectType && notAlreadyHired) {
|
|
|
|
|
candidates.add(npc);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (candidates.isEmpty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4) Shuffle & hire up to remaining slots
|
|
|
|
|
Collections.shuffle(candidates, world.rand);
|
|
|
|
|
int slots = MAX_HIRED - alreadyHired.size();
|
|
|
|
|
|
|
|
|
|
// Track which factions already announced this tick
|
|
|
|
|
Set<String> announced = new HashSet<>();
|
|
|
|
|
|
|
|
|
|
for (LOTREntityNPC toHire : candidates) {
|
|
|
|
|
if (slots-- <= 0) break;
|
|
|
|
|
|
|
|
|
|
// Alignment check
|
|
|
|
|
float align = LOTRLevelData.getData(player)
|
|
|
|
|
.getAlignment(toHire.getHiringFaction());
|
|
|
|
|
if (align < 500.0F) continue;
|
|
|
|
|
|
|
|
|
|
// Hire the NPC via your handler
|
|
|
|
|
MouthOfSauronEntityHandler entry =
|
|
|
|
|
new MouthOfSauronEntityHandler(toHire, 500f);
|
|
|
|
|
entry.getOrCreateHiredNPC(world)
|
|
|
|
|
.hiredNPCInfo.hireUnit(
|
|
|
|
|
player,
|
|
|
|
|
false,
|
|
|
|
|
toHire.getHiringFaction(),
|
|
|
|
|
entry,
|
|
|
|
|
"",
|
|
|
|
|
null
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Announce once per faction
|
|
|
|
|
String factionName = toHire.getHiringFaction().factionEntityName();
|
|
|
|
|
if (announced.add(factionName)) {
|
|
|
|
|
String msg = EnumChatFormatting.YELLOW
|
|
|
|
|
+ "You have rallied the "
|
|
|
|
|
+ factionName
|
|
|
|
|
+ " to your cause!";
|
|
|
|
|
player.addChatMessage(new ChatComponentText(msg));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@SubscribeEvent(priority = EventPriority.NORMAL, receiveCanceled = true)
|
|
|
|
|
public void onLivingHurt(LivingHurtEvent event) {
|
|
|
|
|
// Check if the entity being hurt is a character of interest
|
|
|
|
|
|