diff --git a/build.gradle b/build.gradle index dc3a7dd3b..b76ad9d0c 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { id 'idea' } -version = "1.10.2" +version = "1.10.3" group= "kamkeel.customnpc-plus" archivesBaseName = "CustomNPC-Plus" @@ -31,12 +31,14 @@ tasks.create('buildNoMixin', Exec) { commandLine gradleWrapper, 'build', '-Pnomixin' } -sourceSets { - named("main").configure { - java { - srcDirs += ['src/api/java'] - } +sourceSets.main.java { + def apiDir = file('src/api/java') + + if (!apiDir.exists()) { + throw new GradleException("Missing API sources: Run './gradlew updateAPI' or enable checkout submodules in CI.") } + + srcDirs += apiDir } // Modify the existing 'build' task to depend on 'updateAPI' diff --git a/src/api b/src/api index 4c1728670..305a3778c 160000 --- a/src/api +++ b/src/api @@ -1 +1 @@ -Subproject commit 4c172867018c74ce2cb49582f6486f3510e1e43d +Subproject commit 305a3778c86fed2680b8cad173b7e5fb0f3c98e6 diff --git a/src/main/java/kamkeel/npcs/controllers/SyncController.java b/src/main/java/kamkeel/npcs/controllers/SyncController.java index 7678c2a5e..9617f4d12 100644 --- a/src/main/java/kamkeel/npcs/controllers/SyncController.java +++ b/src/main/java/kamkeel/npcs/controllers/SyncController.java @@ -53,6 +53,10 @@ public class SyncController { public static boolean DEBUG_SYNC_LOGGING = false; + private static final EnumMap cacheEntries = new EnumMap<>(EnumSyncType.class); + private static final ConcurrentHashMap playerSyncState = new ConcurrentHashMap<>(); + + private static void debug(String message, Object... args) { if (DEBUG_SYNC_LOGGING) { System.out.println("[SyncController] " + String.format(message, args)); @@ -71,10 +75,10 @@ public class SyncController { EnumSyncType.MAGIC_CYCLE }; - private static final EnumMap CACHE_ENTRIES = new EnumMap<>(EnumSyncType.class); - private static final ConcurrentHashMap PLAYER_SYNC_STATE = new ConcurrentHashMap<>(); + public static void load() { + cacheEntries.clear(); + playerSyncState.clear(); - static { registerCache(EnumSyncType.FACTION, SyncController::factionsNBT); registerCache(EnumSyncType.DIALOG_CATEGORY, SyncController::dialogCategoriesNBT); registerCache(EnumSyncType.QUEST_CATEGORY, SyncController::questCategoriesNBT); @@ -87,14 +91,14 @@ public class SyncController { } public static void syncPlayer(EntityPlayerMP player) { - syncPlayer(player, true); + SyncController.syncPlayerInternal(player, true); } - private static void syncPlayer(EntityPlayerMP player, boolean includePostPackets) { - PlayerSyncState state = PLAYER_SYNC_STATE.computeIfAbsent(player.getUniqueID(), PlayerSyncState::new); + private static void syncPlayerInternal(EntityPlayerMP player, boolean includePostPackets) { + PlayerSyncState state = playerSyncState.computeIfAbsent(player.getUniqueID(), PlayerSyncState::new); for (EnumSyncType type : LOGIN_SYNC_TYPES) { - SyncCacheEntry entry = CACHE_ENTRIES.get(type); + SyncCacheEntry entry = cacheEntries.get(type); if (entry == null) { continue; } @@ -123,7 +127,7 @@ public class SyncController { } public static void beginLogin(EntityPlayerMP player) { - PLAYER_SYNC_STATE.computeIfAbsent(player.getUniqueID(), PlayerSyncState::new); + playerSyncState.computeIfAbsent(player.getUniqueID(), PlayerSyncState::new); PacketHandler.Instance.sendToPlayer( new LoginPacket(getServerCacheKey(), getServerRevisionSnapshot()), player @@ -137,7 +141,7 @@ public class SyncController { Map clientRevisions ) { String currentServerKey = getServerCacheKey(); - PlayerSyncState state = PLAYER_SYNC_STATE.computeIfAbsent(player.getUniqueID(), PlayerSyncState::new); + PlayerSyncState state = playerSyncState.computeIfAbsent(player.getUniqueID(), PlayerSyncState::new); if (!currentServerKey.equals(serverKey)) { state.reset(); @@ -175,7 +179,7 @@ public class SyncController { private static EnumMap getServerRevisionSnapshot() { EnumMap snapshot = new EnumMap<>(EnumSyncType.class); for (EnumSyncType type : LOGIN_SYNC_TYPES) { - SyncCacheEntry entry = CACHE_ENTRIES.get(type); + SyncCacheEntry entry = cacheEntries.get(type); if (entry != null) { snapshot.put(type, entry.getRevisionValue()); } @@ -199,7 +203,7 @@ public class SyncController { } public static int getCurrentRevision(EnumSyncType type) { - SyncCacheEntry entry = CACHE_ENTRIES.get(type); + SyncCacheEntry entry = cacheEntries.get(type); return entry == null ? -1 : entry.getRevisionValue(); } @@ -792,11 +796,11 @@ public class SyncController { } private static void registerCache(EnumSyncType type, Supplier supplier) { - CACHE_ENTRIES.put(type, new SyncCacheEntry(type, supplier)); + cacheEntries.put(type, new SyncCacheEntry(type, supplier)); } private static CachedSyncPayload rebuildNow(EnumSyncType type) { - SyncCacheEntry entry = CACHE_ENTRIES.get(type); + SyncCacheEntry entry = cacheEntries.get(type); if (entry == null) { return null; } @@ -808,7 +812,7 @@ public class SyncController { EnumSet targets = getInvalidationTargets(type); EnumMap revisions = new EnumMap<>(EnumSyncType.class); for (EnumSyncType target : targets) { - SyncCacheEntry entry = CACHE_ENTRIES.get(target); + SyncCacheEntry entry = cacheEntries.get(target); if (entry != null) { int newRevision = entry.invalidate(); revisions.put(target, newRevision); @@ -848,7 +852,7 @@ public class SyncController { if (revision < 0) { return; } - for (PlayerSyncState state : PLAYER_SYNC_STATE.values()) { + for (PlayerSyncState state : playerSyncState.values()) { state.updateRevision(type, revision); } } @@ -857,7 +861,7 @@ public class SyncController { if (revisions.isEmpty()) { return; } - for (PlayerSyncState state : PLAYER_SYNC_STATE.values()) { + for (PlayerSyncState state : playerSyncState.values()) { for (Map.Entry entry : revisions.entrySet()) { state.updateRevision(entry.getKey(), entry.getValue()); } @@ -939,6 +943,12 @@ public class SyncController { return revision; } + private synchronized void reset() { + dirty = true; + payload = null; + revision = 0; + } + private static byte[][] splitIntoChunks(byte[] payload) { int totalSize = payload.length; int chunkCount = (totalSize + LargeAbstractPacket.CHUNK_SIZE - 1) / LargeAbstractPacket.CHUNK_SIZE; diff --git a/src/main/java/kamkeel/npcs/network/PacketHandler.java b/src/main/java/kamkeel/npcs/network/PacketHandler.java index 4dcf50bac..745962aba 100644 --- a/src/main/java/kamkeel/npcs/network/PacketHandler.java +++ b/src/main/java/kamkeel/npcs/network/PacketHandler.java @@ -60,6 +60,7 @@ import kamkeel.npcs.network.packets.player.MailActionPacket; import kamkeel.npcs.network.packets.player.SaveBookPacket; import kamkeel.npcs.network.packets.player.SaveSignPacket; import kamkeel.npcs.network.packets.player.ScreenSizePacket; +import kamkeel.npcs.network.packets.player.SpecialKeyStatePacket; import kamkeel.npcs.network.packets.player.TransportPacket; import kamkeel.npcs.network.packets.player.customgui.CustomGuiButtonPacket; import kamkeel.npcs.network.packets.player.customgui.CustomGuiClosePacket; @@ -575,6 +576,7 @@ public class PacketHandler { PLAYER_PACKET.registerPacket(new InputDevicePacket()); PLAYER_PACKET.registerPacket(new ScreenSizePacket()); + PLAYER_PACKET.registerPacket(new SpecialKeyStatePacket()); PLAYER_PACKET.registerPacket(new SyncRevisionInfoPacket()); diff --git a/src/main/java/kamkeel/npcs/network/enums/EnumPlayerPacket.java b/src/main/java/kamkeel/npcs/network/enums/EnumPlayerPacket.java index 04d3d3396..0c1db3cd9 100644 --- a/src/main/java/kamkeel/npcs/network/enums/EnumPlayerPacket.java +++ b/src/main/java/kamkeel/npcs/network/enums/EnumPlayerPacket.java @@ -14,6 +14,7 @@ public enum EnumPlayerPacket { CompanionAction, GetRole, InputDevice, + SpecialKeyState, ScreenSize, MagicCycles, diff --git a/src/main/java/kamkeel/npcs/network/packets/player/SaveBookPacket.java b/src/main/java/kamkeel/npcs/network/packets/player/SaveBookPacket.java index 0cac183e5..2822a4c46 100644 --- a/src/main/java/kamkeel/npcs/network/packets/player/SaveBookPacket.java +++ b/src/main/java/kamkeel/npcs/network/packets/player/SaveBookPacket.java @@ -1,7 +1,5 @@ package kamkeel.npcs.network.packets.player; -import cpw.mods.fml.relauncher.Side; -import cpw.mods.fml.relauncher.SideOnly; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import kamkeel.npcs.network.LargeAbstractPacket; @@ -52,7 +50,6 @@ public class SaveBookPacket extends LargeAbstractPacket { } @Override - @SideOnly(Side.CLIENT) protected void handleCompleteData(ByteBuf data, EntityPlayer player) throws IOException { int x = data.readInt(), y = data.readInt(), z = data.readInt(); diff --git a/src/main/java/kamkeel/npcs/network/packets/player/SpecialKeyStatePacket.java b/src/main/java/kamkeel/npcs/network/packets/player/SpecialKeyStatePacket.java new file mode 100644 index 000000000..3b9f56690 --- /dev/null +++ b/src/main/java/kamkeel/npcs/network/packets/player/SpecialKeyStatePacket.java @@ -0,0 +1,60 @@ +package kamkeel.npcs.network.packets.player; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import io.netty.buffer.ByteBuf; +import kamkeel.npcs.network.AbstractPacket; +import kamkeel.npcs.network.PacketChannel; +import kamkeel.npcs.network.PacketClient; +import kamkeel.npcs.network.PacketHandler; +import kamkeel.npcs.network.enums.EnumPlayerPacket; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import noppes.npcs.controllers.PlayerDataController; +import noppes.npcs.controllers.data.PlayerData; + +import java.io.IOException; + +public final class SpecialKeyStatePacket extends AbstractPacket { + private boolean pressed; + + public SpecialKeyStatePacket() { + } + + private SpecialKeyStatePacket(boolean pressed) { + this.pressed = pressed; + } + + public static void send(boolean pressed) { + PacketClient.sendClient(new SpecialKeyStatePacket(pressed)); + } + + @Override + public Enum getType() { + return EnumPlayerPacket.SpecialKeyState; + } + + @Override + public PacketChannel getChannel() { + return PacketHandler.PLAYER_PACKET; + } + + @Override + @SideOnly(Side.CLIENT) + public void sendData(ByteBuf out) throws IOException { + out.writeBoolean(pressed); + } + + @Override + public void receiveData(ByteBuf in, EntityPlayer player) throws IOException { + boolean keyDown = in.readBoolean(); + if (!(player instanceof EntityPlayerMP)) { + return; + } + + PlayerData data = PlayerDataController.Instance.getPlayerData((EntityPlayerMP) player); + if (data != null) { + data.setSpecialKeyDown(keyDown); + } + } +} diff --git a/src/main/java/noppes/npcs/CustomNpcs.java b/src/main/java/noppes/npcs/CustomNpcs.java index 3cfcd18e4..4b5750c6a 100644 --- a/src/main/java/noppes/npcs/CustomNpcs.java +++ b/src/main/java/noppes/npcs/CustomNpcs.java @@ -19,6 +19,7 @@ import kamkeel.npcs.command.CommandKamkeel; import kamkeel.npcs.command.profile.CommandProfile; import kamkeel.npcs.controllers.AttributeController; import kamkeel.npcs.controllers.ProfileController; +import kamkeel.npcs.controllers.SyncController; import kamkeel.npcs.controllers.data.profile.CNPCData; import kamkeel.npcs.developer.Developer; import kamkeel.npcs.network.PacketHandler; @@ -99,7 +100,7 @@ import noppes.npcs.scripted.NpcAPI; import java.io.File; import java.util.Set; -@Mod(modid = "customnpcs", name = "CustomNPC+", version = "1.10.2") +@Mod(modid = "customnpcs", name = "CustomNPC+", version = "1.10.3") public class CustomNpcs { @SidedProxy(clientSide = "noppes.npcs.client.ClientProxy", serverSide = "noppes.npcs.CommonProxy") @@ -310,6 +311,7 @@ public class CustomNpcs { ScriptController.HasStart = true; ServerCloneController.Instance = new ServerCloneController(); ServerTagMapController.Instance = new ServerTagMapController(); + SyncController.load(); } diff --git a/src/main/java/noppes/npcs/DataAdvanced.java b/src/main/java/noppes/npcs/DataAdvanced.java index cc9e08614..45ecfe4a8 100644 --- a/src/main/java/noppes/npcs/DataAdvanced.java +++ b/src/main/java/noppes/npcs/DataAdvanced.java @@ -21,6 +21,7 @@ import noppes.npcs.roles.JobSpawner; import noppes.npcs.roles.RoleBank; import noppes.npcs.roles.RoleCompanion; import noppes.npcs.roles.RoleFollower; +import noppes.npcs.roles.RoleMount; import noppes.npcs.roles.RolePostman; import noppes.npcs.roles.RoleTrader; import noppes.npcs.roles.RoleTransporter; @@ -196,7 +197,11 @@ public class DataAdvanced { if (EnumRoleType.values().length <= i) { i -= 2; } - role = EnumRoleType.values()[i]; + EnumRoleType newRole = EnumRoleType.values()[i]; + if (npc.roleInterface instanceof RoleMount && newRole != EnumRoleType.Mount) { + ((RoleMount) npc.roleInterface).onDisable(); + } + role = newRole; if (role == EnumRoleType.None) npc.roleInterface = null; else if (role == EnumRoleType.Bank && !(npc.roleInterface instanceof RoleBank)) @@ -211,6 +216,8 @@ public class DataAdvanced { npc.roleInterface = new RoleTransporter(npc); else if (role == EnumRoleType.Companion && !(npc.roleInterface instanceof RoleCompanion)) npc.roleInterface = new RoleCompanion(npc); + else if (role == EnumRoleType.Mount && !(npc.roleInterface instanceof RoleMount)) + npc.roleInterface = new RoleMount(npc); } public void setJob(int i) { diff --git a/src/main/java/noppes/npcs/ServerEventsHandler.java b/src/main/java/noppes/npcs/ServerEventsHandler.java index a41a828e6..1bd184a4a 100644 --- a/src/main/java/noppes/npcs/ServerEventsHandler.java +++ b/src/main/java/noppes/npcs/ServerEventsHandler.java @@ -51,6 +51,7 @@ import noppes.npcs.controllers.ServerCloneController; import noppes.npcs.controllers.data.Animation; import noppes.npcs.controllers.data.AnimationData; import noppes.npcs.controllers.data.Line; +import noppes.npcs.controllers.data.LinkedItem; import noppes.npcs.controllers.data.MarkData; import noppes.npcs.controllers.data.Party; import noppes.npcs.controllers.data.PlayerData; @@ -59,6 +60,7 @@ import noppes.npcs.controllers.data.Quest; import noppes.npcs.controllers.data.QuestData; import noppes.npcs.entity.EntityNPCInterface; import noppes.npcs.items.ItemExcalibur; +import noppes.npcs.items.ItemLinked; import noppes.npcs.items.ItemShield; import noppes.npcs.items.ItemSoulstoneEmpty; import noppes.npcs.quests.QuestKill; @@ -171,6 +173,19 @@ public class ServerEventsHandler { @SubscribeEvent public void invoke(LivingHurtEvent event) { + + + + if(event.source.getEntity() instanceof EntityPlayerMP && event.entity instanceof EntityLivingBase ){ + EntityPlayerMP ep = (EntityPlayerMP) event.source.getEntity(); + if(ep.getHeldItem() != null && ep.getHeldItem().getItem() instanceof ItemLinked){ + int time = ep.getHeldItem().stackTagCompound.getCompoundTag("ItemData").getCompoundTag("LinkedData").getInteger("AttackSpeed"); + event.entity.hurtResistantTime = time; + ((EntityLivingBase) event.entity).hurtTime = time; + } + } + + if (!(event.entityLiving instanceof EntityPlayer)) return; @@ -418,6 +433,8 @@ public class ServerEventsHandler { return; String name = EntityList.getEntityString(entity); + if (entity instanceof EntityPlayer) + name = "Player"; QuestKill quest = (QuestKill) data.quest.questInterface; if (data.quest.partyOptions.objectiveRequirement == EnumPartyObjectives.Leader && !party.getLeaderUUID().equals(player.getUniqueID())) return; diff --git a/src/main/java/noppes/npcs/ai/EntityAILeapAtTargetNpc.java b/src/main/java/noppes/npcs/ai/EntityAILeapAtTargetNpc.java new file mode 100644 index 000000000..437dbd6d3 --- /dev/null +++ b/src/main/java/noppes/npcs/ai/EntityAILeapAtTargetNpc.java @@ -0,0 +1,63 @@ +package noppes.npcs.ai; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.ai.EntityAIBase; +import net.minecraft.util.MathHelper; +import noppes.npcs.entity.EntityNPCInterface; + +public class EntityAILeapAtTargetNpc extends EntityAIBase { + private final EntityNPCInterface npc; + private EntityLivingBase leapTarget; + private final float leapMotionY; + + public EntityAILeapAtTargetNpc(EntityNPCInterface npc, float leapMotionY) { + this.npc = npc; + this.leapMotionY = leapMotionY; + this.setMutexBits(5); + } + + @Override + public boolean shouldExecute() { + this.leapTarget = this.npc.getAttackTarget(); + if (this.leapTarget == null) { + return false; + } + double distanceSq = this.npc.getDistanceSqToEntity(this.leapTarget); + if (distanceSq < 4.0D || distanceSq > 16.0D) { + return false; + } + if (!this.npc.onGround) { + return false; + } + return this.npc.getRNG().nextInt(5) == 0; + } + + @Override + public boolean continueExecuting() { + boolean airborne = !this.npc.onGround; + if (!airborne) { + this.npc.setNpcJumpingState(false); + } + return airborne; + } + + @Override + public void startExecuting() { + double d0 = this.leapTarget.posX - this.npc.posX; + double d1 = this.leapTarget.posZ - this.npc.posZ; + float f = MathHelper.sqrt_double(d0 * d0 + d1 * d1); + + if ((double) f >= 1.0E-4D) { + this.npc.motionX += d0 / (double) f * 0.5D * 0.8D + this.npc.motionX * 0.2D; + this.npc.motionZ += d1 / (double) f * 0.5D * 0.8D + this.npc.motionZ * 0.2D; + } + + this.npc.motionY = this.leapMotionY; + this.npc.setNpcJumpingState(true); + } + + @Override + public void resetTask() { + this.npc.setNpcJumpingState(false); + } +} diff --git a/src/main/java/noppes/npcs/ai/EntityAIPounceTarget.java b/src/main/java/noppes/npcs/ai/EntityAIPounceTarget.java index 5dbe5f233..4f87575bf 100644 --- a/src/main/java/noppes/npcs/ai/EntityAIPounceTarget.java +++ b/src/main/java/noppes/npcs/ai/EntityAIPounceTarget.java @@ -30,7 +30,11 @@ public class EntityAIPounceTarget extends EntityAIBase { @Override public boolean continueExecuting() { - return !this.npc.onGround; + boolean airborne = !this.npc.onGround; + if (!airborne) { + this.npc.setNpcJumpingState(false); + } + return airborne; } @Override @@ -47,6 +51,12 @@ public class EntityAIPounceTarget extends EntityAIBase { this.npc.motionX *= this.leapSpeed; this.npc.motionZ *= this.leapSpeed; this.npc.motionY *= this.leapSpeed; + this.npc.setNpcJumpingState(true); + } + + @Override + public void resetTask() { + this.npc.setNpcJumpingState(false); } public float getAngleForXYZ(double varX, double varY, double varZ, double horiDist) { diff --git a/src/main/java/noppes/npcs/client/ClientEventHandler.java b/src/main/java/noppes/npcs/client/ClientEventHandler.java index deb374ab2..7a839fbb5 100644 --- a/src/main/java/noppes/npcs/client/ClientEventHandler.java +++ b/src/main/java/noppes/npcs/client/ClientEventHandler.java @@ -55,6 +55,7 @@ public class ClientEventHandler { public static float partialRenderTick; public static RendererLivingEntity renderer; + public static boolean renderingEntityInGUI; public static EntityNPCInterface renderingNpc; public static EntityPlayer renderingPlayer; public static HashMap partNames = new HashMap<>(); diff --git a/src/main/java/noppes/npcs/client/ClientProxy.java b/src/main/java/noppes/npcs/client/ClientProxy.java index f0346a5d3..7cc3d7b76 100644 --- a/src/main/java/noppes/npcs/client/ClientProxy.java +++ b/src/main/java/noppes/npcs/client/ClientProxy.java @@ -222,6 +222,7 @@ import java.util.Random; public class ClientProxy extends CommonProxy { public static KeyBinding NPCButton; + public static KeyBinding SpecialKey; public static final Random RAND = new Random(); public static FontContainer Font; @@ -288,8 +289,10 @@ public class ClientProxy extends CommonProxy { Minecraft mc = Minecraft.getMinecraft(); NPCButton = new KeyBinding("NPC Inventory", Keyboard.KEY_N, "key.categories.customnpc"); + SpecialKey = new KeyBinding("key.customnpcs.special", Keyboard.KEY_C, "key.categories.customnpc"); ClientRegistry.registerKeyBinding(NPCButton); + ClientRegistry.registerKeyBinding(SpecialKey); new PresetController(CustomNpcs.Dir); diff --git a/src/main/java/noppes/npcs/client/ClientTickHandler.java b/src/main/java/noppes/npcs/client/ClientTickHandler.java index 46af7df1a..af44405dc 100644 --- a/src/main/java/noppes/npcs/client/ClientTickHandler.java +++ b/src/main/java/noppes/npcs/client/ClientTickHandler.java @@ -8,6 +8,7 @@ import cpw.mods.fml.common.gameevent.TickEvent.Phase; import kamkeel.npcs.network.PacketClient; import kamkeel.npcs.network.packets.player.CheckPlayerValue; import kamkeel.npcs.network.packets.player.InputDevicePacket; +import kamkeel.npcs.network.packets.player.SpecialKeyStatePacket; import kamkeel.npcs.network.packets.player.ScreenSizePacket; import net.minecraft.client.Minecraft; import net.minecraft.entity.Entity; @@ -23,9 +24,12 @@ import noppes.npcs.client.gui.hud.EnumHudComponent; import noppes.npcs.client.gui.hud.HudComponent; import noppes.npcs.client.gui.player.inventory.GuiCNPCInventory; import noppes.npcs.client.renderer.RenderNPCInterface; +import noppes.npcs.constants.EnumRoleType; import noppes.npcs.constants.MarkType; import noppes.npcs.controllers.data.MarkData; +import noppes.npcs.controllers.data.PlayerData; import noppes.npcs.entity.EntityNPCInterface; +import noppes.npcs.roles.RoleMount; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import tconstruct.client.tabs.InventoryTabCustomNpc; @@ -42,6 +46,7 @@ public class ClientTickHandler { private int buttonPressed = -1; private long buttonTime = 0L; private final int[] ignoreKeys = new int[]{157, 29, 54, 42, 184, 56, 220, 219}; + private boolean lastSpecialKeyDown = false; @SubscribeEvent(priority = EventPriority.LOWEST) public void onClientTick(TickEvent.ClientTickEvent event) { @@ -52,6 +57,30 @@ public class ClientTickHandler { } this.prevWorld = mc.theWorld; } + if (event.phase == Phase.START) { + EntityPlayer player = mc.thePlayer; + if (player != null) { + boolean specialKeyDown = ClientProxy.SpecialKey != null && Keyboard.isKeyDown(ClientProxy.SpecialKey.getKeyCode()); + if (specialKeyDown != lastSpecialKeyDown) { + PlayerData data = CustomNpcs.proxy.getPlayerData(player); + if (data != null) { + data.setSpecialKeyDown(specialKeyDown); + } + SpecialKeyStatePacket.send(specialKeyDown); + lastSpecialKeyDown = specialKeyDown; + } + + if (player.ridingEntity instanceof EntityNPCInterface) { + EntityNPCInterface mount = (EntityNPCInterface) player.ridingEntity; + if (mount.advanced.role == EnumRoleType.Mount && mount.roleInterface instanceof RoleMount) { + RoleMount role = (RoleMount) mount.roleInterface; + if (!role.isSprintAllowed() && player.isSprinting()) { + player.setSprinting(false); + } + } + } + } + } if (event.phase == Phase.END) { if (mc.thePlayer != null && mc.theWorld != null && !mc.isGamePaused() && ClientEventHandler.hasOverlays(mc.thePlayer)) { renderCNPCPlayer.itemRenderer.updateEquippedItem(); diff --git a/src/main/java/noppes/npcs/client/gui/global/GuiNpcManagePlayerData.java b/src/main/java/noppes/npcs/client/gui/global/GuiNpcManagePlayerData.java index 58b50de0a..d25a6939f 100644 --- a/src/main/java/noppes/npcs/client/gui/global/GuiNpcManagePlayerData.java +++ b/src/main/java/noppes/npcs/client/gui/global/GuiNpcManagePlayerData.java @@ -70,7 +70,6 @@ public class GuiNpcManagePlayerData extends GuiNPCInterface2 implements GuiYesNo @Override public void mouseClicked(int i, int j, int k) { - ; super.mouseClicked(i, j, k); if (k == 0 && playerScroll != null) playerScroll.mouseClicked(i, j, k); @@ -132,11 +131,10 @@ public class GuiNpcManagePlayerData extends GuiNPCInterface2 implements GuiYesNo } if (id == 1) { PacketClient.sendClient(new PlayerDataMapRegenPacket()); - close(); } - } else { - displayGuiScreen(this); } + + displayGuiScreen(this); } // IScrollData interface. diff --git a/src/main/java/noppes/npcs/client/gui/item/SubGuiLinkedItem.java b/src/main/java/noppes/npcs/client/gui/item/SubGuiLinkedItem.java index 9bf537a69..f4296a882 100644 --- a/src/main/java/noppes/npcs/client/gui/item/SubGuiLinkedItem.java +++ b/src/main/java/noppes/npcs/client/gui/item/SubGuiLinkedItem.java @@ -115,13 +115,22 @@ public class SubGuiLinkedItem extends SubGuiInterface implements ITextfieldListe y += spacing; // Dig Speed field (0 to 20) - addLabel(new GuiNpcLabel(11, "display.digSpeed", x, y + 5, CustomNpcResourceListener.DefaultTextColor)); + addLabel(new GuiNpcLabel(11, "Dig & Attack Speed", x, y + 5, CustomNpcResourceListener.DefaultTextColor)); GuiNpcTextField digSpeedField = new GuiNpcTextField(12, this, x + 110, y, 50, 20, "" + linkedItem.digSpeed); digSpeedField.setIntegersOnly().setMinMaxDefault(0, 20, 1); addTextField(digSpeedField); + GuiNpcTextField attackSpeedField = new GuiNpcTextField(14, this, x +165, y, 50, 20, "" +linkedItem.attackSpeed); + attackSpeedField.setIntegersOnly().setMinMaxDefault(0,999999999,20); + addTextField(attackSpeedField); y += spacing; + // Attack Speed Field (integers only) + //addLabel(new GuiNpcLabel(13,"Attack Speed",x,y + 5, CustomNpcResourceListener.DefaultTextColor)); + + + //y += spacing; + // TEXTURE field addLabel(new GuiNpcLabel(3, "display.texture", x, y + 5, CustomNpcResourceListener.DefaultTextColor)); addTextField(new GuiNpcTextField(2, this, x + 60, y, 200, 20, linkedItem.display.texture)); @@ -401,6 +410,9 @@ public class SubGuiLinkedItem extends SubGuiInterface implements ITextfieldListe } else if (id == 12) { // Dig Speed linkedItem.digSpeed = textField.getInteger(); + } else if (id == 14) { + // attack Speed + linkedItem.attackSpeed = textField.getInteger(); } else if (id == 31) { linkedItem.display.scaleX = textField.getFloat(); } else if (id == 32) { diff --git a/src/main/java/noppes/npcs/client/gui/mainmenu/GuiNpcAI.java b/src/main/java/noppes/npcs/client/gui/mainmenu/GuiNpcAI.java index 538d58b59..6e0ebfa6e 100644 --- a/src/main/java/noppes/npcs/client/gui/mainmenu/GuiNpcAI.java +++ b/src/main/java/noppes/npcs/client/gui/mainmenu/GuiNpcAI.java @@ -15,7 +15,9 @@ import noppes.npcs.client.gui.util.IGuiData; import noppes.npcs.client.gui.util.ITextfieldListener; import noppes.npcs.constants.EnumCombatPolicy; import noppes.npcs.constants.EnumNavType; +import noppes.npcs.constants.EnumRoleType; import noppes.npcs.entity.EntityNPCInterface; +import noppes.npcs.roles.RoleMount; public class GuiNpcAI extends GuiNPCInterface2 implements ITextfieldListener, IGuiData { private DataAI ai; @@ -44,7 +46,12 @@ public class GuiNpcAI extends GuiNPCInterface2 implements ITextfieldListener, IG addLabel(new GuiNpcLabel(10, "ai.avoidwater", guiLeft + 150, guiTop + 17)); addButton(new GuiNpcButton(5, guiLeft + 230, guiTop + 10, 60, 20, new String[]{"gui.no", "gui.yes"}, npc.ais.avoidsWater ? 1 : 0)); addLabel(new GuiNpcLabel(11, "ai.return", guiLeft + 150, guiTop + 40)); - addButton(new GuiNpcButton(6, guiLeft + 230, guiTop + 35, 60, 20, new String[]{"gui.no", "gui.yes"}, npc.ais.returnToStart ? 1 : 0)); + int returnValue = npc.ais.returnToStart ? 1 : 0; + if (npc.advanced.role == EnumRoleType.Mount && npc.roleInterface instanceof RoleMount) { + returnValue = ((RoleMount) npc.roleInterface).getReturnToStartPreference() ? 1 : 0; + } + addButton(new GuiNpcButton(6, guiLeft + 230, guiTop + 35, 60, 20, new String[]{"gui.no", "gui.yes"}, returnValue)); + getButton(6).setEnabled(npc.advanced.role != EnumRoleType.Mount); addLabel(new GuiNpcLabel(17, "ai.leapattarget", guiLeft + 150, guiTop + 65)); addButton(new GuiNpcButton(15, guiLeft + 230, guiTop + 60, 60, 20, new String[]{"gui.no", "ai.jump", "ai.pounce"}, npc.ais.leapType)); addLabel(new GuiNpcLabel(15, "ai.indirect", guiLeft + 150, guiTop + 90)); @@ -132,7 +139,13 @@ public class GuiNpcAI extends GuiNPCInterface2 implements ITextfieldListener, IG } else if (button.id == 5) { npc.setAvoidWater(button.getValue() == 1); } else if (button.id == 6) { - ai.returnToStart = (button.getValue() == 1); + if (npc.advanced.role == EnumRoleType.Mount && npc.roleInterface instanceof RoleMount) { + ((RoleMount) npc.roleInterface).setReturnToStartPreference(button.getValue() == 1); + ai.returnToStart = false; + initGui(); + } else { + ai.returnToStart = (button.getValue() == 1); + } } else if (button.id == 7) { ai.canSwim = (button.getValue() == 1); } else if (button.id == 9) { diff --git a/src/main/java/noppes/npcs/client/gui/mainmenu/GuiNpcAdvanced.java b/src/main/java/noppes/npcs/client/gui/mainmenu/GuiNpcAdvanced.java index d7b5ac919..6452145a6 100644 --- a/src/main/java/noppes/npcs/client/gui/mainmenu/GuiNpcAdvanced.java +++ b/src/main/java/noppes/npcs/client/gui/mainmenu/GuiNpcAdvanced.java @@ -25,6 +25,7 @@ import noppes.npcs.client.gui.roles.GuiNpcFollowerJob; import noppes.npcs.client.gui.roles.GuiNpcGuard; import noppes.npcs.client.gui.roles.GuiNpcHealer; import noppes.npcs.client.gui.roles.GuiNpcSpawner; +import noppes.npcs.client.gui.roles.GuiNpcMount; import noppes.npcs.client.gui.roles.GuiNpcTransporter; import noppes.npcs.client.gui.util.GuiNPCInterface2; import noppes.npcs.client.gui.util.GuiNpcButton; @@ -47,7 +48,7 @@ public class GuiNpcAdvanced extends GuiNPCInterface2 implements IGuiData { super.initGui(); int y = guiTop + 10; this.addButton(new GuiNpcButton(3, guiLeft + 85 + 160, y, 52, 20, "selectServer.edit")); - this.addButton(new GuiNpcButton(8, guiLeft + 85, y, 155, 20, new String[]{"role.none", "role.trader", "role.follower", "role.bank", "role.transporter", "role.mailman", NoppesStringUtils.translate("role.companion", "(WIP)")}, npc.advanced.role.ordinal())); + this.addButton(new GuiNpcButton(8, guiLeft + 85, y, 155, 20, new String[]{"role.none", "role.trader", "role.follower", "role.bank", "role.transporter", "role.mailman", NoppesStringUtils.translate("role.companion", "(WIP)"), "role.mount"}, npc.advanced.role.ordinal())); getButton(3).setEnabled(npc.advanced.role != EnumRoleType.None && npc.advanced.role != EnumRoleType.Postman); this.addButton(new GuiNpcButton(4, guiLeft + 85 + 160, y += 22, 52, 20, "selectServer.edit")); @@ -148,6 +149,8 @@ public class GuiNpcAdvanced extends GuiNPCInterface2 implements IGuiData { displayGuiScreen(new GuiNpcTransporter(npc)); else if (npc.advanced.role == EnumRoleType.Companion) displayGuiScreen(new GuiNpcCompanion(npc)); + else if (npc.advanced.role == EnumRoleType.Mount) + displayGuiScreen(new GuiNpcMount(npc)); } else if (compound.hasKey("JobData")) { if (npc.jobInterface != null) npc.jobInterface.readFromNBT(compound); diff --git a/src/main/java/noppes/npcs/client/gui/player/companion/GuiNpcCompanionStats.java b/src/main/java/noppes/npcs/client/gui/player/companion/GuiNpcCompanionStats.java index a7d4c953d..30f8e422d 100644 --- a/src/main/java/noppes/npcs/client/gui/player/companion/GuiNpcCompanionStats.java +++ b/src/main/java/noppes/npcs/client/gui/player/companion/GuiNpcCompanionStats.java @@ -34,6 +34,10 @@ public class GuiNpcCompanionStats extends GuiNPCInterface implements IGuiData { xSize = 171; ySize = 166; PacketClient.sendClient(new GetNPCRole()); + + drawNpc = true; + xOffsetNpc = 34; + yOffsetNpc = 150; } @Override @@ -96,7 +100,6 @@ public class GuiNpcCompanionStats extends GuiNPCInterface implements IGuiData { } isEating = role.isEating(); - super.drawNpc(34, 150); int y = drawHealth(guiTop + 88); } diff --git a/src/main/java/noppes/npcs/client/gui/roles/GuiNpcMount.java b/src/main/java/noppes/npcs/client/gui/roles/GuiNpcMount.java new file mode 100644 index 000000000..0639113af --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/roles/GuiNpcMount.java @@ -0,0 +1,164 @@ +package noppes.npcs.client.gui.roles; + +import kamkeel.npcs.network.PacketClient; +import kamkeel.npcs.network.packets.request.role.RoleSavePacket; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.nbt.NBTTagCompound; +import noppes.npcs.client.gui.util.GuiNPCInterface2; +import noppes.npcs.client.gui.util.GuiNpcButton; +import noppes.npcs.client.gui.util.GuiNpcLabel; +import noppes.npcs.client.gui.util.GuiNpcTextField; +import noppes.npcs.client.gui.util.ITextfieldListener; +import noppes.npcs.entity.EntityNPCInterface; +import noppes.npcs.roles.RoleMount; + +public class GuiNpcMount extends GuiNPCInterface2 implements ITextfieldListener { + + private final RoleMount role; + + public GuiNpcMount(EntityNPCInterface npc) { + super(npc); + this.role = npc.roleInterface instanceof RoleMount ? (RoleMount) npc.roleInterface : null; + } + + @Override + public void initGui() { + super.initGui(); + if (role == null) { + close(); + return; + } + + int leftLabelX = guiLeft + 4; + int leftFieldX = guiLeft + 116; + int leftY = guiTop + 6; + + leftY = addOffsetRow(0, 10, "role.mount.offsetx", role.getOffsetX(), leftLabelX, leftFieldX, leftY); + leftY = addOffsetRow(1, 11, "role.mount.offsety", role.getOffsetY(), leftLabelX, leftFieldX, leftY); + leftY = addOffsetRow(2, 12, "role.mount.offsetz", role.getOffsetZ(), leftLabelX, leftFieldX, leftY); + leftY = addJumpRow(3, 13, "role.mount.jumpheight", role.getJumpStrength(), leftLabelX, leftFieldX, leftY); + + addLabel(new GuiNpcLabel(4, "role.mount.sprint", leftLabelX, leftY + 5)); + addButton(new GuiNpcButton(101, leftFieldX, leftY, 60, 20, new String[]{"gui.no", "gui.yes"}, role.isSprintAllowed() ? 1 : 0)); + leftY += 24; + + int rightLabelX = guiLeft + 214; + int rightFieldX = guiLeft + 320; + int rightY = guiTop + 6; + + addLabel(new GuiNpcLabel(20, "role.mount.fly", rightLabelX, rightY + 5)); + addButton(new GuiNpcButton(102, rightFieldX, rightY, 60, 20, new String[]{"gui.no", "gui.yes"}, role.isFlyingMountEnabled() ? 1 : 0)); + rightY += 24; + + if (role.isFlyingMountEnabled()) { + addLabel(new GuiNpcLabel(21, "role.mount.hover", rightLabelX, rightY + 5)); + addButton(new GuiNpcButton(103, rightFieldX, rightY, 60, 20, new String[]{"gui.no", "gui.yes"}, role.isHoverModeEnabled() ? 1 : 0)); + rightY += 24; + + rightY = addSpeedRow(22, 14, "role.mount.ascendspeed", role.getFlyingAscendSpeed(), rightLabelX, rightFieldX, rightY, 0.1F, 3.0F, 0.60F); + rightY = addSpeedRow(23, 15, "role.mount.descendspeed", role.getFlyingDescendSpeed(), rightLabelX, rightFieldX, rightY, 0.05F, 3.0F, 0.35F); + } + } + + private int addOffsetRow(int labelId, int fieldId, String translationKey, float value, int labelX, int fieldX, int y) { + addLabel(new GuiNpcLabel(labelId, translationKey, labelX, y + 5)); + GuiNpcTextField field = new GuiNpcTextField(fieldId, this, fieldX, y, 80, 20, format(value)); + field.floatsOnly = true; + field.setMinMaxDefaultFloat(-5.0F, 5.0F, 0.0F); + addTextField(field); + return y + 24; + } + + private int addJumpRow(int labelId, int fieldId, String translationKey, float value, int labelX, int fieldX, int y) { + addLabel(new GuiNpcLabel(labelId, translationKey, labelX, y + 5)); + GuiNpcTextField field = new GuiNpcTextField(fieldId, this, fieldX, y, 80, 20, format(value)); + field.floatsOnly = true; + field.setMinMaxDefaultFloat(0.1F, 15.0F, 1.0F); + addTextField(field); + return y + 24; + } + + private int addSpeedRow(int labelId, int fieldId, String translationKey, float value, int labelX, int fieldX, int y, float min, float max, float defaultValue) { + addLabel(new GuiNpcLabel(labelId, translationKey, labelX, y + 5)); + GuiNpcTextField field = new GuiNpcTextField(fieldId, this, fieldX, y, 80, 20, format(value)); + field.floatsOnly = true; + field.setMinMaxDefaultFloat(min, max, defaultValue); + addTextField(field); + return y + 24; + } + + private String format(float value) { + return String.format(java.util.Locale.ROOT, "%.2f", value); + } + + @Override + public void buttonEvent(GuiButton guibutton) { + if (role == null) + return; + if (guibutton instanceof GuiNpcButton) { + GuiNpcButton button = (GuiNpcButton) guibutton; + if (guibutton.id == 101) { + role.setSprintAllowed(button.getValue() == 1); + } else if (guibutton.id == 102) { + role.setFlyingMountEnabled(button.getValue() == 1); + initGui(); + } else if (guibutton.id == 103) { + role.setHoverModeEnabled(button.getValue() == 1); + } + } + } + + @Override + public void unFocused(GuiNpcTextField textfield) { + if (role == null) + return; + float value = textfield.isFloat() ? textfield.getFloat() : 0.0F; + switch (textfield.id) { + case 10: + role.setOffsetX(value); + break; + case 11: + role.setOffsetY(value); + break; + case 12: + role.setOffsetZ(value); + break; + case 13: + role.setJumpStrength(value); + break; + case 14: + role.setFlyingAscendSpeed(value); + break; + case 15: + role.setFlyingDescendSpeed(value); + break; + } + textfield.setText(format(valueForField(textfield.id))); + } + + private float valueForField(int id) { + switch (id) { + case 10: + return role.getOffsetX(); + case 11: + return role.getOffsetY(); + case 12: + return role.getOffsetZ(); + case 13: + return role.getJumpStrength(); + case 14: + return role.getFlyingAscendSpeed(); + case 15: + return role.getFlyingDescendSpeed(); + default: + return 0.0F; + } + } + + @Override + public void save() { + if (role != null) { + PacketClient.sendClient(new RoleSavePacket(role.writeToNBT(new NBTTagCompound()))); + } + } +} diff --git a/src/main/java/noppes/npcs/client/gui/select/GuiTextureSelection.java b/src/main/java/noppes/npcs/client/gui/select/GuiTextureSelection.java index eb8af18d0..4f1bccfaf 100644 --- a/src/main/java/noppes/npcs/client/gui/select/GuiTextureSelection.java +++ b/src/main/java/noppes/npcs/client/gui/select/GuiTextureSelection.java @@ -48,6 +48,7 @@ public class GuiTextureSelection extends SubGuiInterface implements ICustomScrol private String selectedDomain; public ResourceLocation selectedResource; + public boolean setNPCSkin = true; // Instance maps to be populated private final HashMap> domains = new HashMap<>(); private final HashMap textures = new HashMap<>(); @@ -145,6 +146,11 @@ public class GuiTextureSelection extends SubGuiInterface implements ICustomScrol int i = selectedResource.getResourcePath().lastIndexOf('/'); location = selectedResource.getResourcePath().substring(0, i + 1); } + + drawNpc = true; + xOffsetNpc = 307; + yOffsetNpc = 150; + defaultZoom = zoom = 1.5f; } private File decodeFile(String url) { @@ -238,27 +244,23 @@ public class GuiTextureSelection extends SubGuiInterface implements ICustomScrol @Override protected void actionPerformed(GuiButton guibutton) { super.actionPerformed(guibutton); - if (guibutton.id == 2) { - npc.display.setSkinTexture(selectedResource.toString()); + if (guibutton.id == 2 && selectedResource != null) { + if (setNPCSkin) + npc.display.setSkinTexture(selectedResource.toString()); } npc.textureLocation = null; close(); parent.initGui(); } - @Override - public void drawScreen(int i, int j, float f) { - super.drawScreen(i, j, f); - npc.textureLocation = selectedResource; - drawNpc(npc, 307, 150, 1.5F, 0); - } - @Override public void customScrollClicked(int i, int j, int k, GuiCustomScroll scroll) { if (scroll == scrollTextures) { if (scroll.id == 1) { TextureData data = textures.get(scroll.getSelected()); selectedResource = new ResourceLocation(selectedDomain, data.absoluteName); + if (setNPCSkin) + npc.textureLocation = selectedResource; } } else { initGui(); @@ -288,7 +290,8 @@ public class GuiTextureSelection extends SubGuiInterface implements ICustomScrol scrollTextures.selected = -1; initGui(); } else { - npc.display.setSkinTexture(selectedResource.toString()); + if (setNPCSkin) + npc.display.setSkinTexture(selectedResource.toString()); close(); parent.initGui(); } @@ -364,6 +367,10 @@ public class GuiTextureSelection extends SubGuiInterface implements ICustomScrol list.add(new TextureData(domain, name)); } + public void setLocation(String domain, String location) { + selectedDomain = domain; + this.location = location; + } static class TextureData { String domain; String absoluteName; diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiButtonBiDirectional.java b/src/main/java/noppes/npcs/client/gui/util/GuiButtonBiDirectional.java index c1d60fc66..0ebc41d64 100644 --- a/src/main/java/noppes/npcs/client/gui/util/GuiButtonBiDirectional.java +++ b/src/main/java/noppes/npcs/client/gui/util/GuiButtonBiDirectional.java @@ -61,6 +61,8 @@ public class GuiButtonBiDirectional extends GuiNpcButton { boolean bo = super.mousePressed(minecraft, mouseX, mouseY); if (bo && display != null && display.length != 0) { boolean hoverL = mouseX >= this.xPosition && mouseY >= this.yPosition && mouseX < this.xPosition + 11 && mouseY < this.yPosition + this.height; + if (rightClicked.get()) + hoverL = true; boolean hoverR = !hoverL && mouseX >= this.xPosition + 11 && mouseY >= this.yPosition && mouseX < this.xPosition + this.width && mouseY < this.yPosition + this.height; diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiModelInterface.java b/src/main/java/noppes/npcs/client/gui/util/GuiModelInterface.java index ed4fd384f..82bc71a4a 100644 --- a/src/main/java/noppes/npcs/client/gui/util/GuiModelInterface.java +++ b/src/main/java/noppes/npcs/client/gui/util/GuiModelInterface.java @@ -5,6 +5,7 @@ import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.entity.EntityLivingBase; +import noppes.npcs.client.ClientEventHandler; import noppes.npcs.client.EntityUtil; import noppes.npcs.entity.EntityCustomNpc; import noppes.npcs.entity.data.ModelData; @@ -159,12 +160,13 @@ public class GuiModelInterface extends GuiNPCInterface { entity.prevRotationYawHead = entity.rotationYawHead = followMouse ? entity.rotationYaw : rotation; GL11.glTranslatef(0.0F, entity.yOffset, 1F); RenderManager.instance.playerViewY = 180F; - + ClientEventHandler.renderingEntityInGUI = true; try { RenderManager.instance.renderEntityWithPosYaw(entity, 0.0D, 0.0D, 0.0D, 0.0F, 1.0F); } catch (Exception e) { playerdata.setEntityClass(null); } + ClientEventHandler.renderingEntityInGUI = false; entity.prevRenderYawOffset = entity.renderYawOffset = f2; entity.prevRotationYaw = entity.rotationYaw = f3; entity.rotationPitch = f4; diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiModelInterface2.java b/src/main/java/noppes/npcs/client/gui/util/GuiModelInterface2.java index 16d3af9d7..8a1d015d0 100644 --- a/src/main/java/noppes/npcs/client/gui/util/GuiModelInterface2.java +++ b/src/main/java/noppes/npcs/client/gui/util/GuiModelInterface2.java @@ -6,6 +6,7 @@ import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.entity.EntityLivingBase; +import noppes.npcs.client.ClientEventHandler; import noppes.npcs.client.EntityUtil; import noppes.npcs.entity.EntityCustomNpc; import noppes.npcs.entity.EntityNPCInterface; @@ -109,12 +110,13 @@ public class GuiModelInterface2 extends GuiNPCInterface2 { entity.prevRotationYawHead = entity.rotationYawHead = entity.rotationYaw; GL11.glTranslatef(0.0F, entity.yOffset, 0.0F); RenderManager.instance.playerViewY = 180F; - + ClientEventHandler.renderingEntityInGUI = true; try { RenderManager.instance.renderEntityWithPosYaw(entity, 0.0D, 0.0D, 0.0D, 0.0F, 1.0F); } catch (Exception e) { playerdata.setEntityClass(null); } + ClientEventHandler.renderingEntityInGUI = false; entity.prevRenderYawOffset = entity.renderYawOffset = f2; entity.prevRotationYaw = entity.rotationYaw = f3; entity.rotationPitch = f4; diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiNPCInterface.java b/src/main/java/noppes/npcs/client/gui/util/GuiNPCInterface.java index 27e5da0ec..1d453a395 100644 --- a/src/main/java/noppes/npcs/client/gui/util/GuiNPCInterface.java +++ b/src/main/java/noppes/npcs/client/gui/util/GuiNPCInterface.java @@ -11,6 +11,9 @@ import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.ResourceLocation; import net.minecraft.util.StatCollector; +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.common.MinecraftForge; +import noppes.npcs.client.ClientEventHandler; import noppes.npcs.client.CustomNpcResourceListener; import noppes.npcs.client.TextBlockClient; import noppes.npcs.entity.EntityNPCInterface; @@ -23,6 +26,7 @@ import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; public abstract class GuiNPCInterface extends GuiScreen { public EntityClientPlayerMP player; @@ -51,7 +55,6 @@ public abstract class GuiNPCInterface extends GuiScreen { public float bgScaleX = 1; public float bgScaleY = 1; public float bgScaleZ = 1; - public long timeClosedSubGui; public GuiNPCInterface(EntityNPCInterface npc) { this.player = Minecraft.getMinecraft().thePlayer; @@ -94,6 +97,13 @@ public abstract class GuiNPCInterface extends GuiScreen { scrollWindows.clear(); diagrams.clear(); Keyboard.enableRepeatEvents(true); + + if (drawRenderButtons) { + zoomIn = new GuiNpcButton(0, guiLeft + xOffsetNpc + xOffsetButton, guiTop + yOffsetNpc + yOffsetButton, 20, 20, "-"); + zoomOut = new GuiNpcButton(0, guiLeft + 22 + xOffsetNpc + xOffsetButton, guiTop + yOffsetNpc + yOffsetButton, 20, 20, "+"); + rotateLeft = new GuiNpcButton(0, guiLeft + 44 + xOffsetNpc + xOffsetButton, guiTop + yOffsetNpc + yOffsetButton, 20, 20, "<"); + rotateRight = new GuiNpcButton(0, guiLeft + 66 + xOffsetNpc + xOffsetButton, guiTop + yOffsetNpc + yOffsetButton, 20, 20, ">"); + } } @Override @@ -158,10 +168,40 @@ public abstract class GuiNPCInterface extends GuiScreen { } } mouseEvent(i, j, k); - super.mouseClicked(i, j, k); + vanillaMouseClicked(i, j, k); } } + protected void vanillaMouseClicked(int mouseX, int mouseY, int mouseButton) { + if (mouseButton == 0 || mouseButton == 1) { + for (int l = 0; l < this.buttonList.size(); ++l) { + GuiButton guibutton = (GuiButton) this.buttonList.get(l); + + AtomicBoolean rightClicked = null; + if (mouseButton == 1) { + if (guibutton instanceof GuiNpcButton && ((GuiNpcButton) guibutton).rightClickable) { + rightClicked = ((GuiNpcButton) guibutton).rightClicked; + rightClicked.set(true); + } else + continue; + } + + if (guibutton.mousePressed(this.mc, mouseX, mouseY)) { + GuiScreenEvent.ActionPerformedEvent.Pre event = new GuiScreenEvent.ActionPerformedEvent.Pre(this, guibutton, this.buttonList); + if (MinecraftForge.EVENT_BUS.post(event)) + break; + this.selectedButton = event.button; + event.button.func_146113_a(this.mc.getSoundHandler()); + this.actionPerformed(event.button); + if (this.equals(this.mc.currentScreen)) + MinecraftForge.EVENT_BUS.post(new GuiScreenEvent.ActionPerformedEvent.Post(this, event.button, this.buttonList)); + } + + if (rightClicked != null) + rightClicked.set(false); + } + } + } @Override public void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) { if (subgui != null) { @@ -206,11 +246,18 @@ public abstract class GuiNPCInterface extends GuiScreen { guiScrollableComponent.keyTyped(c, i); } - // Fixes closing sub with escape closes all of its parents - boolean enoughTimeSinceSubClosed = Minecraft.getSystemTime() - timeClosedSubGui > 50; + /* + Fixes closing sub with escape closes all of its parents. + The outermost GUI (root of all subs) closes the deepest open sub on ESC. + */ + boolean isSub = this instanceof SubGuiInterface; - if (closeOnEsc && enoughTimeSinceSubClosed && (i == 1 || !GuiNpcTextField.isFieldActive() && isInventoryKey(i))) { - close(); + if (closeOnEsc && !isSub && (i == 1 || !GuiNpcTextField.isFieldActive() && isInventoryKey(i))) { + SubGuiInterface sub = getSubGui(); + if (sub != null) + sub.close(); + else + close(); } } @@ -219,6 +266,9 @@ public abstract class GuiNPCInterface extends GuiScreen { } public void close() { + if(GuiNpcTextField.activeTextfield != null) + GuiNpcTextField.unfocus(); + Keyboard.enableRepeatEvents(false); displayGuiScreen(null); mc.setIngameFocus(); @@ -339,6 +389,9 @@ public abstract class GuiNPCInterface extends GuiScreen { if (subgui != null) { subgui.drawScreen(i, j, f); } + + if (drawNpc) + drawNpcWithExtras(npc, i, j, f); } protected void drawBackground() { @@ -402,7 +455,6 @@ public abstract class GuiNPCInterface extends GuiScreen { public void closeSubGui(SubGuiInterface gui) { subgui = null; - timeClosedSubGui = Minecraft.getSystemTime(); initGui(); } @@ -410,17 +462,92 @@ public abstract class GuiNPCInterface extends GuiScreen { return subgui != null; } + /** + * @return The deepest open subgui + */ public SubGuiInterface getSubGui() { - if (hasSubGui() && subgui.hasSubGui()) - return subgui.getSubGui(); - return subgui; + SubGuiInterface sub = subgui; + if (sub != null) + while (sub.hasSubGui()) + sub = sub.getSubGui(); + return sub; } - public void drawNpc(int x, int y) { - drawNpc(npc, x, y, 1, 0); + private GuiNpcButton rotateLeft, rotateRight, zoomOut, zoomIn; + + public int xOffsetNpc = 0, xOffsetButton = 0, xMouseRange = 50; + public int yOffsetNpc = 0, yOffsetButton = 0, yMouseRange = 150; + + public float defaultZoom = 1, zoom = 1, rotation; + public float minZoom = 1, maxZoom = 2.5f; + + public boolean followMouse = true, allowRotate = true, drawNPConSub; + public boolean drawNpc, drawRenderButtons; + + public boolean isMouseOverRenderer(int x, int y) { + if (!allowRotate) { + return false; + } + // Center of the entity rendering + int centerX = guiLeft + xOffsetNpc; // Matches l in drawScreen() + int centerY = guiTop + yOffsetNpc; // Matches i1 in drawScreen() + + // Range from the center to start considering mouse is over renderer. + int xRange = xMouseRange; // Horizontal range (Left and right of center) + int yRange = yMouseRange; // Vertical range (Up and down of center) + + // Check if the mouse is within the range area + return mouseX >= centerX - xRange && mouseX <= centerX + xRange && mouseY >= centerY - yRange && mouseY <= centerY + yRange; } - public void drawNpc(EntityLivingBase entity, int x, int y, float zoomed, int rotation) { + + public void drawNpcWithExtras(EntityLivingBase entity, int mouseX, int mouseY, float partialTicks) { + drawNpc(entity, mouseX, mouseY, partialTicks); + } + public void drawNpc(EntityLivingBase entity, int mouseX, int mouseY, float partialTicks) { + if (hasSubGui() && !drawNPConSub) + return; + + + if (drawRenderButtons) { + rotateLeft.drawButton(mc, mouseX, mouseY); + rotateRight.drawButton(mc, mouseX, mouseY); + zoomOut.drawButton(mc, mouseX, mouseY); + zoomIn.drawButton(mc, mouseX, mouseY); + } + + if (Mouse.isButtonDown(0) && drawRenderButtons) { + if (this.rotateLeft.mousePressed(this.mc, mouseX, mouseY)) { + rotation += partialTicks * 1.5F; + } else if (this.rotateRight.mousePressed(this.mc, mouseX, mouseY)) { + rotation -= partialTicks * 1.5F; + } else if (this.zoomOut.mousePressed(this.mc, mouseX, mouseY) && zoom < maxZoom) { + zoom += partialTicks * 0.05F; + } else if (this.zoomIn.mousePressed(this.mc, mouseX, mouseY) && zoom > minZoom) { + zoom -= partialTicks * 0.05F; + } + } + + + if (isMouseOverRenderer(mouseX, mouseY)) { + zoom += Mouse.getDWheel() * 0.001f; + if (Mouse.isButtonDown(0)) { + rotation -= Mouse.getDX() * 0.75f; + } else if (Mouse.isButtonDown(1)) { + rotation = 0; + zoom = defaultZoom; + } + } + + if (zoom > maxZoom) + zoom = maxZoom; + if (zoom < minZoom) + zoom = minZoom; + + drawNpc(entity, mouseX, mouseY, xOffsetNpc, yOffsetNpc, zoom, rotation, partialTicks); + } + + public void drawNpc(EntityLivingBase entity, int mouseX, int mouseY, int x, int y, float zoomed, float rotation, float partialTicks) { EntityNPCInterface npc = null; if (entity instanceof EntityNPCInterface) npc = (EntityNPCInterface) entity; @@ -430,10 +557,10 @@ public abstract class GuiNPCInterface extends GuiScreen { npc.isDrawn = true; GL11.glEnable(GL11.GL_COLOR_MATERIAL); GL11.glPushMatrix(); - GL11.glTranslatef(guiLeft + x, guiTop + y, 50F); + GL11.glTranslatef(guiLeft + x, guiTop + y, 90F); float scale = 1; if (entity.height > 2.4) - scale = 2 / npc.height; + scale = 2 / entity.height; GL11.glScalef(-30 * scale * zoomed, 30 * scale * zoomed, 30 * scale * zoomed); GL11.glRotatef(180F, 0.0F, 0.0F, 1.0F); @@ -447,20 +574,27 @@ public abstract class GuiNPCInterface extends GuiScreen { int orientation = 0; if (npc != null) { orientation = npc.ais.orientation; - npc.ais.orientation = rotation; + npc.ais.orientation = (int) rotation; } GL11.glRotatef(135F, 0.0F, 1.0F, 0.0F); RenderHelper.enableStandardItemLighting(); GL11.glRotatef(-135F, 0.0F, 1.0F, 0.0F); - GL11.glRotatef(-(float) Math.atan(f6 / 40F) * 20F, 1.0F, 0.0F, 0.0F); + GL11.glRotatef(-(float) Math.atan(f6 / 400F) * 20F, 1.0F, 0.0F, 0.0F); entity.renderYawOffset = rotation; - entity.rotationYaw = (float) Math.atan(f5 / 80F) * 40F + rotation; - entity.rotationPitch = -(float) Math.atan(f6 / 40F) * 20F; + entity.rotationYaw = followMouse ? (float) Math.atan(f5 / 80F) * 40F + rotation : 0; + entity.rotationPitch = followMouse ? -(float) Math.atan(f6 / 40F) * 20F : 0; entity.rotationYawHead = entity.rotationYaw; GL11.glTranslatef(0.0F, entity.yOffset, 0.0F); RenderManager.instance.playerViewY = 180F; - RenderManager.instance.renderEntityWithPosYaw(entity, 0, 0, 0, 0, 1); + ClientEventHandler.renderingEntityInGUI = true; + + try { + RenderManager.instance.renderEntityWithPosYaw(entity, 0, 0, 0, 0, 1); + } catch (Exception e) { + } + + ClientEventHandler.renderingEntityInGUI = false; entity.prevRenderYawOffset = entity.renderYawOffset = f2; entity.prevRotationYaw = entity.rotationYaw = f3; entity.prevRotationPitch = entity.rotationPitch = f4; diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiNPCInterface2.java b/src/main/java/noppes/npcs/client/gui/util/GuiNPCInterface2.java index 7c9f1d43e..190a03613 100644 --- a/src/main/java/noppes/npcs/client/gui/util/GuiNPCInterface2.java +++ b/src/main/java/noppes/npcs/client/gui/util/GuiNPCInterface2.java @@ -17,7 +17,7 @@ public abstract class GuiNPCInterface2 extends GuiNPCInterface { xSize = 420; ySize = 200; menu = new GuiNpcMenu(this, activeMenu, npc); - + closeOnEsc = true; } @Override diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiNpcButton.java b/src/main/java/noppes/npcs/client/gui/util/GuiNpcButton.java index 1052b9c21..37ffdb807 100644 --- a/src/main/java/noppes/npcs/client/gui/util/GuiNpcButton.java +++ b/src/main/java/noppes/npcs/client/gui/util/GuiNpcButton.java @@ -12,6 +12,7 @@ import org.lwjgl.opengl.GL12; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; public class GuiNpcButton extends GuiButton { @@ -31,6 +32,8 @@ public class GuiNpcButton extends GuiButton { protected int iconPosX = 0; protected int iconPosY = 0; + public boolean rightClickable; + public GuiNpcButton(int i, int j, int k, String s) { super(i, j, k, StatCollector.translateToLocal(s)); id = i; @@ -40,6 +43,9 @@ public class GuiNpcButton extends GuiButton { this(i, j, k, display[val]); this.display = display; this.displayValue = val; + + if (display.length > 1) + rightClickable = true; } public GuiNpcButton(int i, int j, int k, int l, int m, String string) { @@ -51,6 +57,9 @@ public class GuiNpcButton extends GuiButton { this(i, j, k, l, m, display.length == 0 ? "" : display[val % display.length]); this.display = display; this.displayValue = display.length == 0 ? 0 : val % display.length; + + if (display.length > 1) + rightClickable = true; } public GuiNpcButton(int i, int j, int k, int l, int m, Enum[] displayEnums, int val) { @@ -61,6 +70,9 @@ public class GuiNpcButton extends GuiButton { } this.display = strings.toArray(new String[0]); this.displayValue = display.length == 0 ? 0 : val % display.length; + + if (display.length > 1) + rightClickable = true; } public void setDisplayText(String text) { @@ -113,11 +125,17 @@ public class GuiNpcButton extends GuiButton { return this; } + public AtomicBoolean rightClicked = new AtomicBoolean(); @Override public boolean mousePressed(Minecraft minecraft, int i, int j) { boolean bo = super.mousePressed(minecraft, i, j); if (bo && display != null && display.length != 0) { - displayValue = (displayValue + 1) % display.length; + if (rightClicked.get()) { + if (displayValue <= 0) + displayValue = display.length; + displayValue--; + } else + displayValue = (displayValue + 1) % display.length; this.setDisplayText(display[displayValue]); } return bo; diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiScrollWindow.java b/src/main/java/noppes/npcs/client/gui/util/GuiScrollWindow.java index 6c81a0b86..3555b30fd 100644 --- a/src/main/java/noppes/npcs/client/gui/util/GuiScrollWindow.java +++ b/src/main/java/noppes/npcs/client/gui/util/GuiScrollWindow.java @@ -5,6 +5,8 @@ import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.GuiYesNoCallback; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.common.MinecraftForge; import noppes.npcs.entity.EntityNPCInterface; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; @@ -12,6 +14,7 @@ import org.lwjgl.opengl.GL11; import java.util.ArrayList; import java.util.HashMap; +import java.util.concurrent.atomic.AtomicBoolean; public class GuiScrollWindow extends GuiScreen implements ITextfieldListener, ICustomScrollListener, GuiYesNoCallback { public static final ResourceLocation resource = new ResourceLocation("customnpcs", "textures/gui/misc.png"); @@ -107,9 +110,39 @@ public class GuiScrollWindow extends GuiScreen implements ITextfieldListener, IC } } mouseEvent(i, j, k); - super.mouseClicked(i, j, k); + vanillaMouseClicked(i, j, k); } + protected void vanillaMouseClicked(int mouseX, int mouseY, int mouseButton) { + if (mouseButton == 0 || mouseButton == 1) { + for (int l = 0; l < this.buttonList.size(); ++l) { + GuiButton guibutton = (GuiButton) this.buttonList.get(l); + + AtomicBoolean rightClicked = null; + if (mouseButton == 1) { + if (guibutton instanceof GuiNpcButton && ((GuiNpcButton) guibutton).rightClickable) { + rightClicked = ((GuiNpcButton) guibutton).rightClicked; + rightClicked.set(true); + } else + continue; + } + + if (guibutton.mousePressed(this.mc, mouseX, mouseY)) { + GuiScreenEvent.ActionPerformedEvent.Pre event = new GuiScreenEvent.ActionPerformedEvent.Pre(this, guibutton, this.buttonList); + if (MinecraftForge.EVENT_BUS.post(event)) + break; + this.selectedButton = event.button; + event.button.func_146113_a(this.mc.getSoundHandler()); + this.actionPerformed(event.button); + if (this.equals(this.mc.currentScreen)) + MinecraftForge.EVENT_BUS.post(new GuiScreenEvent.ActionPerformedEvent.Post(this, event.button, this.buttonList)); + } + + if (rightClicked != null) + rightClicked.set(false); + } + } + } public void mouseEvent(int i, int j, int k) { } @@ -292,7 +325,7 @@ public class GuiScrollWindow extends GuiScreen implements ITextfieldListener, IC public void adjustScroll(int mouseX, int mouseY, int mouseScroll) { mouseX -= xPos; mouseY -= yPos; - if (Mouse.isButtonDown(0)) { + if (Mouse.isButtonDown(0) && !parent.hasSubGui()) { if (mouseX >= clipWidth - 9 && mouseX < clipWidth - 4 && mouseY >= 4 && mouseY < clipHeight) { isScrolling = true; } diff --git a/src/main/java/noppes/npcs/client/model/ModelMPM.java b/src/main/java/noppes/npcs/client/model/ModelMPM.java index 6c6cc623d..7a8273a77 100644 --- a/src/main/java/noppes/npcs/client/model/ModelMPM.java +++ b/src/main/java/noppes/npcs/client/model/ModelMPM.java @@ -82,6 +82,7 @@ public class ModelMPM extends ModelNPCMale { public ModelTail tail; public ModelBase entityModel; public EntityLivingBase entity; + public EntityCustomNpc npc; public boolean currentlyPlayerTexture; @@ -354,7 +355,7 @@ public class ModelMPM extends ModelNPCMale { @Override public void render(Entity par1Entity, float par2, float par3, float par4, float par5, float par6, float par7) { - EntityCustomNpc npc = (EntityCustomNpc) par1Entity; + npc = (EntityCustomNpc) par1Entity; EntityPlayer player = Minecraft.getMinecraft().thePlayer; if (npc.scriptInvisibleToPlayer(Minecraft.getMinecraft().thePlayer) && (player.getHeldItem() == null || player.getHeldItem().getItem() != CustomItems.wand)) return; diff --git a/src/main/java/noppes/npcs/client/model/part/ModelLegs.java b/src/main/java/noppes/npcs/client/model/part/ModelLegs.java index fe9325b4d..e5f8b5937 100644 --- a/src/main/java/noppes/npcs/client/model/part/ModelLegs.java +++ b/src/main/java/noppes/npcs/client/model/part/ModelLegs.java @@ -18,7 +18,7 @@ import org.lwjgl.opengl.GL11; public class ModelLegs extends ModelScaleRenderer { private EntityCustomNpc entity; - private ModelScaleRenderer leg1, leg2; + public ModelScaleRenderer leg1, leg2; private ModelRenderer spider; private ModelRenderer horse; private ModelNagaLegs naga; diff --git a/src/main/java/noppes/npcs/client/renderer/RenderNPCHumanMale.java b/src/main/java/noppes/npcs/client/renderer/RenderNPCHumanMale.java index 452627bad..565454766 100644 --- a/src/main/java/noppes/npcs/client/renderer/RenderNPCHumanMale.java +++ b/src/main/java/noppes/npcs/client/renderer/RenderNPCHumanMale.java @@ -8,6 +8,7 @@ import net.minecraft.client.renderer.entity.RenderBiped; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.Items; import net.minecraft.item.Item; import net.minecraft.item.ItemArmor; import net.minecraft.item.ItemBlock; @@ -229,7 +230,8 @@ public class RenderNPCHumanMale extends RenderNPCInterface { GL11.glRotatef(20.0F, 1.0F, 0.0F, 0.0F); GL11.glRotatef(45.0F, 0.0F, 1.0F, 0.0F); GL11.glScalef(-var6, -var6, var6); - } else if (itemstack2.getItem() instanceof ItemBow && (customRenderer == null || pluginMod)) { + } else if ((itemstack2.getItem() != null && itemstack2.getItem() == Items.bow) || + (itemstack2.getItem() instanceof ItemBow && (customRenderer == null || pluginMod))) { var6 = 0.625F; GL11.glTranslatef(0.0F, 0.125F, 0.3125F); GL11.glRotatef(-20.0F, 0.0F, 1.0F, 0.0F); @@ -322,7 +324,8 @@ public class RenderNPCHumanMale extends RenderNPCInterface { GL11.glRotatef(20.0F, 1.0F, 0.0F, 0.0F); GL11.glRotatef(45.0F, 0.0F, 1.0F, 0.0F); GL11.glScalef(var6, -var6, var6); - } else if (itemstack2.getItem() instanceof ItemBow && (customRenderer == null || pluginMod)) { + } else if ((itemstack2.getItem() != null && itemstack2.getItem() == Items.bow) || + (itemstack2.getItem() instanceof ItemBow && (customRenderer == null || pluginMod))) { var6 = 0.625F; GL11.glTranslatef(0.0F, 0.125F, 0.3125F); GL11.glRotatef(-20.0F, 0.0F, 1.0F, 0.0F); diff --git a/src/main/java/noppes/npcs/constants/EnumRoleType.java b/src/main/java/noppes/npcs/constants/EnumRoleType.java index a82f4b607..624658fb3 100644 --- a/src/main/java/noppes/npcs/constants/EnumRoleType.java +++ b/src/main/java/noppes/npcs/constants/EnumRoleType.java @@ -2,5 +2,5 @@ package noppes.npcs.constants; public enum EnumRoleType { - None, Trader, Follower, Bank, Transporter, Postman, Companion + None, Trader, Follower, Bank, Transporter, Postman, Companion, Mount } diff --git a/src/main/java/noppes/npcs/controllers/data/LinkedItem.java b/src/main/java/noppes/npcs/controllers/data/LinkedItem.java index 6144dc480..4fb5fc6e7 100644 --- a/src/main/java/noppes/npcs/controllers/data/LinkedItem.java +++ b/src/main/java/noppes/npcs/controllers/data/LinkedItem.java @@ -29,6 +29,7 @@ public class LinkedItem implements ILinkedItem { public boolean isNormalItem = false; public boolean isTool = false; public int digSpeed = 1; + public int attackSpeed = 20; public int armorType = -2; //-2: Fits in no armor slot, -1: Fits in all slots, 0 - 3: Fits in Head -> Boots slot respectively public int enchantability; @@ -58,6 +59,7 @@ public class LinkedItem implements ILinkedItem { compound.setBoolean("IsTool", this.isTool); compound.setBoolean("IsNormalItem", this.isNormalItem); compound.setInteger("DigSpeed", this.digSpeed); + compound.setInteger("AttackSpeed",this.attackSpeed); compound.setInteger("ArmorType", this.armorType); compound.setInteger("Enchantability", this.enchantability); @@ -87,6 +89,7 @@ public class LinkedItem implements ILinkedItem { this.isTool = compound.getBoolean("IsTool"); this.isNormalItem = compound.getBoolean("IsNormalItem"); this.digSpeed = compound.getInteger("DigSpeed"); + this.attackSpeed = compound.getInteger("AttackSpeed"); this.armorType = compound.getInteger("ArmorType"); this.enchantability = compound.getInteger("Enchantability"); @@ -251,4 +254,10 @@ public class LinkedItem implements ILinkedItem { setScriptHandler(data = new LinkedItemScript()); return data; } + + @Override + public int getAttackSpeed() {return attackSpeed;} + + @Override + public void setAttackSpeed(int time) {this.attackSpeed = time;} } diff --git a/src/main/java/noppes/npcs/controllers/data/PlayerData.java b/src/main/java/noppes/npcs/controllers/data/PlayerData.java index 5f6a5e00d..599f81ff1 100644 --- a/src/main/java/noppes/npcs/controllers/data/PlayerData.java +++ b/src/main/java/noppes/npcs/controllers/data/PlayerData.java @@ -84,6 +84,7 @@ public class PlayerData implements IExtendedEntityProperties, IPlayerData { public ScreenSize screenSize = new ScreenSize(-1, -1); public int profileSlot = 0; + private boolean specialKeyDown = false; public void onLogin() { // Continue playing animation for self when re-logging @@ -267,6 +268,14 @@ public class PlayerData implements IExtendedEntityProperties, IPlayerData { return this.isGUIOpen; } + public boolean isSpecialKeyDown() { + return specialKeyDown; + } + + public void setSpecialKeyDown(boolean specialKeyDown) { + this.specialKeyDown = specialKeyDown; + } + public ScreenSize getScreenSize() { return screenSize; } diff --git a/src/main/java/noppes/npcs/controllers/data/action/action/ConditionalAction.java b/src/main/java/noppes/npcs/controllers/data/action/action/ConditionalAction.java index 7bcd0ef97..9e608df37 100644 --- a/src/main/java/noppes/npcs/controllers/data/action/action/ConditionalAction.java +++ b/src/main/java/noppes/npcs/controllers/data/action/action/ConditionalAction.java @@ -88,7 +88,7 @@ public class ConditionalAction extends Action implements IConditionalAction { @Override public boolean isTerminated() { - return terminateWhen != null && terminateWhen.apply(this); + return checkTermination(); } public void inheritedTick() { @@ -107,10 +107,10 @@ public class ConditionalAction extends Action implements IConditionalAction { checkCount++; Runnable execute = () -> { - if (condition != null && condition.apply(this)) + if (evaluatePredicate(condition, "Condition")) executeTask(); - if (isTerminated()) { + if (checkTermination()) { if (onTermination != null) executeOnTermination(); markDone(); @@ -153,6 +153,32 @@ public class ConditionalAction extends Action implements IConditionalAction { manager.LOGGER.log("Finished executing onTermination task", this); } + private boolean checkTermination() { + return evaluatePredicate(terminateWhen, "Termination condition"); + } + + private boolean evaluatePredicate(Function predicate, String name) { + if (predicate == null) + return false; + + Boolean result; + try { + result = predicate.apply(this); + } catch (Throwable t) { + manager.LOGGER.error(name + " of " + this + " threw an exception:", t); + markDone(); + return false; + } + + if (result == null) { + if (manager.inDebugMode()) + manager.LOGGER.log(name + " returned null; treating as false", this); + return false; + } + + return result; + } + public String toString() { return String.format("%s [queue='%s', scheduled=%s, done=%s, paused=%s, updateEvery=%s, duration=%d/%d, count=%d/%d, checks=%d/%d, taskExecuted=%s, threaded=%s]", getIdentifier(), getQueueName(), diff --git a/src/main/java/noppes/npcs/entity/EntityNPCFlying.java b/src/main/java/noppes/npcs/entity/EntityNPCFlying.java index 92ad030c5..3f57ce85f 100644 --- a/src/main/java/noppes/npcs/entity/EntityNPCFlying.java +++ b/src/main/java/noppes/npcs/entity/EntityNPCFlying.java @@ -40,8 +40,12 @@ public abstract class EntityNPCFlying extends EntityNPCInterface { super.onLivingUpdate(); } + @Override public void moveEntityWithHeading(float p_70612_1_, float p_70612_2_) { + if (handleMountedMovement(p_70612_1_, p_70612_2_)) + return; if (!this.canFly() || this.hurtTime != 0 || !this.canBreathe()) { + setNpcFlyingState(false); super.moveEntityWithHeading(p_70612_1_, p_70612_2_); return; } @@ -63,11 +67,13 @@ public abstract class EntityNPCFlying extends EntityNPCInterface { if (!this.getNavigator().noPath() && this.motionY > 0) { this.motionY = 0; } else { + setNpcFlyingState(false); super.moveEntityWithHeading(p_70612_1_, p_70612_2_); return; } } this.flyLimitAllow = true; + setNpcFlyingState(true); double d3 = this.motionY; super.moveEntityWithHeading(p_70612_1_, p_70612_2_); @@ -92,4 +98,57 @@ public abstract class EntityNPCFlying extends EntityNPCInterface { this.limbSwingAmount += (distance - this.limbSwingAmount) * 0.4F; this.limbSwing += this.limbSwingAmount; } + + @Override + public void performMountedMovement(float strafe, float forward, float moveSpeed) { + if (!this.canFly() || this.hurtTime != 0 || !this.canBreathe()) { + setNpcFlyingState(false); + super.performMountedMovement(strafe, forward, moveSpeed); + return; + } + + boolean flightModeActive = isMountFlightModeActive(); + + boolean aboveLimit = false; + double heightOffGround = this.posY - this.worldObj.getTopSolidOrLiquidBlock((int) this.posX, (int) this.posZ); + if (heightOffGround < 0) { + Vec3 pos = Vec3.createVectorHelper(this.posX, this.posY, this.posZ); + Vec3 posLimit = Vec3.createVectorHelper(this.posX, this.posY - this.ais.flyHeightLimit, this.posZ); + MovingObjectPosition mob = this.worldObj.rayTraceBlocks(pos, posLimit, true); + if (mob == null || mob.typeOfHit == MovingObjectPosition.MovingObjectType.MISS) { + aboveLimit = true; + } + } else if (heightOffGround > this.ais.flyHeightLimit) { + aboveLimit = true; + } + if (aboveLimit && this.ais.hasFlyLimit || (heightOffGround < Math.ceil(this.height) && this.motionY == 0)) { + this.flyLimitAllow = false; + if (!this.getNavigator().noPath() && this.motionY > 0) { + this.motionY = 0; + } else { + setNpcFlyingState(false); + super.performMountedMovement(strafe, forward, moveSpeed); + return; + } + } + this.flyLimitAllow = true; + setNpcFlyingState(true); + + if (flightModeActive) { + super.performMountedMovement(strafe, forward, moveSpeed); + this.velocityChanged = true; + return; + } + + double d3 = this.motionY; + super.performMountedMovement(strafe, forward, moveSpeed); + this.motionY = d3; + + if (this.getNavigator().noPath()) { + this.motionY = -Math.abs(this.ais.flyGravity); + } + + this.updateLimbSwing(); + this.velocityChanged = true; + } } diff --git a/src/main/java/noppes/npcs/entity/EntityNPCInterface.java b/src/main/java/noppes/npcs/entity/EntityNPCInterface.java index c72aa7117..8285cf213 100644 --- a/src/main/java/noppes/npcs/entity/EntityNPCInterface.java +++ b/src/main/java/noppes/npcs/entity/EntityNPCInterface.java @@ -32,7 +32,6 @@ import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.EntityAIAttackOnCollide; import net.minecraft.entity.ai.EntityAIBase; import net.minecraft.entity.ai.EntityAIHurtByTarget; -import net.minecraft.entity.ai.EntityAILeapAtTarget; import net.minecraft.entity.ai.EntityAIOpenDoor; import net.minecraft.entity.ai.EntityAIRestrictSun; import net.minecraft.entity.ai.EntityAISwimming; @@ -65,8 +64,10 @@ import net.minecraft.util.IChatComponent; import net.minecraft.util.IIcon; import net.minecraft.util.MathHelper; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.Vec3; import net.minecraft.world.World; import net.minecraft.world.WorldServer; +import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.event.ServerChatEvent; @@ -99,6 +100,7 @@ import noppes.npcs.ai.EntityAIMoveIndoors; import noppes.npcs.ai.EntityAIMovingPath; import noppes.npcs.ai.EntityAIOrbitTarget; import noppes.npcs.ai.EntityAIPanic; +import noppes.npcs.ai.EntityAILeapAtTargetNpc; import noppes.npcs.ai.EntityAIPounceTarget; import noppes.npcs.ai.EntityAIRangedAttack; import noppes.npcs.ai.EntityAIReturn; @@ -152,11 +154,13 @@ import noppes.npcs.roles.JobFollower; import noppes.npcs.roles.JobInterface; import noppes.npcs.roles.RoleCompanion; import noppes.npcs.roles.RoleFollower; +import noppes.npcs.roles.RoleMount; import noppes.npcs.roles.RoleInterface; import noppes.npcs.scripted.NpcAPI; import noppes.npcs.scripted.entity.ScriptNpc; import noppes.npcs.scripted.event.NpcEvent; import noppes.npcs.util.GameProfileAlt; +import noppes.npcs.util.NPCMountUtil; import java.io.IOException; import java.util.ArrayList; @@ -208,6 +212,10 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti public ResourceLocation textureLocation = null; + private final NPCMountUtil.MountState mountState = new NPCMountUtil.MountState(); + private static final int NPC_STATE_FLAG_FLYING = 1; + private static final int NPC_STATE_FLAG_JUMPING = 1 << 1; + public EnumAnimation currentAnimation = EnumAnimation.NONE; public int npcVersion = VersionCompatibility.ModRev; @@ -277,6 +285,7 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti this.dataWatcher.addObject(14, Integer.valueOf(0)); // Animation this.dataWatcher.addObject(15, Integer.valueOf(0)); // isWalking this.dataWatcher.addObject(16, ""); // Role + this.dataWatcher.addObject(17, Byte.valueOf((byte) 0)); // Mount state flags } protected boolean isAIEnabled() { @@ -468,6 +477,8 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti super.onLivingUpdate(); + handleMountRiderState(); + if (worldObj.isRemote) { if (roleInterface != null) { roleInterface.clientUpdate(); @@ -960,7 +971,7 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti */ public void setLeapTask() { if (this.ais.leapType == 1) - this.tasks.addTask(this.taskCount++, aiLeap = new EntityAILeapAtTarget(this, 0.4F)); + this.tasks.addTask(this.taskCount++, aiLeap = new EntityAILeapAtTargetNpc(this, 0.4F)); if (this.ais.leapType == 2) this.tasks.addTask(this.taskCount++, aiLeap = new EntityAIPounceTarget(this)); } @@ -1478,10 +1489,15 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti this.spawnExplosionParticle(); delete(); } else { - if (this.riddenByEntity != null) + if (this.riddenByEntity != null) { + NPCMountUtil.stabilizeDismountedRider(this.riddenByEntity); this.riddenByEntity.mountEntity(null); + NPCMountUtil.haltMountedMotion(this, mountState); + } if (this.ridingEntity != null) this.mountEntity(null); + mountState.lastRider = null; + NPCMountUtil.resetMountedFlightState(this, mountState); setHealth(-1); setSprinting(false); getNavigator().clearPathEntity(); @@ -1612,7 +1628,32 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti } public boolean isFlying() { - return isWalking() && !onGround; + return isNpcFlying(); + } + + public boolean isNpcFlying() { + return (dataWatcher.getWatchableObjectByte(17) & NPC_STATE_FLAG_FLYING) != 0; + } + + public boolean isNpcJumping() { + return (dataWatcher.getWatchableObjectByte(17) & NPC_STATE_FLAG_JUMPING) != 0; + } + + private void setNpcStateFlag(int mask, boolean value) { + byte current = dataWatcher.getWatchableObjectByte(17); + byte updated = value ? (byte) (current | mask) : (byte) (current & ~mask); + if (current != updated) { + dataWatcher.updateObject(17, updated); + } + } + + public void setNpcFlyingState(boolean flying) { + setNpcStateFlag(NPC_STATE_FLAG_FLYING, flying); + } + + public void setNpcJumpingState(boolean jumping) { + setNpcStateFlag(NPC_STATE_FLAG_JUMPING, jumping); + this.isJumping = jumping; } public void setBoolFlag(boolean bo, int id) { @@ -1753,6 +1794,11 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti roleInterface.writeToNBT(bard); compound.setTag("Companion", bard); } + if (advanced.role == EnumRoleType.Mount) { + NBTTagCompound mount = new NBTTagCompound(); + roleInterface.writeToNBT(mount); + compound.setTag("Mount", mount); + } if (this instanceof EntityCustomNpc) { compound.setTag("ModelData", ((EntityCustomNpc) this).modelData.writeToNBT()); @@ -1790,6 +1836,10 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti NBTTagCompound companion = compound.getCompoundTag("Companion"); roleInterface.readFromNBT(companion); } + if (advanced.role == EnumRoleType.Mount) { + NBTTagCompound mount = compound.getCompoundTag("Mount"); + roleInterface.readFromNBT(mount); + } if (this instanceof EntityCustomNpc) { ((EntityCustomNpc) this).modelData.readFromNBT(compound.getCompoundTag("ModelData")); } @@ -1852,9 +1902,12 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti } @Override - protected void fall(float par1) { + protected void fall(float distance) { + if (NPCMountUtil.isFlyingMountWithFlightEnabled(this)) { + return; + } if (!this.stats.noFallDamage) - super.fall(par1); + super.fall(distance); } @Override @@ -2056,15 +2109,111 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti } @Override - public void moveEntityWithHeading(float p_70612_1_, float p_70612_2_) { + public void moveEntityWithHeading(float strafe, float forward) { + if (handleMountedMovement(strafe, forward)) { + return; + } double d0 = this.posX; double d1 = this.posY; double d2 = this.posZ; - super.moveEntityWithHeading(p_70612_1_, p_70612_2_); + super.moveEntityWithHeading(strafe, forward); if (advanced.role == EnumRoleType.Companion && !isRemote()) ((RoleCompanion) roleInterface).addMovementStat(this.posX - d0, this.posY - d1, this.posZ - d2); } + protected boolean handleMountedMovement(float strafe, float forward) { + return NPCMountUtil.handleMountedMovement(this, mountState, strafe, forward); + } + + public void performMountedMovement(float strafe, float forward, float moveSpeed) { + this.moveStrafing = strafe; + this.moveForward = forward; + + boolean flightMode = isMountFlightModeActive(); + double prevMotionX = this.motionX; + double prevMotionY = this.motionY; + double prevMotionZ = this.motionZ; + float previousJumpFactor = this.jumpMovementFactor; + float appliedJumpFactor = getMountedAirStrafeFactor(moveSpeed, flightMode); + + this.jumpMovementFactor = appliedJumpFactor; + + this.setAIMoveSpeed(moveSpeed); + + super.moveEntityWithHeading(strafe, forward); + + if (flightMode) { + this.motionY = prevMotionY; + this.isAirBorne = true; + } + + this.jumpMovementFactor = previousJumpFactor; + + if (!worldObj.isRemote) { + double newMotionX = this.motionX; + double newMotionY = this.motionY; + double newMotionZ = this.motionZ; + if (Math.abs(newMotionX - prevMotionX) > 1.0E-5D || Math.abs(newMotionY - prevMotionY) > 1.0E-5D || Math.abs(newMotionZ - prevMotionZ) > 1.0E-5D) { + this.velocityChanged = true; + } + } + + syncMountedRiderVelocity(); + updateMountedLimbSwing(); + } + + protected boolean isMountFlightModeActive() { + return NPCMountUtil.isMountInFlightMode(mountState); + } + + private float getMountedAirStrafeFactor(float moveSpeed, boolean flightMode) { + if (moveSpeed <= 0.0F) { + return 0.0F; + } + if (!flightMode) { + return moveSpeed * 0.1F; + } + return moveSpeed * 0.5F; + } + + private void syncMountedRiderVelocity() { + if (!(this.riddenByEntity instanceof EntityLivingBase)) { + return; + } + EntityLivingBase rider = (EntityLivingBase) this.riddenByEntity; + double riderPrevMotionX = rider.motionX; + double riderPrevMotionY = rider.motionY; + double riderPrevMotionZ = rider.motionZ; + + rider.motionX = this.motionX; + rider.motionY = this.motionY; + rider.motionZ = this.motionZ; + rider.fallDistance = 0.0F; + rider.isAirBorne = !this.onGround; + + if (!worldObj.isRemote) { + if (Math.abs(rider.motionX - riderPrevMotionX) > 1.0E-5D || Math.abs(rider.motionY - riderPrevMotionY) > 1.0E-5D || Math.abs(rider.motionZ - riderPrevMotionZ) > 1.0E-5D) { + rider.velocityChanged = true; + } + } + } + + private void updateMountedLimbSwing() { + this.prevLimbSwingAmount = this.limbSwingAmount; + double deltaX = this.posX - this.prevPosX; + double deltaZ = this.posZ - this.prevPosZ; + if (worldObj.isRemote && deltaX * deltaX + deltaZ * deltaZ < 1.0E-6D) { + deltaX = this.motionX; + deltaZ = this.motionZ; + } + float limbSwingSpeed = MathHelper.sqrt_double(deltaX * deltaX + deltaZ * deltaZ) * 4.0F; + if (limbSwingSpeed > 1.0F) { + limbSwingSpeed = 1.0F; + } + this.limbSwingAmount += (limbSwingSpeed - this.limbSwingAmount) * 0.4F; + this.limbSwing += this.limbSwingAmount; + } + @Override public boolean allowLeashing() { return false; @@ -2075,6 +2224,37 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti return false; } + @Override + public void updateRiderPosition() { + if (advanced.role == EnumRoleType.Mount && roleInterface instanceof RoleMount && riddenByEntity != null) { + RoleMount mount = (RoleMount) roleInterface; + double scale = Math.max(0.1D, this.display.modelSize / 5.0D); + Vec3 seat = Vec3.createVectorHelper(mount.getOffsetX(), 0.0D, mount.getOffsetZ() + (0.8D * scale)); + seat.rotateAroundY((float) Math.toRadians(-this.renderYawOffset)); + double px = this.posX + seat.xCoord; + double py = this.posY + this.getMountedYOffset() + riddenByEntity.getYOffset() + mount.getOffsetY(); + double pz = this.posZ + seat.zCoord; + + riddenByEntity.setPosition(px, py, pz); + + if (riddenByEntity instanceof EntityLivingBase) { + EntityLivingBase rider = (EntityLivingBase) riddenByEntity; + rider.prevRotationPitch = rider.rotationPitch; + rider.prevRotationYaw = rider.rotationYaw; + rider.prevRenderYawOffset = this.renderYawOffset; + rider.renderYawOffset = this.renderYawOffset; + rider.prevRotationYawHead = this.renderYawOffset; + rider.rotationYawHead = this.renderYawOffset; + } + } else { + super.updateRiderPosition(); + } + } + + private void handleMountRiderState() { + NPCMountUtil.handleMountRiderState(this, mountState); + } + // Model Types: 0: Steve 64x32, 1: Steve 64x64, 2: Alex 64x64 public int getModelType() { return this.display.modelType; diff --git a/src/main/java/noppes/npcs/entity/EntityNpcDragon.java b/src/main/java/noppes/npcs/entity/EntityNpcDragon.java index 6f490583f..a9df9da99 100644 --- a/src/main/java/noppes/npcs/entity/EntityNpcDragon.java +++ b/src/main/java/noppes/npcs/entity/EntityNpcDragon.java @@ -94,6 +94,7 @@ public class EntityNpcDragon extends EntityNPCInterface { field_40172_ax += f1 * 0.5F; } super.onLivingUpdate(); + this.isFlying = isNpcFlying(); } // public float ticks = 0.0f; diff --git a/src/main/java/noppes/npcs/entity/EntityNpcPony.java b/src/main/java/noppes/npcs/entity/EntityNpcPony.java index ed6ca617c..81ba41233 100644 --- a/src/main/java/noppes/npcs/entity/EntityNpcPony.java +++ b/src/main/java/noppes/npcs/entity/EntityNpcPony.java @@ -35,4 +35,10 @@ public class EntityNpcPony extends EntityNPCInterface { super.onUpdate(); } + @Override + public void onLivingUpdate() { + super.onLivingUpdate(); + this.isFlying = isNpcFlying(); + } + } diff --git a/src/main/java/noppes/npcs/roles/RoleMount.java b/src/main/java/noppes/npcs/roles/RoleMount.java new file mode 100644 index 000000000..f930a4975 --- /dev/null +++ b/src/main/java/noppes/npcs/roles/RoleMount.java @@ -0,0 +1,202 @@ +package noppes.npcs.roles; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import noppes.npcs.entity.EntityNPCInterface; +import noppes.npcs.util.ValueUtil; + +public class RoleMount extends RoleInterface { + + private float offsetX; + private float offsetY; + private float offsetZ; + private boolean storedReturnToStart; + private float jumpStrength = 1.0F; + private boolean allowSprint = true; + private boolean flyingMountEnabled = false; + private boolean hoverMode = false; + private float flyingAscendSpeed = 0.60F; + private float flyingDescendSpeed = 0.35F; + + public RoleMount(EntityNPCInterface npc) { + super(npc); + this.storedReturnToStart = npc.ais.returnToStart; + npc.ais.returnToStart = false; + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound compound) { + compound.setFloat("MountOffsetX", offsetX); + compound.setFloat("MountOffsetY", offsetY); + compound.setFloat("MountOffsetZ", offsetZ); + compound.setBoolean("MountReturnFlag", storedReturnToStart); + compound.setFloat("MountJumpStrength", jumpStrength); + compound.setBoolean("MountAllowSprint", allowSprint); + compound.setBoolean("MountAllowFlying", flyingMountEnabled); + compound.setBoolean("MountHoverMode", hoverMode); + compound.setFloat("MountFlyingAscendSpeed", flyingAscendSpeed); + compound.setFloat("MountFlyingDescendSpeed", flyingDescendSpeed); + return compound; + } + + @Override + public void readFromNBT(NBTTagCompound compound) { + setOffsetX(compound.getFloat("MountOffsetX")); + setOffsetY(compound.getFloat("MountOffsetY")); + setOffsetZ(compound.getFloat("MountOffsetZ")); + if (compound.hasKey("MountReturnFlag")) { + storedReturnToStart = compound.getBoolean("MountReturnFlag"); + } else { + storedReturnToStart = npc.ais.returnToStart; + } + if (compound.hasKey("MountJumpStrength")) { + setJumpStrength(compound.getFloat("MountJumpStrength")); + } else { + jumpStrength = 1.0F; + } + allowSprint = !compound.hasKey("MountAllowSprint") || compound.getBoolean("MountAllowSprint"); + flyingMountEnabled = compound.hasKey("MountAllowFlying") && compound.getBoolean("MountAllowFlying"); + hoverMode = compound.hasKey("MountHoverMode") && compound.getBoolean("MountHoverMode"); + if (compound.hasKey("MountFlyingAscendSpeed")) { + setFlyingAscendSpeed(compound.getFloat("MountFlyingAscendSpeed")); + } else { + flyingAscendSpeed = 0.60F; + } + if (compound.hasKey("MountFlyingDescendSpeed")) { + setFlyingDescendSpeed(compound.getFloat("MountFlyingDescendSpeed")); + } else if (compound.hasKey("MountFlyingFallSpeed")) { + setFlyingDescendSpeed(compound.getFloat("MountFlyingFallSpeed")); + } else { + flyingDescendSpeed = 0.35F; + } + npc.ais.returnToStart = false; + } + + @Override + public void interact(EntityPlayer player) { + if (player == null || npc.worldObj.isRemote) { + return; + } + if (npc.riddenByEntity != null && npc.riddenByEntity != player) { + return; + } + if (player.ridingEntity != null && player.ridingEntity != npc) { + player.mountEntity(null); + } + player.fallDistance = 0.0F; + npc.fallDistance = 0.0F; + player.mountEntity(npc); + npc.getNavigator().clearPathEntity(); + npc.setAttackTarget(null); + npc.setRevengeTarget(null); + } + + @Override + public boolean aiShouldExecute() { + if (npc.ais.returnToStart) { + storedReturnToStart = true; + npc.ais.returnToStart = false; + } + return false; + } + + public void setOffsetX(float value) { + this.offsetX = clamp(value); + } + + public void setOffsetY(float value) { + this.offsetY = clamp(value); + } + + public void setOffsetZ(float value) { + this.offsetZ = clamp(value); + } + + public float getOffsetX() { + return offsetX; + } + + public float getOffsetY() { + return offsetY; + } + + public float getOffsetZ() { + return offsetZ; + } + + public void setJumpStrength(float value) { + this.jumpStrength = ValueUtil.clamp(value, 0.1F, 3.0F); + } + + public float getJumpStrength() { + return jumpStrength; + } + + public void setSprintAllowed(boolean allowSprint) { + this.allowSprint = allowSprint; + } + + public boolean isSprintAllowed() { + return allowSprint; + } + + public void setFlyingMountEnabled(boolean enabled) { + this.flyingMountEnabled = enabled; + } + + public boolean isFlyingMountEnabled() { + return flyingMountEnabled; + } + + public void setHoverModeEnabled(boolean enabled) { + this.hoverMode = enabled; + } + + public boolean isHoverModeEnabled() { + return hoverMode; + } + + public void setFlyingAscendSpeed(float value) { + this.flyingAscendSpeed = ValueUtil.clamp(value, 0.1F, 3.0F); + } + + public float getFlyingAscendSpeed() { + return flyingAscendSpeed; + } + + public void setFlyingDescendSpeed(float value) { + this.flyingDescendSpeed = ValueUtil.clamp(value, 0.05F, 3.0F); + } + + public float getFlyingDescendSpeed() { + return flyingDescendSpeed; + } + + public void setReturnToStartPreference(boolean value) { + this.storedReturnToStart = value; + npc.ais.returnToStart = false; + } + + public boolean getReturnToStartPreference() { + return storedReturnToStart; + } + + private float clamp(float value) { + return ValueUtil.clamp(value, -5.0F, 5.0F); + } + + public void resetOffsets() { + offsetX = 0.0F; + offsetY = 0.0F; + offsetZ = 0.0F; + } + + public void onDisable() { + npc.ais.returnToStart = storedReturnToStart; + } + + @Override + public void delete() { + onDisable(); + } +} diff --git a/src/main/java/noppes/npcs/scripted/entity/ScriptLivingBase.java b/src/main/java/noppes/npcs/scripted/entity/ScriptLivingBase.java index edf9d2d29..15459194e 100644 --- a/src/main/java/noppes/npcs/scripted/entity/ScriptLivingBase.java +++ b/src/main/java/noppes/npcs/scripted/entity/ScriptLivingBase.java @@ -374,4 +374,10 @@ public class ScriptLivingBase extends ScriptEntity extends ScriptLiving imp * @param bo Whether or not the npc will try to return to his home position */ public void setReturnToHome(boolean bo) { - npc.ais.returnToStart = bo; + if (npc.advanced.role == EnumRoleType.Mount && npc.roleInterface instanceof RoleMount) { + ((RoleMount) npc.roleInterface).setReturnToStartPreference(bo); + } else { + npc.ais.returnToStart = bo; + } } /** * @return Whether or not the npc returns home */ public boolean getReturnToHome() { + if (npc.advanced.role == EnumRoleType.Mount && npc.roleInterface instanceof RoleMount) { + return ((RoleMount) npc.roleInterface).getReturnToStartPreference(); + } return npc.ais.returnToStart; } diff --git a/src/main/java/noppes/npcs/util/NPCMountUtil.java b/src/main/java/noppes/npcs/util/NPCMountUtil.java new file mode 100644 index 000000000..708bf3b76 --- /dev/null +++ b/src/main/java/noppes/npcs/util/NPCMountUtil.java @@ -0,0 +1,371 @@ +package noppes.npcs.util; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.MathHelper; +import noppes.npcs.CustomNpcs; +import noppes.npcs.controllers.PlayerDataController; +import noppes.npcs.controllers.data.PlayerData; +import noppes.npcs.entity.EntityNPCInterface; +import noppes.npcs.constants.EnumRoleType; +import noppes.npcs.roles.RoleMount; + +public final class NPCMountUtil { + private static final int MOUNT_FLIGHT_TOGGLE_WINDOW = 7; + + private NPCMountUtil() { + } + + public static class MountState { + public Entity lastRider; + public boolean flightMode; + public boolean jumpPressed; + public int flightToggleTimer; + } + + public static boolean handleMountedMovement(EntityNPCInterface npc, MountState state, float strafe, float forward) { + if (npc.advanced.role != EnumRoleType.Mount || !(npc.roleInterface instanceof RoleMount)) { + resetMountedFlightState(npc, state); + return false; + } + if (npc.riddenByEntity != null && !(npc.riddenByEntity instanceof EntityPlayer)) { + npc.riddenByEntity.mountEntity(null); + return false; + } + if (!(npc.riddenByEntity instanceof EntityPlayer)) { + resetMountedFlightState(npc, state); + return false; + } + + RoleMount mount = (RoleMount) npc.roleInterface; + EntityPlayer rider = (EntityPlayer) npc.riddenByEntity; + updateMountedFlightState(npc, state, mount, rider); + + npc.prevRotationYaw = npc.rotationYaw = rider.rotationYaw; + npc.rotationPitch = rider.rotationPitch * 0.5F; + npc.setPositionAndRotation(npc.posX, npc.posY, npc.posZ, npc.rotationYaw, npc.rotationPitch); + npc.renderYawOffset = npc.rotationYaw; + npc.rotationYawHead = npc.rotationYaw; + + float controlledStrafe = rider.moveStrafing; + float controlledForward = rider.moveForward; + if (controlledForward <= 0.0F) { + controlledForward *= 0.25F; + } + + float moveSpeed = getMountMoveSpeed(npc); + boolean riderSprinting = rider.isSprinting() && mount.isSprintAllowed(); + if (riderSprinting) { + moveSpeed *= 1.2F; + } + + if (!mount.isSprintAllowed() && rider.isSprinting()) { + rider.setSprinting(false); + } + + if (moveSpeed <= 0.0F) { + controlledStrafe = 0.0F; + controlledForward = 0.0F; + } + + npc.setSprinting(riderSprinting); + npc.stepHeight = 1.0F; + + npc.getNavigator().clearPathEntity(); + npc.setAttackTarget(null); + npc.setRevengeTarget(null); + + npc.fallDistance = 0.0F; + rider.fallDistance = 0.0F; + + applyMountedVerticalMotion(npc, state, mount, rider, moveSpeed, controlledForward); + npc.performMountedMovement(controlledStrafe, controlledForward, moveSpeed); + + return true; + } + + private static float getMountMoveSpeed(EntityNPCInterface npc) { + return Math.max(0.0F, npc.getSpeed()); + } + + private static void applyMountedVerticalMotion(EntityNPCInterface npc, MountState state, RoleMount mount, EntityLivingBase rider, float moveSpeed, float forward) { + if (mount == null) { + return; + } + double jumpFactor = MathHelper.clamp_double(mount.getJumpStrength(), 0.1D, 3.0D); + boolean flyingEnabled = mount.isFlyingMountEnabled(); + + npc.setNpcJumpingState(false); + + if (flyingEnabled) { + double ascendSpeed = MathHelper.clamp_double(mount.getFlyingAscendSpeed(), 0.1D, 3.0D); + double descendSpeed = MathHelper.clamp_double(mount.getFlyingDescendSpeed(), 0.05D, 3.0D); + boolean flightMode = isMountInFlightMode(state); + boolean jumpPressed = rider.isJumping; + boolean descendPressed = rider instanceof EntityPlayer && isSpecialKeyDown((EntityPlayer) rider); + + if (flightMode) { + double previousMotionY = npc.motionY; + double newMotionY = 0.0D; + + if (jumpPressed) { + newMotionY += ascendSpeed; + } else if (descendPressed) { + newMotionY -= descendSpeed; + } + + newMotionY = MathHelper.clamp_double(newMotionY, -descendSpeed, ascendSpeed); + npc.motionY = newMotionY; + npc.setNpcFlyingState(true); + npc.setNpcJumpingState(jumpPressed); + npc.isAirBorne = true; + npc.fallDistance = 0.0F; + + if (!npc.worldObj.isRemote && Math.abs(previousMotionY - newMotionY) > 1.0E-4D) { + npc.velocityChanged = true; + } + + if (!npc.worldObj.isRemote && rider instanceof EntityPlayer) { + EntityPlayer player = (EntityPlayer) rider; + if (!player.capabilities.isFlying) { + double playerPrevMotion = player.motionY; + player.motionY = npc.motionY; + if (Math.abs(playerPrevMotion - player.motionY) > 1.0E-4D) { + player.velocityChanged = true; + } + } + } + return; + } + + if (jumpPressed && npc.onGround) { + double previousMotionY = npc.motionY; + npc.motionY = jumpFactor; + npc.setNpcJumpingState(true); + npc.isAirBorne = true; + npc.fallDistance = 0.0F; + if (!npc.worldObj.isRemote) { + if (Math.abs(previousMotionY - npc.motionY) > 1.0E-4D) { + npc.velocityChanged = true; + } + net.minecraftforge.common.ForgeHooks.onLivingJump(npc); + } + return; + } + + if (!npc.onGround) { + double previousMotionY = npc.motionY; + double limitedMotionY = Math.max(npc.motionY, -descendSpeed); + if (Math.abs(previousMotionY - limitedMotionY) > 1.0E-4D) { + npc.motionY = limitedMotionY; + if (!npc.worldObj.isRemote) { + npc.velocityChanged = true; + } + } else { + npc.motionY = limitedMotionY; + } + npc.setNpcFlyingState(!npc.isInWater()); + } else { + npc.setNpcFlyingState(false); + } + + return; + } + + if (npc.onGround) { + double previousMotionY = npc.motionY; + if (rider.isJumping) { + npc.motionY = jumpFactor; + npc.setNpcJumpingState(true); + npc.isAirBorne = true; + npc.fallDistance = 0.0F; + if (!npc.worldObj.isRemote) { + if (Math.abs(previousMotionY - npc.motionY) > 1.0E-4D) { + npc.velocityChanged = true; + } + net.minecraftforge.common.ForgeHooks.onLivingJump(npc); + } + } else { + npc.motionY = 0.0D; + } + return; + } + + npc.setNpcFlyingState(false); + } + + public static void handleMountRiderState(EntityNPCInterface npc, MountState state) { + if (npc.worldObj.isRemote) { + if (npc.advanced.role != EnumRoleType.Mount || !(npc.roleInterface instanceof RoleMount)) { + state.lastRider = null; + } + return; + } + + if (npc.advanced.role != EnumRoleType.Mount || !(npc.roleInterface instanceof RoleMount)) { + state.lastRider = null; + return; + } + + RoleMount mount = (RoleMount) npc.roleInterface; + Entity currentRider = npc.riddenByEntity; + if (currentRider != null && !(currentRider instanceof EntityPlayer)) { + Entity dismount = currentRider; + dismount.mountEntity(null); + stabilizeDismountedRider(dismount); + haltMountedMotion(npc, state); + applyUnriddenFlightDescent(npc, state, mount); + currentRider = null; + } + if (currentRider != state.lastRider) { + if (state.lastRider != null) { + stabilizeDismountedRider(state.lastRider); + } + if (currentRider == null) { + haltMountedMotion(npc, state); + applyUnriddenFlightDescent(npc, state, mount); + } else { + resetMountedFlightState(npc, state); + } + state.lastRider = currentRider; + } else if (currentRider == null) { + applyUnriddenFlightDescent(npc, state, mount); + } + } + + public static boolean isFlyingMountWithFlightEnabled(EntityNPCInterface npc) { + return npc.advanced.role == EnumRoleType.Mount && npc.roleInterface instanceof RoleMount && ((RoleMount) npc.roleInterface).isFlyingMountEnabled(); + } + + public static void haltMountedMotion(EntityNPCInterface npc, MountState state) { + double prevMotionX = npc.motionX; + double prevMotionY = npc.motionY; + double prevMotionZ = npc.motionZ; + npc.motionX = 0.0D; + npc.motionY = 0.0D; + npc.motionZ = 0.0D; + npc.isAirBorne = false; + npc.setSprinting(false); + npc.moveForward = 0.0F; + npc.moveStrafing = 0.0F; + npc.setAIMoveSpeed(0.0F); + npc.limbSwingAmount = 0.0F; + npc.limbSwing = 0.0F; + npc.getNavigator().clearPathEntity(); + npc.fallDistance = 0.0F; + if (!npc.worldObj.isRemote && (Math.abs(prevMotionX) > 1.0E-4D || Math.abs(prevMotionY) > 1.0E-4D || Math.abs(prevMotionZ) > 1.0E-4D)) { + npc.velocityChanged = true; + } + resetMountedFlightState(npc, state); + } + + public static void applyUnriddenFlightDescent(EntityNPCInterface npc, MountState state, RoleMount mount) { + if (mount == null || !mount.isFlyingMountEnabled()) { + npc.setNpcFlyingState(false); + npc.setNpcJumpingState(false); + return; + } + if (npc.canFly()) { + return; + } + if (npc.onGround) { + npc.motionY = 0.0D; + npc.setNpcFlyingState(false); + npc.setNpcJumpingState(false); + return; + } + + double descendSpeed = MathHelper.clamp_double(mount.getFlyingDescendSpeed(), 0.05D, 3.0D); + if (descendSpeed <= 0.0D) { + npc.setNpcFlyingState(false); + npc.setNpcJumpingState(false); + return; + } + + double desired = -descendSpeed; + double previousMotionY = npc.motionY; + npc.motionY = desired; + npc.isAirBorne = true; + npc.fallDistance = 0.0F; + npc.setNpcFlyingState(true); + npc.setNpcJumpingState(false); + if (!npc.worldObj.isRemote && Math.abs(previousMotionY - desired) > 1.0E-4D) { + npc.velocityChanged = true; + } + } + + public static void stabilizeDismountedRider(Entity rider) { + boolean wasOnGround = rider.onGround; + double previousMotionX = rider.motionX; + double previousMotionY = rider.motionY; + double previousMotionZ = rider.motionZ; + float previousFall = rider.fallDistance; + + if (wasOnGround) { + rider.motionX = 0.0D; + rider.motionY = 0.0D; + rider.motionZ = 0.0D; + rider.fallDistance = 0.0F; + rider.onGround = true; + } else { + rider.motionX = previousMotionX; + rider.motionY = previousMotionY; + rider.motionZ = previousMotionZ; + rider.fallDistance = previousFall; + } + + rider.velocityChanged = true; + } + + private static void updateMountedFlightState(EntityNPCInterface npc, MountState state, RoleMount mount, EntityPlayer rider) { + if (mount == null || rider == null || !mount.isFlyingMountEnabled()) { + resetMountedFlightState(npc, state); + return; + } + + if (npc.onGround) { + state.flightMode = false; + } + + boolean jumpPressed = rider.isJumping; + if (jumpPressed && !state.jumpPressed) { + if (state.flightToggleTimer > 0) { + state.flightMode = !state.flightMode; + state.flightToggleTimer = 0; + } else { + state.flightToggleTimer = MOUNT_FLIGHT_TOGGLE_WINDOW; + } + } + + if (state.flightToggleTimer > 0) { + state.flightToggleTimer--; + } + + state.jumpPressed = jumpPressed; + } + + public static boolean isMountInFlightMode(MountState state) { + return state.flightMode; + } + + public static void resetMountedFlightState(EntityNPCInterface npc, MountState state) { + state.flightMode = false; + state.jumpPressed = false; + state.flightToggleTimer = 0; + npc.setNpcFlyingState(false); + npc.setNpcJumpingState(false); + } + + private static boolean isSpecialKeyDown(EntityPlayer rider) { + if (rider == null) { + return false; + } + if (rider.worldObj.isRemote) { + PlayerData data = CustomNpcs.proxy.getPlayerData(rider); + return data != null && data.isSpecialKeyDown(); + } + PlayerData data = PlayerDataController.Instance.getPlayerData(rider); + return data != null && data.isSpecialKeyDown(); + } +} diff --git a/src/main/resources/META-INF/customnpcs_at.cfg b/src/main/resources/META-INF/customnpcs_at.cfg index 990efc151..dbcb46481 100644 --- a/src/main/resources/META-INF/customnpcs_at.cfg +++ b/src/main/resources/META-INF/customnpcs_at.cfg @@ -17,7 +17,10 @@ public net.minecraft.client.renderer.ItemRenderer field_78453_b # itemToRender public net.minecraft.client.renderer.entity.RenderPlayer func_77043_a(Lnet/minecraft/entity/EntityLivingBase;FFF)V # rotateCorpse #EntityLivingBase public net.minecraft.entity.EntityLivingBase func_82166_i()I # getArmSwingAnimationEnd +public net.minecraft.entity.EntityLivingBase field_70703_bu # isJumping # Minecraft public net.minecraft.client.Minecraft field_147126_aw # mcMusicTicker # MusicTicker public net.minecraft.client.audio.MusicTicker field_147676_d # timeUntilNextMusic +#GuiScreen +public net.minecraft.client.gui.GuiScreen field_146290_a # selectedButton diff --git a/src/main/resources/assets/customnpcs/lang/cs_CZ.lang b/src/main/resources/assets/customnpcs/lang/cs_CZ.lang index f8f092bbf..c45e3dade 100644 --- a/src/main/resources/assets/customnpcs/lang/cs_CZ.lang +++ b/src/main/resources/assets/customnpcs/lang/cs_CZ.lang @@ -439,3 +439,12 @@ item.npcOfficerHelmet.name=důstojnické brnění item.npcCrown.name=Koruna item.npcCrown2.name=Koruna key.npcInventory=NPC inventář +role.mount=Mount +role.mount.offsetx=Seat X +role.mount.offsety=Seat Y +role.mount.offsetz=Seat Z +role.mount.jumpheight=Jump +role.mount.sprint=Sprint +role.mount.reset=Reset Position +role.mount.walkspeed=Walk Speed: %s +key.customnpcs.special=Special Key diff --git a/src/main/resources/assets/customnpcs/lang/de_DE.lang b/src/main/resources/assets/customnpcs/lang/de_DE.lang index f88dd2769..32170875b 100644 --- a/src/main/resources/assets/customnpcs/lang/de_DE.lang +++ b/src/main/resources/assets/customnpcs/lang/de_DE.lang @@ -871,3 +871,12 @@ companion.stage=Bühne #German by DewTix key.npcInventory=NPC Inventar +role.mount=Mount +role.mount.offsetx=Seat X +role.mount.offsety=Seat Y +role.mount.offsetz=Seat Z +role.mount.jumpheight=Jump +role.mount.sprint=Sprint +role.mount.reset=Reset Position +role.mount.walkspeed=Walk Speed: %s +key.customnpcs.special=Special Key diff --git a/src/main/resources/assets/customnpcs/lang/en_US.lang b/src/main/resources/assets/customnpcs/lang/en_US.lang index 57dc34cdc..466acfb99 100644 --- a/src/main/resources/assets/customnpcs/lang/en_US.lang +++ b/src/main/resources/assets/customnpcs/lang/en_US.lang @@ -1,6 +1,7 @@ customnpcs.defaultTextColor=404040 key.categories.customnpc=CustomNPC+ +key.customnpcs.special=Special Key key.npcInventory=NPC Inventory entity.CustomNpc.name=Custom Npc @@ -417,6 +418,17 @@ role.transporter=Transporter role.mailman=Mailman role.marketname=Linked Marketname role.companion=Companion +role.mount=Mount +role.mount.offsetx=Seat X +role.mount.offsety=Seat Y +role.mount.offsetz=Seat Z +role.mount.jumpheight=Jump +role.mount.sprint=Sprint +role.mount.fly=Flying +role.mount.hover=Hover +role.mount.ascendspeed=Ascend Speed +role.mount.descendspeed=Descend Speed +role.mount.walkspeed=Walk Speed: %s trader.insufficient=Insufficient Currency trader.sufficient=Sufficient Currency diff --git a/src/main/resources/assets/customnpcs/lang/es_AR.lang b/src/main/resources/assets/customnpcs/lang/es_AR.lang index 27c79cd78..03e80082e 100644 --- a/src/main/resources/assets/customnpcs/lang/es_AR.lang +++ b/src/main/resources/assets/customnpcs/lang/es_AR.lang @@ -499,3 +499,12 @@ item.npcSlingshot.name=Slingshot item.npcMusket.name=Mosquete item.npcExcalibur.name=Excalibur key.npcInventory=Inventario de NPC +role.mount=Mount +role.mount.offsetx=Seat X +role.mount.offsety=Seat Y +role.mount.offsetz=Seat Z +role.mount.jumpheight=Jump +role.mount.sprint=Sprint +role.mount.reset=Reset Position +role.mount.walkspeed=Walk Speed: %s +key.customnpcs.special=Special Key diff --git a/src/main/resources/assets/customnpcs/lang/es_MX.lang b/src/main/resources/assets/customnpcs/lang/es_MX.lang index 53bca03af..7ea1b25b2 100644 --- a/src/main/resources/assets/customnpcs/lang/es_MX.lang +++ b/src/main/resources/assets/customnpcs/lang/es_MX.lang @@ -499,3 +499,12 @@ item.npcSlingshot.name=Slingshot item.npcMusket.name=Mosquete item.npcExcalibur.name=Excalibur key.npcInventory=Inventario de NPC +role.mount=Mount +role.mount.offsetx=Seat X +role.mount.offsety=Seat Y +role.mount.offsetz=Seat Z +role.mount.jumpheight=Jump +role.mount.sprint=Sprint +role.mount.reset=Reset Position +role.mount.walkspeed=Walk Speed: %s +key.customnpcs.special=Special Key diff --git a/src/main/resources/assets/customnpcs/lang/fr_FR.lang b/src/main/resources/assets/customnpcs/lang/fr_FR.lang index b22a75ac3..cea83f824 100644 --- a/src/main/resources/assets/customnpcs/lang/fr_FR.lang +++ b/src/main/resources/assets/customnpcs/lang/fr_FR.lang @@ -541,3 +541,12 @@ item.npcSlingshot.name=Lance-Pièrre item.npcMusket.name=Mousquet item.npcExcalibur.name=Excalibur key.npcInventory=Inventaire Pnj +role.mount=Mount +role.mount.offsetx=Seat X +role.mount.offsety=Seat Y +role.mount.offsetz=Seat Z +role.mount.jumpheight=Jump +role.mount.sprint=Sprint +role.mount.reset=Reset Position +role.mount.walkspeed=Walk Speed: %s +key.customnpcs.special=Special Key diff --git a/src/main/resources/assets/customnpcs/lang/hu_HU.lang b/src/main/resources/assets/customnpcs/lang/hu_HU.lang index 1a9fc71f5..db2fc6c38 100644 --- a/src/main/resources/assets/customnpcs/lang/hu_HU.lang +++ b/src/main/resources/assets/customnpcs/lang/hu_HU.lang @@ -541,3 +541,12 @@ item.npcSlingshot.name=Csúzli item.npcMusket.name=Muskéta item.npcExcalibur.name=Excalibur key.npcInventory=NPC felszerelés +role.mount=Mount +role.mount.offsetx=Seat X +role.mount.offsety=Seat Y +role.mount.offsetz=Seat Z +role.mount.jumpheight=Jump +role.mount.sprint=Sprint +role.mount.reset=Reset Position +role.mount.walkspeed=Walk Speed: %s +key.customnpcs.special=Special Key diff --git a/src/main/resources/assets/customnpcs/lang/id_ID.lang b/src/main/resources/assets/customnpcs/lang/id_ID.lang index a5952d7ab..025320030 100644 --- a/src/main/resources/assets/customnpcs/lang/id_ID.lang +++ b/src/main/resources/assets/customnpcs/lang/id_ID.lang @@ -316,3 +316,12 @@ item.npcAmethyst.name=Permata Amethyst item.npcRuby.name=Permata Rubi +role.mount=Mount +role.mount.offsetx=Seat X +role.mount.offsety=Seat Y +role.mount.offsetz=Seat Z +role.mount.jumpheight=Jump +role.mount.sprint=Sprint +role.mount.reset=Reset Position +role.mount.walkspeed=Walk Speed: %s +key.customnpcs.special=Special Key diff --git a/src/main/resources/assets/customnpcs/lang/ko_KR.lang b/src/main/resources/assets/customnpcs/lang/ko_KR.lang index 993006c34..e3a672289 100644 --- a/src/main/resources/assets/customnpcs/lang/ko_KR.lang +++ b/src/main/resources/assets/customnpcs/lang/ko_KR.lang @@ -796,3 +796,12 @@ enchantment.infinite=무한 enchantment.poison=독 key.npcInventory=NPC 인벤토리 +role.mount=Mount +role.mount.offsetx=Seat X +role.mount.offsety=Seat Y +role.mount.offsetz=Seat Z +role.mount.jumpheight=Jump +role.mount.sprint=Sprint +role.mount.reset=Reset Position +role.mount.walkspeed=Walk Speed: %s +key.customnpcs.special=Special Key diff --git a/src/main/resources/assets/customnpcs/lang/nl_NL.lang b/src/main/resources/assets/customnpcs/lang/nl_NL.lang index 6756f197f..297cfa1fc 100644 --- a/src/main/resources/assets/customnpcs/lang/nl_NL.lang +++ b/src/main/resources/assets/customnpcs/lang/nl_NL.lang @@ -230,4 +230,13 @@ item.npcCrown2.name=Kroon item.npcNinjaHead.name=Ninja Helm item.npcNinjaChest.name=Ninja Borst -item.npcNinjaPants.name=Ninja Broek \ No newline at end of file +item.npcNinjaPants.name=Ninja Broek +role.mount=Mount +role.mount.offsetx=Seat X +role.mount.offsety=Seat Y +role.mount.offsetz=Seat Z +role.mount.jumpheight=Jump +role.mount.sprint=Sprint +role.mount.reset=Reset Position +role.mount.walkspeed=Walk Speed: %s +key.customnpcs.special=Special Key diff --git a/src/main/resources/assets/customnpcs/lang/pl_PL.lang b/src/main/resources/assets/customnpcs/lang/pl_PL.lang index 2f1047663..e84de64ee 100644 --- a/src/main/resources/assets/customnpcs/lang/pl_PL.lang +++ b/src/main/resources/assets/customnpcs/lang/pl_PL.lang @@ -497,3 +497,12 @@ item.npcSlingshot.name=Proca item.npcMusket.name=Muszkiet item.npcExcalibur.name=Excalibur key.npcInventory=Inwentarz npc +role.mount=Mount +role.mount.offsetx=Seat X +role.mount.offsety=Seat Y +role.mount.offsetz=Seat Z +role.mount.jumpheight=Jump +role.mount.sprint=Sprint +role.mount.reset=Reset Position +role.mount.walkspeed=Walk Speed: %s +key.customnpcs.special=Special Key diff --git a/src/main/resources/assets/customnpcs/lang/pt_BR.lang b/src/main/resources/assets/customnpcs/lang/pt_BR.lang index c3bbd3c26..6d07b2df0 100644 --- a/src/main/resources/assets/customnpcs/lang/pt_BR.lang +++ b/src/main/resources/assets/customnpcs/lang/pt_BR.lang @@ -497,3 +497,12 @@ item.npcSlingshot.name=Estilingue item.npcMusket.name=Mosquete item.npcExcalibur.name=Excalibur key.npcInventory=Inventário NPC +role.mount=Mount +role.mount.offsetx=Seat X +role.mount.offsety=Seat Y +role.mount.offsetz=Seat Z +role.mount.jumpheight=Jump +role.mount.sprint=Sprint +role.mount.reset=Reset Position +role.mount.walkspeed=Walk Speed: %s +key.customnpcs.special=Special Key diff --git a/src/main/resources/assets/customnpcs/lang/ru_RU.lang b/src/main/resources/assets/customnpcs/lang/ru_RU.lang index 0b286b3ae..2c6f76422 100644 --- a/src/main/resources/assets/customnpcs/lang/ru_RU.lang +++ b/src/main/resources/assets/customnpcs/lang/ru_RU.lang @@ -1020,3 +1020,12 @@ questgui.reject=Отменить questgui.accept=Принять key.npcInventory=Инвентарь NPC +role.mount=Mount +role.mount.offsetx=Seat X +role.mount.offsety=Seat Y +role.mount.offsetz=Seat Z +role.mount.jumpheight=Jump +role.mount.sprint=Sprint +role.mount.reset=Reset Position +role.mount.walkspeed=Walk Speed: %s +key.customnpcs.special=Special Key diff --git a/src/main/resources/assets/customnpcs/lang/sv_SE.lang b/src/main/resources/assets/customnpcs/lang/sv_SE.lang index 91be6d6bc..7e536400b 100644 --- a/src/main/resources/assets/customnpcs/lang/sv_SE.lang +++ b/src/main/resources/assets/customnpcs/lang/sv_SE.lang @@ -307,3 +307,12 @@ item.npcKey.name=Key item.npcPendant.name=Pendant item.npcBlueprint.name=Blueprint item.npcRing.name=Ring +role.mount=Mount +role.mount.offsetx=Seat X +role.mount.offsety=Seat Y +role.mount.offsetz=Seat Z +role.mount.jumpheight=Jump +role.mount.sprint=Sprint +role.mount.reset=Reset Position +role.mount.walkspeed=Walk Speed: %s +key.customnpcs.special=Special Key diff --git a/src/main/resources/assets/customnpcs/lang/zh_CN.lang b/src/main/resources/assets/customnpcs/lang/zh_CN.lang index 7831cf590..32105c7db 100644 --- a/src/main/resources/assets/customnpcs/lang/zh_CN.lang +++ b/src/main/resources/assets/customnpcs/lang/zh_CN.lang @@ -1243,3 +1243,12 @@ hitbox.width=宽度比例 hitbox.height=身高比例 key.npcInventory=NPC物品栏 +role.mount=Mount +role.mount.offsetx=Seat X +role.mount.offsety=Seat Y +role.mount.offsetz=Seat Z +role.mount.jumpheight=Jump +role.mount.sprint=Sprint +role.mount.reset=Reset Position +role.mount.walkspeed=Walk Speed: %s +key.customnpcs.special=Special Key diff --git a/src/main/resources/assets/customnpcs/lang/zh_TW.lang b/src/main/resources/assets/customnpcs/lang/zh_TW.lang index 168709725..b7f2c04f5 100644 --- a/src/main/resources/assets/customnpcs/lang/zh_TW.lang +++ b/src/main/resources/assets/customnpcs/lang/zh_TW.lang @@ -313,3 +313,12 @@ item.npcBronzeIngot.name=銅錠 item.npcSaphire.name=藍寶石 item.npcAmethyst.name=紫水晶 item.npcRuby.name=紅寶石 +role.mount=Mount +role.mount.offsetx=Seat X +role.mount.offsety=Seat Y +role.mount.offsetz=Seat Z +role.mount.jumpheight=Jump +role.mount.sprint=Sprint +role.mount.reset=Reset Position +role.mount.walkspeed=Walk Speed: %s +key.customnpcs.special=Special Key