diff --git a/README.md b/README.md
index 001657d95..979cd2373 100644
--- a/README.md
+++ b/README.md
@@ -1,95 +1,432 @@
+
-## 👋 Welcome to the CustomNPC+ Repository.
-
+# CustomNPC+
-> CustomNPC+ is a [Minecraft](https://minecraft.net/) mod that allows you to add custom NPCs to your world. It is developed for creative and storytelling players who want to make their Minecraft worlds more in-depth and unique. CustomNPC+ is only a branch version of the **1.7.10** Forge version of the original (down below) and has no plans to add or update any other version. This is not an official version of CustomNPC.
+**CustomNPC+** is a Minecraft 1.7.10 Forge mod that lets you create fully customizable NPCs with advanced AI, combat abilities, quests, dialogs, scripting, an economy system, and much more. Built for creative and storytelling players who want to transform their worlds into living RPG experiences.
-----------------
+> CustomNPC+ is a branch version of the original [CustomNPC](https://www.curseforge.com/minecraft/mc-mods/custom-npcs) by [Noppes](https://github.com/Noppes), developed with permission. This is not an official version of CustomNPC.
-
-
+---
+
+
[](https://modrinth.com/mod/customnpc-plus)
[](https://www.curseforge.com/minecraft/mc-mods/moreplayermodels-plus)
[](https://github.com/KAMKEEL/Plugin-Mod)
-----------------
+---
-### ❗ Notice
-I am not the original creator of CustomNPC. The original creator is @[Noppes](https://github.com/Noppes). I have been permitted to update and develop my own branch version for 1.7.10. The original mod that is updated to the latest versions of Minecraft can be found on these links: [CurseForge](https://www.curseforge.com/minecraft/mc-mods/custom-npcs), [kodevelopment](http://www.kodevelopment.nl/minecraft/customnpcs)
+## Installation
-### ⬇️ Downloads
+CustomNPC+ is a **replacement** for the original CustomNPC — not an add-on. Do not install both together. Simply drop CustomNPC+ into your client or server mods folder. All original CustomNPC features are preserved and expanded upon.
+
+> Please **backup your world** before installing. Report any bugs on the [issue tracker](https://github.com/KAMKEEL/CustomNPC-Plus/issues).
+
+### Downloads
- **Modrinth**: [Download](https://modrinth.com/mod/customnpc-plus)
- **CurseForge**: [Download](https://www.curseforge.com/minecraft/mc-mods/customnpc-plus)
-### 🔹 Installation
-This mod is an ***update*** to CustomNPC and not an add-on. Do not install CustomNPC with CustomNPC-Plus. CustomNPC-Plus does not remove any functional features from the original mod. It expands upon CustomNPC with original features and backported features from newer versions. Simply drag CustomNPC-Plus into any client/server mods folder to utilize. Please **backup** before using as this could still have unforeseen errors. Report any bugs if found, thank you and enjoy.
+---
-### ❓ Features:
-- Flying NPC (Smart Pathfinding)
-- 1.8 Skin Support (64x64) (Alex/Steve64)
-- Full URL64 Selector (Downloads FULL Size Images for Custom Mob Skins)
-- Additional Parts: [Wings, Fins, Capes, Horns, Tail]
-- Hide Body Parts [Arms, Legs, Head, Body]
-- Custom Overlays
-- Animation Maker
-- Enhanced Cloner GUI (More Tabs, Filters, Tags)
-- Markov Name Generator
-- Dark Mode GUI (Link Below)
-- 1.12 Scripting Features (Details below)
-- Profile System (Multiple Character Slots)
-- Quest Party System
-- Item and Armor Attributes
-- Magic System with Elemental Cycles
-- Custom Effect Engine
-- Scripted Blocks & Particles
-- Compass Marks for Waypoints
-- Custom Model Support
-- Gecko & Dragon Block C Addons
+
-#### Scripting:
-- CustomNPC+ Api: [API](https://github.com/KAMKEEL/CustomNPC-Plus-API)
-- Java Doc: [kamkeel.github.io/CustomNPC-Plus](https://kamkeel.github.io/CustomNPC-Plus/)
-- Scripted Items
-- Player Overlays
-- Script Timers
-- Global Scripts
-- Script Logging
-- GUI Overlays
-- Event Scripting
-(We never remove script functionality, only add on existing functions)
+> More betas with new features will continue to be released to supporters for **Early Access** to new content!
-## 🔰 Skin Model Feature:
-###### **Majority of these cape designs are taken from the internet with fair-usage.*
-##### ❔ Please note all *local* skins in this version of CustomNPC, must match the model selected.
-
+---
+
+## Feature Overview
+
+### NPC Creation & Customization
+
+Create NPCs with deep visual customization and lifelike behavior.
+
+
+
+- **Skin System** - 1.8 skin support (64x64), Alex & Steve64 models, full URL64 selector that downloads full-size images for custom skins
+- **Body Parts** - Wings, fins, capes, horns, tails. Hide individual body parts (arms, legs, head, body)
+- **Skin Overlays** - Layer additional textures on top of the base skin with color tinting and alpha control
+- **Custom Models** - Support for custom model formats, plus Gecko and DBC addon model integration
+- **Hitbox Scaling** - Independently scale NPC hitbox width and height
+- **Tint System** - Control hurt flash color and apply persistent color tints
+
+---
+
+### NPC AI & Behavior
+
+NPCs have a full AI system for combat, pathing, and interaction.
+
+- **Flying NPCs** - Smart pathfinding in 3D space for flying entities
+- **Combat AI** - Multiple tactical behaviors: attack, ranged attack, ambush, pounce, dodge-shoot, zigzag, stalk, orbit, sprint-to-target, and leap attacks
+- **Movement Types** - Standing, wandering, and moving path modes
+- **Pathfinding** - Ground, flying, and water navigation
+- **Door Interaction** - NPCs can break, open, or ignore doors
+- **Behavior Controls** - Configurable sprinting, swimming, fire reactions, tactical chance, and walking range
+- **Attack Speed** - NPCs respect attack speed timing when dealing damage
+- **Faction Awareness** - NPCs respond to faction standings. Passive faction NPCs are protected from damage
-#### Flying NPCs:
-#### Url64:
-
+---
-#### DarkMode + Cloner GUI:
-
+### NPC Roles & Jobs
-## 🔗 Want to check out my other projects?
-[Plugin Mod](https://github.com/KAMKEEL/Plugin-Mod) is a mod designed to add more aesthetic items for RPG and storytelling. It is compatible with CustomNPC+ and has many items intended to be used and wielded by created NPCs.
+**Roles** give NPCs interactive functions — Trader, Follower, Bank, Transporter, Postman, Companion, Mount, and Auctioneer. **Jobs** give NPCs background tasks — Bard, Healer, Guard, Item Giver, Follower, Spawner, Conversation, and Chunk Loader.
-[RPG Messenger](https://github.com/KAMKEEL/RPGMessenger) is a bukkit plugin designed to allow operators to create messagable NPCs for RPG Servers. Allows a 'RPG Controller' to reply quickly as NPCs, form groupchats, and messagable parties.
+---
-[CustomNPC+ Dark Mode](https://github.com/KAMKEEL/CustomNPC-Plus-Dark-Mode) is a resource pack for CustomNPC+ that alters all GUIs within the mod to a dark variant that is both clean and pleasing to look at.
+### Dialog System
-## Cloning / Compiling / Building
+Create branching dialog trees for storytelling and player interaction.
-git clone call `git submodule update --init --recursive`
+
-Using IntelliJ, take the following steps:
-1. Run `setupDecompWorkspace` under the `forgegradle` tab.
-2. Refresh Gradle.
-3. Run `genIntellijRuns` under the `other` tab to set up your Minecraft runs.
+- **Dialog Trees** - Multi-level branching conversations with unlimited depth
+- **Dialog Options** - Player choices that affect outcomes, trigger quests, or change faction standings
+- **Dialog Images** - Display images alongside dialog text
+- **Dialog Colors** - Customizable text and background colors
+- **Categories** - Organize dialogs into categories for large projects
+- **Availability Conditions** - Show or hide dialogs based on quests, factions, items, or custom conditions
+- **Script Hooks** - Full scripting support for dialog open, close, and option events
-or for Eclipse, run `gradlew setupDecompWorkspace eclipse` then import the project.
+---
-Mixin code will not work if you do not add `--tweakClass org.spongepowered.asm.launch.MixinTweaker --mixin customnpcs.mixins.json` to your program arguments.
+### Quest System
+
+A complete quest framework for RPG progression.
+
+
+
+- **Quest Types** - Item collection, dialog completion, kill targets, reach locations, area kills, and fully manual (script-driven) quests
+- **Quest Tracking** - On-screen HUD overlay showing active quest objectives
+- **Categories** - Organize quests into categories
+- **Rewards** - Configure item, XP, and currency rewards
+- **Cooldowns** - Repeatable quests with MC time, real-time, or custom cooldown intervals
+- **Party Quests** - Share quest objectives across party members with configurable sharing modes
+- **Availability** - Control quest visibility based on completed quests, faction standing, dialogs, and more
+- **Script Hooks** - Events for quest start, completion, turn-in, and custom quest objectives
+
+---
+
+### Ability System
+
+A full combat ability system for both NPCs and players.
+
+
+
+
+**Melee Abilities** - Slam, Heavy Hit, Cutter
+**Energy Projectiles** - Orbs, Discs, Beams, Laser Shots with full visual customization, homing, and hit types
+**Energy Barriers** - Domes, Walls, Shields with HP, reflection, and damage absorption
+**Defensive** - Guard, Counter, Dodge with configurable damage reduction and counter-attacks
+**Movement** - Charge, Dash, Teleport
+**AOE** - Shockwave, Sweeper, Vortex
+**Hazards & Traps** - Persistent damage zones and proximity-triggered traps with visual presets
+**Support** - Ability Effect for healing, buffs, and debuffs
+
+**Key Features:**
+- Phase-based execution (Wind-up, Active, Dazed) with visual telegraphs
+- Burst system for rapid multi-fire
+- Chained abilities for sequential combos
+- Player ability hotbar (12 slots) with unlock system
+- Full scripting API for every lifecycle event
+- Live preview in the ability editor
+
+---
+
+### Auction House & Economy
+
+A complete marketplace and economy system.
+
+
+
+- **Built-in Currency** - Configurable currency with starting balance, max cap, and Vault plugin integration
+- **Auction House** - Global player marketplace with bidding, buyout, snipe protection, and notifications
+- **Trade Slots** - Configurable per-player slot limits via permissions
+- **Item Blacklist** - Block items by name, wildcard, mod, or NBT tag from being listed
+- **Admin Tools** - Dedicated admin GUI for managing listings and creating server auctions
+- **Scripting API** - Cancelable events for creates, bids, buyouts, cancels, and claims
+
+**Trader Enhancements:**
+- Limited stock with automatic restocking (MC time, real-time, or custom intervals)
+- Global or per-player stock modes
+- Currency costs on top of item trades
+- Client-side balance preview
+
+---
+
+### Script Editor
+
+A full-featured code editor built right into Minecraft.
+
+
+
+- **Syntax Highlighting** - Color-coded keywords, types, variables, methods, strings, and comments
+- **Autocomplete** - Smart suggestions with type awareness, static vs instance context, and auto-imports
+- **Error Detection** - Real-time underlining of wrong argument types, missing methods, type mismatches, and unused imports
+- **Hover Info** - Full type information, documentation, and JSDoc rendering on hover
+- **Navigation** - Go to line, search & replace, go to definition, and fullscreen mode
+- **Editing** - Smart undo/redo, duplicate lines, comment toggle, rename refactoring, smart bracket pairing
+- **Visual** - Line numbers, smooth scrolling, indent guides, brace matching, resizable panels
+
+---
+
+### Scripting
+
+Write scripts in **JavaScript** or **Java** to control every aspect of the mod.
+
+- **Java Scripting** - Write real Java code compiled by the Janino engine. Full support for classes, generics, lambdas, and method references
+- **JavaScript** - Full Nashorn-based JavaScript with ECMAScript 5.1 globals (Math, JSON, Date, Number)
+- **Client-Side Scripting** - Run scripts on the client for responsive visual experiences (server-controlled)
+- **154+ Script Hooks** - Events for NPCs, players, blocks, items, quests, dialogs, factions, abilities, auction, animations, and more
+- **Script Types** - NPC, Player, Global, Block, Item, Linked Item, Effect, Ability, Recipe, and Forge Event scripts
+- **Scripted Blocks** - Blocks with full script hooks for click, redstone, neighbor changes, and more
+- **Scripted Items** - Items with use, attack, toss, pickup, and durability hooks
+- **Custom GUIs** - Build custom interfaces with buttons, text fields, scroll panels, and slots via scripting
+- **GUI Overlays** - Persistent on-screen overlays with labels, lines, and textured rectangles
+- **Addon API** - Mods can ship `.d.ts` type definitions for full autocomplete in the editor
+
+**Resources:**
+- API Repository: [CustomNPC+ API](https://github.com/KAMKEEL/CustomNPC-Plus-API)
+- Java Docs: [kamkeel.github.io/CustomNPC-Plus](https://kamkeel.github.io/CustomNPC-Plus/)
+
+
+
+
+---
+
+### Animation System
+
+Create custom animations for NPCs directly in-game.
+
+- **Animation Maker** - Visual editor for creating frame-based animations
+- **Animation Parts** - Animate individual body parts with rotation, position, and scaling
+- **Frame Events** - Script hooks for animation start, end, frame enter, and frame exit
+- **Data Store** - Animations can store and pass data across events and frames
+- **Task System** - Consumer-based callbacks for animation lifecycle
+- **Built-in Animations** - Pre-made animations for abilities that work automatically
+- **Multiple Registrations** - Register multiple animations under one common name
+- **Animated Textures** - Frame-based animated textures for items, effects, and ability icons
+
+
+
+---
+
+### Custom Effects
+
+Create custom status effects beyond vanilla potions.
+
+- **Custom Icons** - Each effect gets its own texture, with support for animated icons
+- **Script Hooks** - Events for effect apply, tick, and removal
+- **Ability Integration** - Abilities can apply custom effects to targets
+- **Condition System** - Check if entities have specific effects for ability or availability conditions
+
+---
+
+### Profile System
+
+Multiple character slots on a single account.
+
+- **Profile Slots** - Each slot stores separate quest progress, dialogs, factions, currency, abilities, and effects
+- **Region Locking** - Lock profiles to specific areas
+- **Soulbound Items** - Bind items to a specific player by UUID
+- **Profile-Slotbound Items** - Bind items to a specific profile slot
+
+---
+
+### Party System
+
+Group up with other players for cooperative gameplay.
+
+- **Party Management** - Invite, kick, leave, disband, and transfer leadership
+- **Quest Sharing** - Share quest objectives across party members
+- **Ability Integration** - Party members are treated as allies for AOE ability targeting
+- **Script Hooks** - Events for invites, kicks, leaves, disbands, and quest completion
+
+
+
+
+---
+
+### Faction System
+
+Create factions to control NPC relationships and player reputation.
+
+- **Faction Points** - Players earn or lose standing with factions through quests, combat, and scripting
+- **Availability Conditions** - Gate dialogs, quests, and content behind faction thresholds
+- **NPC Behavior** - NPCs react to players based on faction standing (friendly, neutral, hostile)
+- **Passive Factions** - Passive faction NPCs are protected from damage
+
+---
+
+### HUD System
+
+Customizable on-screen elements.
+
+- **HUD Editor** - Drag and position HUD components to fit your screen
+- **Ability Hotbar** - 12-slot bar with horizontal/vertical layout and configurable visible slots
+- **Quest Tracking** - On-screen quest objective tracker
+- **Compass** - Directional compass with quest and waypoint markers
+- **Effect Bar** - Display active custom effects
+
+
+
+---
+
+### Cloner & Organization
+
+Save, organize, and reuse NPCs and content.
+
+- **Cloner Tabs** - Save and load NPCs, items, and other content
+- **Folder System** - Organize with folders and subfolders for animations, abilities, forms, auras, outlines, effects, and linked items
+- **Quick Tags** - Tag-based filtering for fast searching
+- **Full Screen Browser** - Wide directory view for large collections
+
+
+
+---
+
+### Items & Blocks
+
+A large library of custom items and decorative blocks.
+
+**Weapons:** Battle Axe, Broadsword, Claw, Crossbow, Dagger, Staff, Glaive, Gun, Kunai, Scythe, Spear, Wand, Warhammer, Musket, and more
+
+**Linked Items:** Create custom items with configurable attack speed, scripted behavior, animated textures, and item versioning
+
+**Blocks:** Banners, barrels, beams, signs, campfires, candles, chairs, couches, crates, crystals, lanterns, mailboxes, pedestals, redstone blocks, and scripted blocks
+
+**Crafting:** Carpentry Bench and Anvil with custom recipe support
+
+
+
+
+---
+
+### Custom Models
+
+Support for custom NPC models beyond the default humanoid. Import Blockbench models using the **Gecko Addon** (GeckoLib integration) or use **Armorer's Workshop** skins with the AW Addon.
+
+
+
+
+---
+
+### Addon Compatibility
+
+CustomNPC+ has official addons that extend its functionality with other mods. Vault and Pixelmon are also supported natively for economy and scripting integration.
+
+---
+
+## Official CNPC+ Addons
+
+### DBC Addon
+
+Adds full compatibility between [Dragon Block C](https://www.curseforge.com/minecraft/mc-mods/dragon-block-c) and CustomNPC+. Extends abilities with ki-based attacks, adds DBC stat integration to conditions, and enables DBC model/animation support on NPCs.
+
+[](https://www.curseforge.com/minecraft/mc-mods/cnpc-dbc-addon)
+[](https://modrinth.com/mod/customnpc-plus-dbc-addon)
+[](https://github.com/KAMKEEL/CustomNPC-DBC-Addon)
+
+### Gecko Addon
+
+Adds [GeckoLib](https://www.curseforge.com/minecraft/mc-mods/geckolib) support to CustomNPC+. Import Blockbench models directly into the mod and use them as custom NPC models with full animation support.
+
+[](https://www.curseforge.com/minecraft/mc-mods/cnpc-custom-model-addon)
+[](https://modrinth.com/mod/customnpc-plus-gecko-addon)
+[](https://github.com/KAMKEEL/CustomNPC-Gecko-Addon)
+
+### Armorer's Workshop Addon
+
+Adds compatibility between [Armorer's Workshop](https://www.curseforge.com/minecraft/mc-mods/armorers-workshop) and CustomNPC+. Use Armorer's Workshop skins and equipment on NPCs with custom rotation, scaling, and animation support. Requires UniMixins.
+
+[](https://www.curseforge.com/minecraft/mc-mods/cnpc-armorers-workshop-addon)
+[](https://modrinth.com/mod/customnpc-plus-aw-addon)
+
+---
+
+## Other Projects
+
+### MorePlayerModels+
+
+An updated continuation of MorePlayerModels for 1.7.10 with backported GUIs, original parts and customizations, and permission support. Works alongside CustomNPC+. This is a replacement — do not install alongside the original MorePlayerModels.
+
+[](https://www.curseforge.com/minecraft/mc-mods/moreplayermodels-plus)
+[](https://modrinth.com/mod/moreplayermodels+)
+[](https://github.com/KAMKEEL/MorePlayerModels-Plus)
+
+### The Plugin Mod
+
+Adds aesthetic weapons, artifacts, blocks, and apples for RPG and storytelling servers. Designed to pair with CustomNPC+ — use the included swords, spears, axes, medpacks, and decorative blocks to make your NPCs and worlds more diverse.
+
+[](https://www.curseforge.com/minecraft/mc-mods/the-plugin-mod)
+[](https://modrinth.com/mod/the-plugin-mod)
+[](https://github.com/KAMKEEL/Plugin-Mod)
+
+### HexText
+
+Upgrades Minecraft's font renderer with full RGB hex color support, nested color spans, and animated text effects (glow, shake, wave). Works in signs, anvils, and chat. Requires UniMixins.
+
+[](https://www.curseforge.com/minecraft/mc-mods/hex-text)
+[](https://modrinth.com/mod/hex-text)
+[](https://github.com/KAMKEEL/HexText)
+
+### RPG Messenger
+
+A Bukkit plugin for messageable NPCs, group chats, and RPG controller tools. Allows operators to create NPCs that players can message, and lets RPG controllers reply as NPCs in real-time.
+
+[](https://github.com/KAMKEEL/RPGMessenger)
+
+### CustomNPC+ Dark Mode
+
+A resource pack that applies a clean dark theme to all CustomNPC+ GUIs.
+
+[](https://github.com/KAMKEEL/CustomNPC-Plus-Dark-Mode)
+
+---
+
+## Configuration
+
+CustomNPC+ has a modular configuration system:
+
+| Config | Purpose |
+|--------|---------|
+| **Main** | Core mod settings |
+| **Client** | Client-side display and UI preferences |
+| **Script** | Scripting engine settings and client script toggle |
+| **Market** | Currency, auction house, trader, and economy settings |
+| **Energy** | Energy projectile settings (explosion block damage, dome item blacklist) |
+| **Item** | Item and gun configuration |
+| **Debug** | Debug logging and diagnostics |
+| **Experimental** | Experimental features toggle |
+
+---
+
+## Building from Source
+
+This project uses the [GTNH Gradle Convention](https://github.com/GTNewHorizons/ExampleMod1.7.10) build system with [RetroFuturaGradle](https://github.com/GTNewHorizons/RetroFuturaGradle).
+
+```bash
+git clone
+git submodule update --init --recursive
+./gradlew build
+```
+
+That's it. Submodules pull in the API sources, and `build` handles decompilation, compilation, and mixin embedding automatically.
+
+**Run the game:**
+```bash
+./gradlew runClient # Launch client
+./gradlew runServer # Launch server
+```
+
+**IDE Setup (IntelliJ):**
+1. Import the project as a Gradle project
+2. Run `./gradlew genIntellijRuns`
+3. Add program arguments: `--tweakClass org.spongepowered.asm.launch.MixinTweaker --mixin customnpcs.mixins.json`
+
+---
+
+## Notice
+
+I am not the original creator of CustomNPC. The original creator is [Noppes](https://github.com/Noppes). I have been permitted to update and develop my own branch version for 1.7.10. The original mod updated to the latest Minecraft versions can be found on [CurseForge](https://www.curseforge.com/minecraft/mc-mods/custom-npcs) and [kodevelopment](http://www.kodevelopment.nl/minecraft/customnpcs).
diff --git a/images/Animation Maker.png b/images/Animation Maker.png
deleted file mode 100644
index 2fa6f2bef..000000000
Binary files a/images/Animation Maker.png and /dev/null differ
diff --git a/images/AnimationMaker.gif b/images/AnimationMaker.gif
new file mode 100644
index 000000000..dcd917fca
Binary files /dev/null and b/images/AnimationMaker.gif differ
diff --git a/images/Auction.png b/images/Auction.png
new file mode 100644
index 000000000..c7794860c
Binary files /dev/null and b/images/Auction.png differ
diff --git a/images/ClonerGUI-DarkMode.png b/images/ClonerGUI-DarkMode.png
deleted file mode 100644
index 946f9dd8e..000000000
Binary files a/images/ClonerGUI-DarkMode.png and /dev/null differ
diff --git a/images/ClonerTabs.png b/images/ClonerTabs.png
new file mode 100644
index 000000000..f833ab6cd
Binary files /dev/null and b/images/ClonerTabs.png differ
diff --git a/images/Dialog.png b/images/Dialog.png
new file mode 100644
index 000000000..6671e96bb
Binary files /dev/null and b/images/Dialog.png differ
diff --git a/images/GUI.png b/images/GUI.png
deleted file mode 100644
index c75a95abf..000000000
Binary files a/images/GUI.png and /dev/null differ
diff --git a/images/GUIRevamp.png b/images/GUIRevamp.png
deleted file mode 100644
index c944da6ac..000000000
Binary files a/images/GUIRevamp.png and /dev/null differ
diff --git a/images/CustomModel1.png b/images/GeckoAddon1.png
similarity index 100%
rename from images/CustomModel1.png
rename to images/GeckoAddon1.png
diff --git a/images/CustomModel2.png b/images/GeckoAddon2.png
similarity index 100%
rename from images/CustomModel2.png
rename to images/GeckoAddon2.png
diff --git a/images/HudSystem.png b/images/HudSystem.png
new file mode 100644
index 000000000..cb6c063b1
Binary files /dev/null and b/images/HudSystem.png differ
diff --git a/images/NewTextures2.png b/images/JappaTextures.png
similarity index 100%
rename from images/NewTextures2.png
rename to images/JappaTextures.png
diff --git a/images/NPCAbilities.gif b/images/NPCAbilities.gif
new file mode 100644
index 000000000..fa13b8630
Binary files /dev/null and b/images/NPCAbilities.gif differ
diff --git a/images/NPCEditor.gif b/images/NPCEditor.gif
new file mode 100644
index 000000000..b6a24fbe4
Binary files /dev/null and b/images/NPCEditor.gif differ
diff --git a/images/Party System.png b/images/PartySystem.png
similarity index 100%
rename from images/Party System.png
rename to images/PartySystem.png
diff --git a/images/PlayerAbilities.gif b/images/PlayerAbilities.gif
new file mode 100644
index 000000000..819b2e870
Binary files /dev/null and b/images/PlayerAbilities.gif differ
diff --git a/images/Marks.png b/images/QuestMarks.png
similarity index 100%
rename from images/Marks.png
rename to images/QuestMarks.png
diff --git a/images/ScriptEditor.gif b/images/ScriptEditor.gif
new file mode 100644
index 000000000..bd3d365a9
Binary files /dev/null and b/images/ScriptEditor.gif differ
diff --git a/images/Url64Example.gif b/images/Url64Example.gif
deleted file mode 100644
index c2e7ffec2..000000000
Binary files a/images/Url64Example.gif and /dev/null differ
diff --git a/images/New Textures.png b/images/VariousWeapons.png
similarity index 100%
rename from images/New Textures.png
rename to images/VariousWeapons.png
diff --git a/images/guiAnimation.gif b/images/guiAnimation.gif
deleted file mode 100644
index 65f7e3fdb..000000000
Binary files a/images/guiAnimation.gif and /dev/null differ
diff --git a/images/showcase.gif b/images/showcase.gif
deleted file mode 100644
index 0d7272146..000000000
Binary files a/images/showcase.gif and /dev/null differ
diff --git a/images/skinAnimation.gif b/images/skinAnimation.gif
deleted file mode 100644
index 132adf09b..000000000
Binary files a/images/skinAnimation.gif and /dev/null differ
diff --git a/src/main/java/noppes/npcs/CustomNpcs.java b/src/main/java/noppes/npcs/CustomNpcs.java
index 5f020e507..810354152 100644
--- a/src/main/java/noppes/npcs/CustomNpcs.java
+++ b/src/main/java/noppes/npcs/CustomNpcs.java
@@ -67,6 +67,7 @@ import noppes.npcs.compat.PixelmonHelper;
import noppes.npcs.config.ConfigMain;
import noppes.npcs.config.LoadConfiguration;
import noppes.npcs.config.legacy.LegacyConfig;
+import noppes.npcs.controllers.APIRegistry;
import noppes.npcs.controllers.AnimationController;
import noppes.npcs.controllers.AuctionController;
import noppes.npcs.controllers.BankController;
@@ -316,6 +317,8 @@ public class CustomNpcs {
new AddonManager();
new AttributeController();
new MagicController();
+
+ APIRegistry.Instance.register("CNPC+ API", "https://kamkeel.github.io/CustomNPC-Plus/");
}
@EventHandler
diff --git a/src/main/java/noppes/npcs/client/gui/GuiScript.java b/src/main/java/noppes/npcs/client/gui/GuiScript.java
index b8309b955..96a7efab1 100644
--- a/src/main/java/noppes/npcs/client/gui/GuiScript.java
+++ b/src/main/java/noppes/npcs/client/gui/GuiScript.java
@@ -2,13 +2,15 @@ package noppes.npcs.client.gui;
import kamkeel.npcs.network.packets.request.script.NPCScriptPacket;
import net.minecraft.client.gui.GuiButton;
-import net.minecraft.client.gui.GuiConfirmOpenLink;
import net.minecraft.client.gui.GuiYesNo;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.StatCollector;
import noppes.npcs.NoppesStringUtils;
import noppes.npcs.client.NoppesUtil;
+import noppes.npcs.client.gui.util.SubGuiAPISelect;
+import noppes.npcs.client.gui.util.SubGuiConfirmLink;
+import noppes.npcs.controllers.APIRegistry;
import noppes.npcs.client.gui.script.GuiScriptInterface;
import noppes.npcs.client.gui.util.GuiCustomScroll;
import noppes.npcs.client.gui.util.GuiMenuTopButton;
@@ -107,7 +109,7 @@ public class GuiScript extends GuiScriptInterface {
top.active = showScript;
addTopButton(top = new GuiMenuTopButton(14, top, "gui.settings"));
top.active = !showScript;
- addTopButton(new GuiMenuTopButton(15, top, "gui.website"));
+ addTopButton(new GuiMenuTopButton(15, top, "gui.api"));
if (showScript) {
initScriptView();
@@ -285,9 +287,6 @@ public class GuiScript extends GuiScriptInterface {
NoppesUtil.openGUI(player, this);
if (!result)
return;
- if (id == 0) {
- openLink("https://kamkeel.github.io/CustomNPC-Plus/");
- }
if (id == 101) {
getTextField(2).setText(NoppesStringUtils.getClipboardContents());
}
@@ -319,7 +318,12 @@ public class GuiScript extends GuiScriptInterface {
initGui();
}
if (guibutton.id == 15) {
- displayGuiScreen(new GuiConfirmOpenLink(this, "https://kamkeel.github.io/CustomNPC-Plus/", 0, true));
+ if (APIRegistry.Instance.size() == 1) {
+ String url = APIRegistry.Instance.getEntries().values().iterator().next();
+ setSubGui(new SubGuiConfirmLink(url));
+ } else {
+ setSubGui(new SubGuiAPISelect());
+ }
}
if (guibutton.id == 16) {
close();
diff --git a/src/main/java/noppes/npcs/client/gui/hud/GuiHudEditor.java b/src/main/java/noppes/npcs/client/gui/hud/GuiHudEditor.java
index d36727aad..5ffa2b50c 100644
--- a/src/main/java/noppes/npcs/client/gui/hud/GuiHudEditor.java
+++ b/src/main/java/noppes/npcs/client/gui/hud/GuiHudEditor.java
@@ -23,6 +23,7 @@ public class GuiHudEditor extends GuiScreen {
private final int HANDLE_SIZE = 10;
private final int RESET_POSITION_ID = 100;
+ private final int RESET_SIZE_ID = 104;
// IDs for cycle buttons.
private final int CYCLE_LEFT_ID = 101;
@@ -90,9 +91,11 @@ public class GuiHudEditor extends GuiScreen {
rowHeight += btn.height + spacingY;
}
}
- // Always add the Reset Position button below the custom buttons.
- GuiButton resetPos = new GuiButton(RESET_POSITION_ID, width / 2 - buttonWidth / 2, height - 70 - rowHeight, buttonWidth, 20, "Reset Position");
+ // Always add the Reset Position and Reset Size buttons below the custom buttons.
+ GuiButton resetSize = new GuiButton(RESET_SIZE_ID, startXRight, height - 70 - rowHeight, buttonWidth, 20, "Reset Size");
+ GuiButton resetPos = new GuiButton(RESET_POSITION_ID, startXLeft, height - 70 - rowHeight, buttonWidth, 20, "Reset Position");
buttonList.add(resetPos);
+ buttonList.add(resetSize);
}
// Now update (or add if missing) the cycle buttons at the very bottom.
@@ -149,10 +152,11 @@ public class GuiHudEditor extends GuiScreen {
int actualY = (int) (hud.posY / 100F * res.getScaledHeight());
int margin = 5;
int barWidth = 6; // same as WIDTH_BAR_SIZE
- int barX = actualX + (int) (hud.overlayWidth * effectiveScale) + margin;
+ int barX = actualX + (int) ((hud.overlayWidth + margin) * effectiveScale);
int barY = actualY + (int) (((hud.overlayHeight - 20) / 2.0F) * effectiveScale);
int barHeight = (int) (20 * effectiveScale);
- if (mouseX >= barX && mouseX <= barX + barWidth &&
+ int scaledBarWidth = Math.max(6, (int) (barWidth * effectiveScale));
+ if (mouseX >= barX && mouseX <= barX + scaledBarWidth &&
mouseY >= barY && mouseY <= barY + barHeight) {
resizingWidth = true;
selectedComponent = hud;
@@ -226,15 +230,22 @@ public class GuiHudEditor extends GuiScreen {
}
if (resizing) {
int currentMouseX = Mouse.getX() * width / mc.displayWidth;
- int deltaX = currentMouseX - initialMouseX;
- selectedComponent.scale = initialScale + deltaX;
+ int currentMouseY = scaledHeight - (Mouse.getY() * scaledHeight / mc.displayHeight);
+ int actualX = (int) (selectedComponent.posX / 100F * scaledWidth);
+ int actualY = (int) (selectedComponent.posY / 100F * scaledHeight);
+ // Use diagonal distance ratio so the resize handle tracks the mouse
+ float initDist = (float) Math.sqrt((double)(initialMouseX - actualX) * (initialMouseX - actualX) + (double)(initialMouseY - actualY) * (initialMouseY - actualY));
+ float currDist = (float) Math.sqrt((double)(currentMouseX - actualX) * (currentMouseX - actualX) + (double)(currentMouseY - actualY) * (currentMouseY - actualY));
+ if (initDist > 1) {
+ selectedComponent.scale = (int) (initialScale * currDist / initDist);
+ }
if (selectedComponent.scale < 50) selectedComponent.scale = 50;
- if (selectedComponent.scale > 300) selectedComponent.scale = 300;
+ if (selectedComponent.scale > 500) selectedComponent.scale = 500;
}
if (resizingWidth && (selectedComponent instanceof CompassHudComponent)) {
int currentMouseX = Mouse.getX() * width / mc.displayWidth;
int delta = currentMouseX - initialWidthMouseX;
- selectedComponent.overlayWidth = initialOverlayWidth + delta;
+ selectedComponent.overlayWidth = initialOverlayWidth + (int) (delta / effectiveScale);
if (selectedComponent.overlayWidth < 50) selectedComponent.overlayWidth = 50;
if (selectedComponent.overlayWidth > 500) selectedComponent.overlayWidth = 500;
}
@@ -267,6 +278,11 @@ public class GuiHudEditor extends GuiScreen {
selectedComponent.posY = 100F * centerY / res.getScaledHeight();
updateCustomButtons();
}
+ } else if (button.id == RESET_SIZE_ID) {
+ if (selectedComponent != null) {
+ selectedComponent.scale = 100;
+ updateCustomButtons();
+ }
} else if (button.id == CYCLE_LEFT_ID) {
cycleComponent(-1);
} else if (button.id == CYCLE_RIGHT_ID) {
diff --git a/src/main/java/noppes/npcs/client/gui/script/GuiJaninoScript.java b/src/main/java/noppes/npcs/client/gui/script/GuiJaninoScript.java
deleted file mode 100644
index 9fb601162..000000000
--- a/src/main/java/noppes/npcs/client/gui/script/GuiJaninoScript.java
+++ /dev/null
@@ -1,429 +0,0 @@
-package noppes.npcs.client.gui.script;
-
-
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.GuiButton;
-import net.minecraft.client.gui.GuiConfirmOpenLink;
-import net.minecraft.client.gui.GuiScreen;
-import net.minecraft.client.gui.GuiYesNo;
-import net.minecraft.client.gui.GuiYesNoCallback;
-import net.minecraft.util.StatCollector;
-import noppes.npcs.NoppesStringUtils;
-import noppes.npcs.client.gui.util.GuiCustomScroll;
-import noppes.npcs.client.gui.util.GuiMenuTopButton;
-import noppes.npcs.client.gui.util.GuiNPCInterface;
-import noppes.npcs.client.gui.util.GuiNpcButton;
-import noppes.npcs.client.gui.util.GuiNpcLabel;
-import noppes.npcs.client.gui.util.GuiNpcTextArea;
-import noppes.npcs.client.gui.util.GuiScriptTextArea;
-import noppes.npcs.client.gui.util.ICustomScrollListener;
-import noppes.npcs.client.gui.util.ISubGuiListener;
-import noppes.npcs.client.gui.util.ITextChangeListener;
-import noppes.npcs.client.gui.util.SubGuiInterface;
-import noppes.npcs.controllers.ScriptController;
-import noppes.npcs.janino.JaninoScript;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-public class GuiJaninoScript extends GuiNPCInterface implements GuiYesNoCallback, ITextChangeListener, ICustomScrollListener, ISubGuiListener {
-
- private GuiScriptTextArea textArea;
- private int activeTab = 0;
- public List allExternalScripts = new ArrayList<>();
- private final int scriptLimit = 1;
- public String previousHookClicked = "";
-
- // GUI display list
- List hooklist = new ArrayList<>();
-
- // Map from display name (with parameters if overloaded) to Method
- Map hookMap = new HashMap<>();
-
- public final GuiScreen parent;
- private final JaninoScript container;
-
- public Runnable saveFunction;
-
- public GuiJaninoScript(GuiScreen parent, JaninoScript handler) {
- this.drawDefaultBackground = true;
- this.closeOnEsc = true;
- this.xSize = 420;
- this.setBackground("menubg.png");
-
- this.parent = parent;
- this.container = handler;
-
- createHookList();
-
- String lang = handler.getLanguage();
- allExternalScripts.addAll(ScriptController.Instance.getScripts(lang));
- }
-
- public GuiJaninoScript setSave(Runnable run) {
- saveFunction = run;
- return this;
- }
-
- public void createHookList() {
- // Group all declared methods of the handler's type by their method name
- Map> grouped = Arrays.stream(container.type.getDeclaredMethods())
- .collect(Collectors.groupingBy(Method::getName));
-
- for (Map.Entry> entry : grouped.entrySet()) {
- List methods = entry.getValue();
-
- // Sort overloads by number of parameters (ascending)
- // This ensures the simplest overload comes first
- methods.sort(Comparator.comparingInt(Method::getParameterCount));
- boolean first = true;
-
-
- for (Method m : methods) {
- if (Modifier.isFinal(m.getModifiers()))
- continue; //skip finals
-
- String displayName = first ? m.getName() :
- m.getName() + "(" + Arrays.stream(m.getParameterTypes())
- .map(Class::getSimpleName)
- .collect(Collectors.joining(", ")) + ")";
-
-
- hooklist.add(displayName);
- hookMap.put(displayName, m);
- first = false;
- }
- }
- }
-
- public void initGui() {
- this.ySize = (int) ((double) this.xSize * 0.56);
- if ((double) this.ySize > (double) this.height * 0.95) {
- this.ySize = (int) ((double) this.height * 0.95);
- this.xSize = (int) ((double) this.ySize / 0.56);
- }
-
- this.bgScale = (float) this.xSize / 400.0F;
- super.initGui();
- this.guiTop += 10;
- int yoffset = (int) ((double) this.ySize * 0.02);
- GuiMenuTopButton top;
- addTopButton(new GuiMenuTopButton(-1, guiLeft + xSize - 2, guiTop - 17, "X"));
- this.addTopButton(top = new GuiMenuTopButton(0, this.guiLeft + 4, this.guiTop - 17, "gui.settings"));
- int topXoffset = 0;
- int topYoffset = 0;
-
-
- if (this.container != null) {
- this.addTopButton(top = new GuiMenuTopButton(1, top.xPosition + top.width + topXoffset, top.yPosition + topYoffset, "Script"));
- } else {
- this.addTopButton(new GuiMenuTopButton(this.scriptLimit, top.xPosition + top.width, top.yPosition, "+"));
- }
-
- top = this.getTopButton(this.activeTab);
- if (top == null) {
- this.activeTab = 0;
- top = this.getTopButton(0);
- }
-
- top.active = true;
- if (this.activeTab == 1) {
- GuiCustomScroll hooks = new GuiCustomScroll(this, 1);
- hooks.allowUserInput = false;
- hooks.setSize(108, 198);
- hooks.guiLeft = this.guiLeft - 110;
- hooks.guiTop = this.guiTop + 14;
-
- hooks.setUnsortedList(this.hooklist);
- this.addScroll(hooks);
- GuiNpcLabel hookLabel = new GuiNpcLabel(0, "script.hooks", hooks.guiLeft, this.guiTop + 5);
- hookLabel.color = 11184810;
- this.addLabel(hookLabel);
- JaninoScript container = this.container;
- if (textArea == null)
- textArea = new GuiScriptTextArea(this, 2, this.guiLeft + 1 + yoffset, this.guiTop + yoffset, this.xSize - 108 - yoffset, (int) ((double) this.ySize * 0.96) - yoffset * 2, container == null ? "" : container.script);
- else
- textArea.init(this.guiLeft + 1 + yoffset, this.guiTop + yoffset, this.xSize - 108 - yoffset, (int) ((double) this.ySize * 0.96) - yoffset * 2, container == null ? "" : container.script);
- textArea.enableCodeHighlighting();
- textArea.setListener(this);
- this.closeOnEsc(textArea::closeOnEsc);
- this.addTextField(textArea);
-
- int left1 = this.guiLeft + this.xSize - 104;
- this.addButton(new GuiNpcButton(102, left1, this.guiTop + yoffset, 60, 20, "gui.clear"));
- this.addButton(new GuiNpcButton(101, left1 + 61, this.guiTop + yoffset, 60, 20, "gui.paste"));
- this.addButton(new GuiNpcButton(100, left1, this.guiTop + 21 + yoffset, 60, 20, "gui.copy"));
- this.addButton(new GuiNpcButton(105, left1 + 61, this.guiTop + 21 + yoffset, 60, 20, "gui.remove"));
-
- this.addButton(new GuiNpcButton(107, left1, this.guiTop + 66 + yoffset, 80, 20, "script.loadscript"));
- // this.getButton(107).enabled = false;
-
- GuiCustomScroll scroll = (new GuiCustomScroll(this, 0)).setUnselectable();
- scroll.setSize(100, (int) ((double) this.ySize * 0.54) - yoffset * 2);
- scroll.guiLeft = left1;
- scroll.guiTop = this.guiTop + 88 + yoffset;
- if (container != null)
- scroll.setList(container.externalScripts);
-
- this.addScroll(scroll);
- } else {
- GuiNpcTextArea var8 = new GuiNpcTextArea(2, this, this.guiLeft + 4 + yoffset, this.guiTop + 6 + yoffset, this.xSize - 160 - yoffset, (int) ((float) this.ySize * 0.92F) - yoffset * 2, this.getConsoleText());
- var8.enabled = false;
- this.addTextField(var8);
- int var9 = this.guiLeft + this.xSize - 150;
- this.addButton(new GuiNpcButton(100, var9, this.guiTop + 125, 60, 20, "gui.copy"));
- this.addButton(new GuiNpcButton(102, var9, this.guiTop + 146, 60, 20, "gui.clear"));
- this.addLabel(new GuiNpcLabel(1, "script.language", var9, this.guiTop + 15));
- String containerLang = container.getLanguage();
- this.addButton(new GuiNpcButton(103, var9 + 60, this.guiTop + 10, 80, 20, new String[]{containerLang.equals("Java") ? "Janino (JVM 8)" : containerLang},
- this.getLanguageIndex()));
- // this.getButton(103).enabled = !this.languages.isEmpty();
- this.addLabel(new GuiNpcLabel(2, "gui.enabled", var9, this.guiTop + 36));
- // Note: GuiJaninoScript is deprecated; enabled button disabled
- this.addButton(new GuiNpcButton(104, var9 + 60, this.guiTop + 31, 50, 20, new String[]{"gui.no", "gui.yes"}, 0));
-
- this.addButton(new GuiNpcButton(109, var9, this.guiTop + 78, 80, 20, "gui.website"));
- this.addButton(new GuiNpcButton(112, var9 + 81, this.guiTop + 78, 80, 20, "gui.forum"));
- this.addButton(new GuiNpcButton(110, var9, this.guiTop + 99, 80, 20, "script.apidoc"));
- this.addButton(new GuiNpcButton(111, var9 + 81, this.guiTop + 99, 80, 20, "script.apisrc"));
- }
-
- this.xSize = 420;
- this.ySize = 256;
- }
-
- public void customScrollClicked(int i, int j, int k, GuiCustomScroll scroll) {
- String hook = scroll.getSelected();
- if (this.previousHookClicked.equals(hook)) {
- String addString = "";
- if (!this.getTextField(2)
- .getText()
- .isEmpty()) {
- addString = addString + "\n";
- }
-
- addString = addString + generateMethodStub(hookMap.get(hook));
- this.getTextField(2)
- .setText(this.getTextField(2)
- .getText() + addString);
- this.previousHookClicked = "";
- } else {
- this.previousHookClicked = hook;
- }
- }
-
- public void confirmClicked(boolean flag, int i) {
- if (flag) {
- if (i == 0)
- this.openLink("https://www.curseforge.com/minecraft/mc-mods/customnpc-plus");
- else if (i == 1)
- this.openLink("https://kamkeel.github.io/CustomNPC-Plus/");
- else if (i == 2)
- this.openLink("https://kamkeel.github.io/CustomNPC-Plus/");
- else if (i == 3)
- this.openLink("http://www.minecraftforge.net/forum/index.php/board,122.0.html");
-
- if (i == 10) { //Remove
- this.container.setScript("");
- this.activeTab = 0;
- } else if (i == 101) { //Paste
- this.getTextField(2)
- .setText(NoppesStringUtils.getClipboardContents());
- this.setScript();
- } else if (i == 102) { //Clear
- if (this.activeTab == 1)
- container.script = "";
- else
- this.container.clearConsole();
-
- this.initGui();
- }
- }
-
- this.displayGuiScreen(this);
- }
-
- protected void actionPerformed(GuiButton guibutton) {
- if (guibutton.id == -1) {
- close();
- return;
- }
-
- if (guibutton.id == 0) {
- this.setScript();
- this.activeTab = 0;
- this.initGui();
- container.ensureCompiled();
- }
-
- if (guibutton.id == this.scriptLimit) {
- // if (container.container == null)
- //this.container.container = new ScriptContainer(this.container);
- // else
- // this.setScript();
- this.activeTab = 1;
- this.initGui();
- }
-
- if (guibutton.id == 109) {
- this.displayGuiScreen(new GuiConfirmOpenLink(this, "https://kamkeel.github.io/CustomNPC-Plus/", 0, true));
- } else if (guibutton.id == 110) {
- this.displayGuiScreen(new GuiConfirmOpenLink(this, "https://github.com/KAMKEEL/CustomNPC-Plus-API", 1, true));
- } else if (guibutton.id == 111) {
- this.displayGuiScreen(new GuiConfirmOpenLink(this, "https://github.com/Noppes/CustomNPCsAPI", 2, true));
- } else if (guibutton.id == 112) {
- this.displayGuiScreen(new GuiConfirmOpenLink(this, "http://www.minecraftforge.net/forum/index.php/board,122.0.html", 3, true));
- }
-
- GuiYesNo confirmScreen;
-
- //Copy
- if (guibutton.id == 100) {
- NoppesStringUtils.setClipboardContents(this.getTextField(2)
- .getText());
- }
- //Paste
- else if (guibutton.id == 101) {
- GuiYesNo guiyesno = new GuiYesNo(this, StatCollector.translateToLocal("gui.paste"), StatCollector.translateToLocal("gui.sure"), 101);
- this.displayGuiScreen(guiyesno);
- }
- //Clear
- else if (guibutton.id == 102) {
- confirmScreen = new GuiYesNo(this, StatCollector.translateToLocal("gui.clear"), StatCollector.translateToLocal("gui.sure"), 102);
- this.displayGuiScreen(confirmScreen);
- }
- //Enable
- else if (guibutton.id == 104) {
- // Deprecated GUI - enabled is now per-handler, not per-unit
- }
- //Remove
- else if (guibutton.id == 105) {
- confirmScreen = new GuiYesNo(this, "", guibutton.displayString, 10);
- this.displayGuiScreen(confirmScreen);
- }
- //Load Script
- else if (guibutton.id == 107) {
- setSubGui(new SubGuiSelectList(allExternalScripts, container.externalScripts, "All Scripts", "Selected Scripts"));
- }
- }
-
- public void subGuiClosed(SubGuiInterface sub) {
- if (sub instanceof SubGuiSelectList)
- container.setExternalScripts(((SubGuiSelectList) sub).selected);
-
- }
-
- /**
- * Generates a stub string for a given Method.
- */
- public static String generateMethodStub(Method method) {
- String mods = java.lang.reflect.Modifier.toString(method.getModifiers());
- if (!mods.isEmpty())
- mods += " ";
-
- String returnTypeStr = method.getReturnType()
- .getSimpleName();
- String name = method.getName();
-
- Map typeCount = new HashMap<>();
- String params = Arrays.stream(method.getParameters())
- .map(p -> {
- String typeName = p.getType()
- .getSimpleName();
- String baseName = Character.toLowerCase(typeName.charAt(0)) + typeName.substring(1);
-
- int count = typeCount.getOrDefault(baseName, 0) + 1;
- typeCount.put(baseName, count);
-
- // append number if same type of arg exists
- String paramName = count == 1 ? baseName : baseName + (count - 1);
-
- return typeName + " " + paramName;
- })
- .collect(Collectors.joining(", "));
-
- String body;
- Class> returnType = method.getReturnType();
- if (returnType == void.class)
- body = "";
- else if (returnType.isPrimitive()) {
- if (returnType == boolean.class)
- body = " return false;";
- else if (returnType == char.class)
- body = " return '\\0';";
- else
- body = " return 0;";
- } else {
- body = " return null;";
- }
-
- return String.format("%s%s %s(%s) {\n%s\n}\n", mods, returnTypeStr, name, params, body);
- }
-
- private String getConsoleText() {
- Map map = this.container.getConsole();
- StringBuilder builder = new StringBuilder();
- Iterator var3 = map.entrySet()
- .iterator();
-
- while (var3.hasNext()) {
- Map.Entry entry = (Map.Entry) var3.next();
- builder.insert(0, new Date(entry.getKey()) + entry.getValue() + "\n");
- }
-
- return builder.toString();
- }
-
- private int getLanguageIndex() {
- return 0;
- }
-
- private void setScript() {
- if (this.activeTab == 1) {
- String text = this.getTextField(2)
- .getText();
- text = text.replace("\r\n", "\n");
- text = text.replace("\r", "\n");
- container.setScript(text);
- }
- }
-
- public void save() {
- if (saveFunction != null)
- saveFunction.run();
- else if (parent instanceof GuiNPCInterface)
- ((GuiNPCInterface) parent).save();
- }
-
- public void textUpdate(String text) {
-// container.setScript(text);
- }
-
- public static GuiJaninoScript create(GuiScreen parent, JaninoScript script, int width, int height) {
- GuiJaninoScript gui = new GuiJaninoScript(parent, script);
- gui.setWorldAndResolution(Minecraft.getMinecraft(), width, height);
- Minecraft.getMinecraft().currentScreen = gui;
- gui.initGui();
- return gui;
- }
-
-
- @Override
- public void close() {
- this.save();
- this.setScript();
- container.ensureCompiled();
- parent.setWorldAndResolution(mc, width, height);
- parent.initGui();
- mc.currentScreen = parent;
- }
-}
diff --git a/src/main/java/noppes/npcs/client/gui/script/GuiScriptInterface.java b/src/main/java/noppes/npcs/client/gui/script/GuiScriptInterface.java
index ccb3ffde8..0b7829ebd 100644
--- a/src/main/java/noppes/npcs/client/gui/script/GuiScriptInterface.java
+++ b/src/main/java/noppes/npcs/client/gui/script/GuiScriptInterface.java
@@ -11,7 +11,10 @@ import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.StatCollector;
import noppes.npcs.NoppesStringUtils;
import noppes.npcs.client.NoppesUtil;
+import noppes.npcs.controllers.APIRegistry;
import noppes.npcs.client.gui.util.GuiCustomScroll;
+import noppes.npcs.client.gui.util.SubGuiAPISelect;
+import noppes.npcs.client.gui.util.SubGuiConfirmLink;
import noppes.npcs.client.gui.util.GuiMenuTopButton;
import noppes.npcs.client.gui.util.GuiNPCInterface;
import noppes.npcs.client.gui.util.GuiNpcButton;
@@ -127,6 +130,8 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb
// Request data from server
if (handler instanceof IScriptHandlerPacket)
((IScriptHandlerPacket) handler).requestData();
+ else
+ gui.serverDataReceived = true; // No server data to wait for
return gui;
}
@@ -366,13 +371,11 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb
}
this.addButton(new GuiNpcButton(109, var9, this.guiTop + 78, 80, 20, "gui.website"));
- this.addButton(new GuiNpcButton(112, var9 + 81, this.guiTop + 78, 80, 20, "gui.forum"));
- this.addButton(new GuiNpcButton(110, var9, this.guiTop + 99, 80, 20, "script.apidoc"));
- this.addButton(new GuiNpcButton(111, var9 + 81, this.guiTop + 99, 80, 20, "script.apisrc"));
+ this.addButton(new GuiNpcButton(110, var9 + 81, this.guiTop + 78, 80, 20, "gui.api"));
// Disable all buttons until server data arrives
if (!serverDataReceived) {
- for (int btnId : new int[]{100, 102, 103, 104, 106, 109, 110, 111, 112}) {
+ for (int btnId : new int[]{100, 102, 103, 104, 106, 109, 110}) {
GuiNpcButton btn = getButton(btnId);
if (btn != null) btn.enabled = false;
}
@@ -608,17 +611,6 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb
this.openLink("https://www.curseforge.com/minecraft/mc-mods/customnpc-plus");
}
- if (i == 1) {
- this.openLink("https://kamkeel.github.io/CustomNPC-Plus/");
- }
-
- if (i == 2) {
- this.openLink("https://kamkeel.github.io/CustomNPC-Plus/");
- }
-
- if (i == 3) {
- this.openLink("http://www.minecraftforge.net/forum/index.php/board,122.0.html");
- }
if (i == 10) {
handler.removeScriptUnit(this.activeTab - 1);
this.activeTab = 0;
@@ -714,15 +706,12 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb
}
if (guibutton.id == 110) {
- this.displayGuiScreen(new GuiConfirmOpenLink(this, "https://github.com/KAMKEEL/CustomNPC-Plus-API", 1, true));
- }
-
- if (guibutton.id == 111) {
- this.displayGuiScreen(new GuiConfirmOpenLink(this, "https://github.com/Noppes/CustomNPCsAPI", 2, true));
- }
-
- if (guibutton.id == 112) {
- this.displayGuiScreen(new GuiConfirmOpenLink(this, "http://www.minecraftforge.net/forum/index.php/board,122.0.html", 3, true));
+ if (APIRegistry.Instance.size() == 1) {
+ String url = APIRegistry.Instance.getEntries().values().iterator().next();
+ this.setSubGui(new SubGuiConfirmLink(url));
+ } else {
+ this.setSubGui(new SubGuiAPISelect());
+ }
}
if (guibutton.id == 100) {
diff --git a/src/main/java/noppes/npcs/client/gui/util/SubGuiAPISelect.java b/src/main/java/noppes/npcs/client/gui/util/SubGuiAPISelect.java
new file mode 100644
index 000000000..092fd6579
--- /dev/null
+++ b/src/main/java/noppes/npcs/client/gui/util/SubGuiAPISelect.java
@@ -0,0 +1,59 @@
+package noppes.npcs.client.gui.util;
+
+import net.minecraft.client.gui.GuiButton;
+import noppes.npcs.controllers.APIRegistry;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+public class SubGuiAPISelect extends SubGuiInterface implements ISubGuiListener {
+ private final List names;
+ private final List urls;
+
+ public SubGuiAPISelect() {
+ LinkedHashMap entries = APIRegistry.Instance.getEntries();
+ this.names = new ArrayList<>(entries.keySet());
+ this.urls = new ArrayList<>(entries.values());
+
+ this.xSize = 180;
+ this.ySize = 40 + names.size() * 24;
+ this.closeOnEsc = true;
+ }
+
+ @Override
+ public void initGui() {
+ super.initGui();
+
+ addLabel(new GuiNpcLabel(0, "gui.api", guiLeft + 10, guiTop + 10, 0xFFFFFF));
+
+ for (int i = 0; i < names.size(); i++) {
+ addButton(new GuiNpcButton(i, guiLeft + 10, guiTop + 28 + i * 24, 160, 20, names.get(i)));
+ }
+ }
+
+ @Override
+ public void drawScreen(int mouseX, int mouseY, float partialTicks) {
+ drawGradientRect(guiLeft, guiTop, guiLeft + xSize, guiTop + ySize, 0xC0101010, 0xC0101010);
+ super.drawScreen(mouseX, mouseY, partialTicks);
+ }
+
+ @Override
+ protected void actionPerformed(GuiButton guibutton) {
+ int id = guibutton.id;
+ if (id >= 0 && id < urls.size()) {
+ setSubGui(new SubGuiConfirmLink(urls.get(id)));
+ }
+ }
+
+ @Override
+ public void subGuiClosed(SubGuiInterface subgui) {
+ if (subgui instanceof SubGuiConfirmLink && ((SubGuiConfirmLink) subgui).confirmed) {
+ close();
+ }
+ }
+
+ @Override
+ public void save() {
+ }
+}
diff --git a/src/main/java/noppes/npcs/client/gui/util/SubGuiConfirmLink.java b/src/main/java/noppes/npcs/client/gui/util/SubGuiConfirmLink.java
new file mode 100644
index 000000000..f821bdc67
--- /dev/null
+++ b/src/main/java/noppes/npcs/client/gui/util/SubGuiConfirmLink.java
@@ -0,0 +1,61 @@
+package noppes.npcs.client.gui.util;
+
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.resources.I18n;
+import noppes.npcs.NoppesStringUtils;
+
+public class SubGuiConfirmLink extends SubGuiInterface {
+ private final String url;
+ public boolean confirmed = false;
+
+ public SubGuiConfirmLink(String url) {
+ this.url = url;
+ this.xSize = 260;
+ this.ySize = 120;
+ this.closeOnEsc = true;
+ }
+
+ @Override
+ public void initGui() {
+ super.initGui();
+
+ GuiNpcLabel titleLabel = new GuiNpcLabel(0, I18n.format("chat.link.confirmTrusted"), guiLeft, guiTop + 10, 0xFFFFFF);
+ titleLabel.center(xSize);
+ addLabel(titleLabel);
+
+ GuiNpcLabel urlLabel = new GuiNpcLabel(1, url, guiLeft, guiTop + 28, 0xCCCCFF);
+ urlLabel.center(xSize);
+ addLabel(urlLabel);
+
+ int btnWidth = 115;
+ int spacing = 10;
+ int totalWidth = btnWidth * 2 + spacing;
+ int startX = guiLeft + (xSize - totalWidth) / 2;
+
+ addButton(new GuiNpcButton(0, startX, guiTop + 52, btnWidth, 20, "chat.link.open"));
+ addButton(new GuiNpcButton(1, startX + btnWidth + spacing, guiTop + 52, btnWidth, 20, "chat.copy"));
+ addButton(new GuiNpcButton(2, guiLeft + (xSize - btnWidth) / 2, guiTop + 78, btnWidth, 20, "gui.cancel"));
+ }
+
+ @Override
+ public void drawScreen(int mouseX, int mouseY, float partialTicks) {
+ drawGradientRect(0, 0, width, height, 0xC0101010, 0xC0101010);
+ super.drawScreen(mouseX, mouseY, partialTicks);
+ }
+
+ @Override
+ protected void actionPerformed(GuiButton guibutton) {
+ if (guibutton.id == 0) {
+ confirmed = true;
+ openLink(url);
+ } else if (guibutton.id == 1) {
+ confirmed = true;
+ NoppesStringUtils.setClipboardContents(url);
+ }
+ close();
+ }
+
+ @Override
+ public void save() {
+ }
+}
diff --git a/src/main/java/noppes/npcs/config/ConfigClient.java b/src/main/java/noppes/npcs/config/ConfigClient.java
index ea87eeaf9..fa4376334 100644
--- a/src/main/java/noppes/npcs/config/ConfigClient.java
+++ b/src/main/java/noppes/npcs/config/ConfigClient.java
@@ -87,10 +87,10 @@ public class ConfigClient {
public static float QuestOverlayX = 0;
public static Property QuestOverlayYProperty;
- public static float QuestOverlayY = 31;
+ public static float QuestOverlayY = 14;
public static Property QuestOverlayScaleProperty;
- public static int QuestOverlayScale = 223;
+ public static int QuestOverlayScale = 246;
public static Property QuestOverlayTextAlignProperty;
public static int QuestOverlayTextAlign = 0; // 0: Left, 1: Center, 2: Right
@@ -99,35 +99,35 @@ public class ConfigClient {
public static boolean CompassEnabled = true;
public static Property CompassOverlayXProperty;
- public static float CompassOverlayX = 37;
+ public static float CompassOverlayX = 36;
public static Property CompassOverlayYProperty;
public static float CompassOverlayY = 0;
public static Property CompassOverlayScaleProperty;
- public static int CompassOverlayScale = 276;
+ public static int CompassOverlayScale = 344;
public static Property CompassOverlayWidthProperty;
- public static int CompassOverlayWidth = 200;
+ public static int CompassOverlayWidth = 158;
// Ability Hotbar HUD
public static Property AbilityHotbarEnabledProperty;
public static boolean AbilityHotbarEnabled = true;
public static Property AbilityHotbarXProperty;
- public static float AbilityHotbarX = 3;
+ public static float AbilityHotbarX = 0;
public static Property AbilityHotbarYProperty;
- public static float AbilityHotbarY = 50;
+ public static float AbilityHotbarY = 43;
public static Property AbilityHotbarScaleProperty;
- public static int AbilityHotbarScale = 100;
+ public static int AbilityHotbarScale = 227;
public static Property AbilityHotbarHorizontalProperty;
public static boolean AbilityHotbarHorizontal = false;
public static Property AbilityHotbarAltTextureProperty;
- public static boolean AbilityHotbarAltTexture = false;
+ public static boolean AbilityHotbarAltTexture = true;
// 1=Above(H)/Left(V), 2=Below(H)/Right(V)
public static Property AbilityHotbarTextPositionProperty;
@@ -179,11 +179,11 @@ public class ConfigClient {
QuestOverlayXProperty = config.get(HUD, "Quest Hud X", 0.0, "X position of the quest overlay.");
QuestOverlayX = (float) QuestOverlayXProperty.getDouble(0);
- QuestOverlayYProperty = config.get(HUD, "Quest Hud Y", 31.0, "Y position of the quest overlay.");
- QuestOverlayY = (float) QuestOverlayYProperty.getDouble(31);
+ QuestOverlayYProperty = config.get(HUD, "Quest Hud Y", 14.0, "Y position of the quest overlay.");
+ QuestOverlayY = (float) QuestOverlayYProperty.getDouble(14);
- QuestOverlayScaleProperty = config.get(HUD, "Quest Hud Scale", 223, "Scale percentage of the quest overlay.");
- QuestOverlayScale = QuestOverlayScaleProperty.getInt(223);
+ QuestOverlayScaleProperty = config.get(HUD, "Quest Hud Scale", 246, "Scale percentage of the quest overlay.");
+ QuestOverlayScale = QuestOverlayScaleProperty.getInt(246);
QuestOverlayTextAlignProperty = config.get(HUD, "Quest Hud Text Alignment", 0, "Text alignment in quest overlay (0: Left, 1: Center, 2: Right).");
QuestOverlayTextAlign = QuestOverlayTextAlignProperty.getInt(0);
@@ -200,7 +200,7 @@ public class ConfigClient {
CompassOverlayXProperty = config.get(
HUD,
"Compass Hud X",
- 37.0,
+ 36.0,
"Horizontal position of compass overlay (0-100 percentage)"
);
CompassOverlayX = (float) CompassOverlayXProperty.getDouble();
@@ -216,19 +216,19 @@ public class ConfigClient {
CompassOverlayScaleProperty = config.get(
HUD,
"Compass Hud Scale",
- 276,
+ 344,
"Scale percentage of compass overlay",
50,
- 300
+ 500
);
CompassOverlayScale = CompassOverlayScaleProperty.getInt();
CompassOverlayWidthProperty = config.get(
HUD,
"Compass Hud Width",
- 200,
+ 158,
"Base width of compass bar in pixels",
- 100,
+ 50,
1000
);
CompassOverlayWidth = CompassOverlayWidthProperty.getInt();
@@ -237,19 +237,19 @@ public class ConfigClient {
AbilityHotbarEnabledProperty = config.get(HUD, "Ability Hotbar Enabled", true, "Enable Ability Hotbar HUD Component");
AbilityHotbarEnabled = AbilityHotbarEnabledProperty.getBoolean();
- AbilityHotbarXProperty = config.get(HUD, "Ability Hotbar X", 3.0, "Horizontal position (0-100 percentage)");
+ AbilityHotbarXProperty = config.get(HUD, "Ability Hotbar X", 0.0, "Horizontal position (0-100 percentage)");
AbilityHotbarX = (float) AbilityHotbarXProperty.getDouble();
- AbilityHotbarYProperty = config.get(HUD, "Ability Hotbar Y", 50.0, "Vertical position (0-100 percentage)");
+ AbilityHotbarYProperty = config.get(HUD, "Ability Hotbar Y", 43.0, "Vertical position (0-100 percentage)");
AbilityHotbarY = (float) AbilityHotbarYProperty.getDouble();
- AbilityHotbarScaleProperty = config.get(HUD, "Ability Hotbar Scale", 100, "Scale percentage", 50, 300);
+ AbilityHotbarScaleProperty = config.get(HUD, "Ability Hotbar Scale", 227, "Scale percentage", 50, 500);
AbilityHotbarScale = AbilityHotbarScaleProperty.getInt();
AbilityHotbarHorizontalProperty = config.get(HUD, "Ability Hotbar Horizontal", false, "Display horizontally instead of vertically");
AbilityHotbarHorizontal = AbilityHotbarHorizontalProperty.getBoolean();
- AbilityHotbarAltTextureProperty = config.get(HUD, "Ability Hotbar Alt Texture", false, "Use rounded square instead of circle slots");
+ AbilityHotbarAltTextureProperty = config.get(HUD, "Ability Hotbar Alt Texture", true, "Use rounded square instead of circle slots");
AbilityHotbarAltTexture = AbilityHotbarAltTextureProperty.getBoolean();
AbilityHotbarTextPositionProperty = config.get(HUD, "Ability Hotbar Text Position", 2, "Text label position (1=Above/Left, 2=Below/Right)");
diff --git a/src/main/java/noppes/npcs/controllers/APIRegistry.java b/src/main/java/noppes/npcs/controllers/APIRegistry.java
new file mode 100644
index 000000000..746bc4acd
--- /dev/null
+++ b/src/main/java/noppes/npcs/controllers/APIRegistry.java
@@ -0,0 +1,25 @@
+package noppes.npcs.controllers;
+
+import java.util.LinkedHashMap;
+
+public class APIRegistry {
+ public static final APIRegistry Instance = new APIRegistry();
+
+ private final LinkedHashMap entries = new LinkedHashMap<>();
+
+ public void register(String name, String url) {
+ entries.put(name, url);
+ }
+
+ public void unregister(String name) {
+ entries.remove(name);
+ }
+
+ public LinkedHashMap getEntries() {
+ return entries;
+ }
+
+ public int size() {
+ return entries.size();
+ }
+}
diff --git a/src/main/java/noppes/npcs/controllers/AnimationController.java b/src/main/java/noppes/npcs/controllers/AnimationController.java
index 6e9d9e87c..ae9012b75 100644
--- a/src/main/java/noppes/npcs/controllers/AnimationController.java
+++ b/src/main/java/noppes/npcs/controllers/AnimationController.java
@@ -43,8 +43,8 @@ public class AnimationController implements IAnimationHandler {
// Built-in animations loaded from assets folder (read-only, keyed by name)
public HashMap builtInAnimations = new HashMap<>();
- private static final String BUILTIN_ANIMATIONS_PATH = "/assets/customnpcs/animations";
- private static final String BUILTIN_ANIMATIONS_RESOURCE = "assets/customnpcs/animations";
+ private static final String BUILTIN_ANIMATIONS_PATH = "/assets/customnpcs/cnpc_animations";
+ private static final String BUILTIN_ANIMATIONS_RESOURCE = "assets/customnpcs/cnpc_animations";
public static AnimationController Instance = new AnimationController();
private int lastUsedID = 0;
@@ -75,7 +75,7 @@ public class AnimationController implements IAnimationHandler {
}
/**
- * Load built-in animations from assets/customnpcs/animations/ folder.
+ * Load built-in animations from assets/customnpcs/cnpc_animations/ folder.
* These animations are read-only and accessed by name only (no IDs).
* Scans the folder directly instead of using a manifest.
*/
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_BeamDual_Active.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_BeamDual_Active.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_BeamDual_Active.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_BeamDual_Active.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_BeamDual_Windup.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_BeamDual_Windup.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_BeamDual_Windup.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_BeamDual_Windup.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Beam_Active.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Beam_Active.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Beam_Active.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Beam_Active.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Beam_Windup.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Beam_Windup.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Beam_Windup.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Beam_Windup.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Charge_Active.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Charge_Active.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Charge_Active.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Charge_Active.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Charge_Windup.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Charge_Windup.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Charge_Windup.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Charge_Windup.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Cutter_Active.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Cutter_Active.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Cutter_Active.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Cutter_Active.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Cutter_Windup.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Cutter_Windup.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Cutter_Windup.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Cutter_Windup.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_DiscDual_Active.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_DiscDual_Active.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_DiscDual_Active.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_DiscDual_Active.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_DiscDual_Windup.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_DiscDual_Windup.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_DiscDual_Windup.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_DiscDual_Windup.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Disc_Active.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Disc_Active.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Disc_Active.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Disc_Active.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Disc_Windup.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Disc_Windup.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Disc_Windup.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Disc_Windup.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Generic_Dazed.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Generic_Dazed.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Generic_Dazed.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Generic_Dazed.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Guard_Active.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Guard_Active.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Guard_Active.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Guard_Active.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Guard_Counter.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Guard_Counter.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Guard_Counter.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Guard_Counter.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_HeavyHit_Active.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_HeavyHit_Active.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_HeavyHit_Active.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_HeavyHit_Active.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_HeavyHit_Windup.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_HeavyHit_Windup.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_HeavyHit_Windup.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_HeavyHit_Windup.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Laser_Active.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Laser_Active.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Laser_Active.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Laser_Active.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Laser_Windup.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Laser_Windup.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Laser_Windup.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Laser_Windup.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_OrbBarrage_Active.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_OrbBarrage_Active.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_OrbBarrage_Active.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_OrbBarrage_Active.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_OrbBarrage_Windup.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_OrbBarrage_Windup.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_OrbBarrage_Windup.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_OrbBarrage_Windup.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_OrbDual_Active.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_OrbDual_Active.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_OrbDual_Active.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_OrbDual_Active.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_OrbDual_Windup.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_OrbDual_Windup.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_OrbDual_Windup.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_OrbDual_Windup.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Orb_Active.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Orb_Active.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Orb_Active.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Orb_Active.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Orb_Windup.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Orb_Windup.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Orb_Windup.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Orb_Windup.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Shockwave_Active.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Shockwave_Active.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Shockwave_Active.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Shockwave_Active.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Shockwave_Windup.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Shockwave_Windup.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Shockwave_Windup.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Shockwave_Windup.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Slam_Active.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Slam_Active.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Slam_Active.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Slam_Active.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Slam_Windup.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Slam_Windup.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Slam_Windup.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Slam_Windup.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Zone_Active.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Zone_Active.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Zone_Active.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Zone_Active.json
diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Zone_Windup.json b/src/main/resources/assets/customnpcs/cnpc_animations/Ability_Zone_Windup.json
similarity index 100%
rename from src/main/resources/assets/customnpcs/animations/Ability_Zone_Windup.json
rename to src/main/resources/assets/customnpcs/cnpc_animations/Ability_Zone_Windup.json
diff --git a/src/main/resources/assets/customnpcs/lang/en_US.lang b/src/main/resources/assets/customnpcs/lang/en_US.lang
index 13fa4fc07..5eb898151 100644
--- a/src/main/resources/assets/customnpcs/lang/en_US.lang
+++ b/src/main/resources/assets/customnpcs/lang/en_US.lang
@@ -854,8 +854,7 @@ quest.tracking=Tracking
quest.alerts=Alerts
quest.noAlerts=No Alerts
-script.apidoc=API Docs
-script.apisrc=API Source
+gui.api=API
script.scripts=Scripts
script.hooks=Hooks