| Name | Author | Game Mode | Rating | |||||
|---|---|---|---|---|---|---|---|---|
| NpcBunnies | Cranky | Mutator | N/A | |||||
namespace npcBunniesEditorCore
{
/// <summary>
/// Editor view identifier for main.
/// </summary>
const int NDE_MAIN = 0;
/// <summary>
/// Editor view identifier for create.
/// </summary>
const int NDE_CREATE = 1;
/// <summary>
/// Editor view identifier for edit pick.
/// </summary>
const int NDE_EDIT_PICK = 2;
/// <summary>
/// Editor view identifier for edit.
/// </summary>
const int NDE_EDIT = 3;
/// <summary>
/// Editor view identifier for dialogue.
/// </summary>
const int NDE_DIALOGUE = 4;
/// <summary>
/// Editor view identifier for shop.
/// </summary>
const int NDE_SHOP = 5;
/// <summary>
/// Editor view identifier for guide.
/// </summary>
const int NDE_GUIDE = 6;
/// <summary>
/// Editor view identifier for path record.
/// </summary>
const int NDE_PATH_RECORD = 7;
/// <summary>
/// Editor view identifier for quest.
/// </summary>
const int NDE_QUEST = 8;
/// <summary>
/// Editor view identifier for reward.
/// </summary>
const int NDE_REWARD = 9;
/// <summary>
/// Editor view identifier for help.
/// </summary>
const int NDE_HELP = 10;
const int NDE_LOAD_ANIMS = 11;
/// <summary>
/// Vertical pixel adjustment for the focused or selected button highlight.
/// </summary>
const int NDE_FOCUS_OFFSET_Y = DB_FOCUS_OFFSET_Y; //Selection offset
/// <summary>
/// Horizontal pixel adjustment for the green/red toggle underlay rectangles.
/// </summary>
int NDE_TOGGLE_UNDERLAY_OFFSET_X = -3;
/// <summary>
/// Vertical pixel adjustment for the green/red toggle underlay rectangles.
/// </summary>
int NDE_TOGGLE_UNDERLAY_OFFSET_Y = -7;
/// <summary>
/// Extra vertical offset applied to menu contents below the title and global controls.
/// </summary>
int NDE_CONTENT_OFFSET_Y = 20;
/// <summary>
/// Tile offset added to mouse-based NPC placement on the X axis.
/// </summary>
int NDE_MOUSE_PLACE_TILE_OFFSET_X = 0;
/// <summary>
/// Tile offset added to mouse-based NPC placement on the Y axis.
/// </summary>
int NDE_MOUSE_PLACE_TILE_OFFSET_Y = 0;
/// <summary>
/// Horizontal pixel offset for the character preview in the edit screen.
/// </summary>
int NDE_CHAR_EDIT_PREVIEW_OFFSET_X = 34;
/// <summary>
/// Vertical pixel offset for the character preview in the edit screen.
/// </summary>
int NDE_CHAR_EDIT_PREVIEW_OFFSET_Y = -3;
/// <summary>
/// Horizontal pixel offset for character previews in the create screen.
/// </summary>
int NDE_CREATE_PREVIEW_OFFSET_X = 28;
/// <summary>
/// Vertical pixel offset for character previews in the create screen.
/// </summary>
int NDE_CREATE_PREVIEW_OFFSET_Y = 18;
/// <summary>
/// Horizontal pixel offset applied to the whole NPC Designer panel.
/// </summary>
int NDE_PANEL_OFFSET_X = 0;
/// <summary>
/// Vertical pixel offset applied to the whole NPC Designer panel while preserving the bottom edge.
/// </summary>
int NDE_PANEL_OFFSET_Y = 10;
/// <summary>
/// Characters accepted by editor text fields in addition to letters, numbers, and spaces.
/// </summary>
const string ALLOWED_SPECIAL_CHARACTERS = "()[]?!|/,.\\\"';:-_+=@#$%^&*{}<>`~";
/// <summary>
/// Button/action identifier for main create.
/// </summary>
const int NDE_ACT_MAIN_CREATE = 1;
/// <summary>
/// Button/action identifier for main edit.
/// </summary>
const int NDE_ACT_MAIN_EDIT = 2;
/// <summary>
/// Button/action identifier for main delete.
/// </summary>
const int NDE_ACT_MAIN_DELETE = 3;
/// <summary>
/// Button/action identifier for main undo delete.
/// </summary>
const int NDE_ACT_MAIN_UNDO_DELETE = 4;
/// <summary>
/// Button/action identifier for exit.
/// </summary>
const int NDE_ACT_EXIT = 5;
/// <summary>
/// Button/action identifier for back main.
/// </summary>
const int NDE_ACT_BACK_MAIN = 6;
/// <summary>
/// Button/action identifier for create type.
/// </summary>
const int NDE_ACT_CREATE_TYPE = 7;
/// <summary>
/// Button/action identifier for scroll up.
/// </summary>
const int NDE_ACT_SCROLL_UP = 8;
/// <summary>
/// Button/action identifier for scroll down.
/// </summary>
const int NDE_ACT_SCROLL_DOWN = 9;
/// <summary>
/// Button/action identifier for pick edit npc.
/// </summary>
const int NDE_ACT_PICK_EDIT_NPC = 10;
/// <summary>
/// Button/action identifier for field.
/// </summary>
const int NDE_ACT_FIELD = 11;
/// <summary>
/// Button/action identifier for toggle position.
/// </summary>
const int NDE_ACT_TOGGLE_POSITION = 12;
/// <summary>
/// Button/action identifier for direction.
/// </summary>
const int NDE_ACT_DIRECTION = 13;
/// <summary>
/// Button/action identifier for toggle follow.
/// </summary>
const int NDE_ACT_TOGGLE_FOLLOW = 14;
/// <summary>
/// Button/action identifier for edit dialogue.
/// </summary>
const int NDE_ACT_EDIT_DIALOGUE = 15;
/// <summary>
/// Button/action identifier for edit shop.
/// </summary>
const int NDE_ACT_EDIT_SHOP = 16;
/// <summary>
/// Button/action identifier for toggle guide.
/// </summary>
const int NDE_ACT_TOGGLE_GUIDE = 17;
/// <summary>
/// Button/action identifier for edit guide.
/// </summary>
const int NDE_ACT_EDIT_GUIDE = 18;
const int NDE_ACT_TOGGLE_FIGHTING = 310;
const int NDE_ACT_FIGHTING_STYLE = 311;
const int NDE_ACT_CHAR_CATEGORY = 312;
/// <summary>
/// Button/action identifier for dialogue prev.
/// </summary>
const int NDE_ACT_DIALOGUE_PREV = 19;
/// <summary>
/// Button/action identifier for dialogue next.
/// </summary>
const int NDE_ACT_DIALOGUE_NEXT = 20;
/// <summary>
/// Button/action identifier for dialogue add.
/// </summary>
const int NDE_ACT_DIALOGUE_ADD = 21;
/// <summary>
/// Button/action identifier for dialogue type.
/// </summary>
const int NDE_ACT_DIALOGUE_TYPE = 22;
/// <summary>
/// Button/action identifier for choice goto.
/// </summary>
const int NDE_ACT_CHOICE_GOTO = 23;
/// <summary>
/// Button/action identifier for edit quest.
/// </summary>
const int NDE_ACT_EDIT_QUEST = 24;
/// <summary>
/// Button/action identifier for edit reward.
/// </summary>
const int NDE_ACT_EDIT_REWARD = 25;
/// <summary>
/// Button/action identifier for shop add.
/// </summary>
const int NDE_ACT_SHOP_ADD = 26;
/// <summary>
/// Button/action identifier for shop reward prev.
/// </summary>
const int NDE_ACT_SHOP_REWARD_PREV = 27;
/// <summary>
/// Button/action identifier for shop reward next.
/// </summary>
const int NDE_ACT_SHOP_REWARD_NEXT = 28;
/// <summary>
/// Button/action identifier for shop coins.
/// </summary>
const int NDE_ACT_SHOP_COINS = 29;
/// <summary>
/// Button/action identifier for shop gems.
/// </summary>
const int NDE_ACT_SHOP_GEMS = 30;
/// <summary>
/// Button/action identifier for shop stock.
/// </summary>
const int NDE_ACT_SHOP_STOCK = 31;
/// <summary>
/// Button/action identifier for shop delete.
/// </summary>
const int NDE_ACT_SHOP_DELETE = 32;
/// <summary>
/// Button/action identifier for guide add.
/// </summary>
const int NDE_ACT_GUIDE_ADD = 33;
/// <summary>
/// Button/action identifier for guide edit.
/// </summary>
const int NDE_ACT_GUIDE_EDIT = 34;
/// <summary>
/// Button/action identifier for guide delete.
/// </summary>
const int NDE_ACT_GUIDE_DELETE = 35;
/// <summary>
/// Button/action identifier for quest add.
/// </summary>
const int NDE_ACT_QUEST_ADD = 36;
/// <summary>
/// Button/action identifier for quest type.
/// </summary>
const int NDE_ACT_QUEST_TYPE = 37;
/// <summary>
/// Button/action identifier for quest amount.
/// </summary>
const int NDE_ACT_QUEST_AMOUNT = 38;
/// <summary>
/// Button/action identifier for quest delete.
/// </summary>
const int NDE_ACT_QUEST_DELETE = 39;
/// <summary>
/// Button/action identifier for reward add.
/// </summary>
const int NDE_ACT_REWARD_ADD = 40;
/// <summary>
/// Button/action identifier for reward type.
/// </summary>
const int NDE_ACT_REWARD_TYPE = 41;
/// <summary>
/// Button/action identifier for reward amount.
/// </summary>
const int NDE_ACT_REWARD_AMOUNT = 42;
/// <summary>
/// Button/action identifier for reward delete.
/// </summary>
const int NDE_ACT_REWARD_DELETE = 43;
/// <summary>
/// Button/action identifier for char prev.
/// </summary>
const int NDE_ACT_CHAR_PREV = 44;
/// <summary>
/// Button/action identifier for char next.
/// </summary>
const int NDE_ACT_CHAR_NEXT = 45;
/// <summary>
/// Button/action identifier for shop amount.
/// </summary>
const int NDE_ACT_SHOP_AMOUNT = 46;
/// <summary>
/// Button/action identifier for path edit start.
/// </summary>
const int NDE_ACT_PATH_EDIT_START = 47;
/// <summary>
/// Button/action identifier for path edit stop.
/// </summary>
const int NDE_ACT_PATH_EDIT_STOP = 48;
/// <summary>
/// Button/action identifier for toggling player movement while the editor remains open.
/// </summary>
const int NDE_ACT_TOGGLE_PLAYER_MOVEMENT = 49;
/// <summary>
/// Button/action identifier for help.
/// </summary>
const int NDE_ACT_HELP = 50;
/// <summary>
/// Button/action identifier for toggling big NPC dialogue animations.
/// </summary>
const int NDE_ACT_TOGGLE_BIG_ANIMS = 51;
const int NDE_ACT_TOGGLE_ALL_MONSTER_ANIMS = 313;
const int NDE_ACT_LOAD_ANIMS = 314;
const int NDE_ACT_LOAD_ANIM_PREV = 315;
const int NDE_ACT_LOAD_ANIM_NEXT = 316;
const int NDE_ACT_LOAD_ANIM_LOAD = 317;
const int NDE_ACT_LOAD_ANIM_UNLOAD = 318;
const int NDE_ACT_DIALOGUE_FRAME_PREV = 319;
const int NDE_ACT_DIALOGUE_FRAME_NEXT = 320;
const int NDE_ACT_DIALOGUE_DELETE = 321;
const int NDE_ACT_NPC_ACCESSORY = 322;
const int NDE_ACT_EDIT_PATH_REWARD = 323;
const int NDE_ACT_GUIDE_ADD_TELEPORT = 324;
const int NDE_ACT_NPC_SIZE = 325;
const int NDE_ACT_TELEPORT_DIRECTION = 326;
const int NDE_ACT_DIALOGUE_SPEAKER = 327;
const int NDE_ACT_DIALOGUE_AUTO_CONTINUE = 328;
const int NDE_ACT_TOGGLE_PUSHABLE = 329;
const int NDE_ACT_NPC_SPEED = 330;
const int NDE_ACT_QUEST_RESPAWN_MONSTERS = 331;
const int NDE_ACT_DIALOGUE_GOTO = 332;
const int NDE_ACT_NPC_TRACE_MODE = 333;
const int NDE_ACT_NPC_TRACE_COLOR = 334;
/// <summary>
/// Text field identifier for guide path base.
/// </summary>
const int NDE_FIELD_GUIDE_PATH_BASE = 50;
/// <summary>
/// Text field identifier for guide end line.
/// </summary>
const int NDE_FIELD_GUIDE_END_LINE = 500;
/// <summary>
/// Text field identifier for guide already line.
/// </summary>
const int NDE_FIELD_GUIDE_ALREADY_LINE = 501;
const int NDE_FIELD_QUEST_IN_PROGRESS_LINE = 502;
const int NDE_FIELD_QUEST_FINISHED_LINE = 503;
const int NDE_FIELD_NPC_HAT = 504;
const int NDE_FIELD_NPC_SCARF = 505;
const int NDE_FIELD_NPC_GLASSES = 506;
const int NDE_FIELD_NPC_TRACE_COLOR = 507;
/// <summary>
/// Stores one clickable editor button and the action payload attached to it.
/// </summary>
class NpcDesignerButton
{
int x;
int y;
int w;
int h;
int action;
int a;
int b;
string text;
}
/// <summary>
/// Whether the NPC Designer overlay is currently visible and active.
/// </summary>
bool NpcDesignerOpen = false;
/// <summary>
/// Whether the current menu session was opened through the public !npcHelp command.
/// Help-only sessions may browse help but can never return to the NPC editor.
/// </summary>
bool NpcDesignerHelpOnly = false;
/// <summary>
/// Current NPC Designer view identifier.
/// </summary>
int NpcDesignerView = NDE_MAIN;
/// <summary>
/// Index of the currently keyboard-focused button.
/// </summary>
int NpcDesignerFocus = 0;
/// <summary>
/// Game tick of the last processed mouse click.
/// </summary>
int NpcDesignerLastClick = 0;
/// <summary>
/// Whether the mouse button was held during the previous editor input frame.
/// </summary>
bool NpcDesignerMouseWasDown = false;
/// <summary>
/// Game tick of the last processed navigation or path-edit key.
/// </summary>
int NpcDesignerLastKey = 0;
/// <summary>
/// Game tick of the last accepted chat command opening the editor.
/// </summary>
int NpcDesignerLastCommandTick = -1000;
/// <summary>
/// Game tick before which editor input is ignored after opening.
/// </summary>
int NpcDesignerIgnoreInputUntilTick = 0;
/// <summary>
/// Last keyboard key accepted by a text field.
/// </summary>
int NpcDesignerLastTextKey = -1;
/// <summary>
/// Game tick of the last text-field key accepted.
/// </summary>
int NpcDesignerLastTextTick = 0;
/// <summary>
/// Editor-local caps-lock state used while typing in text fields.
/// </summary>
bool NpcDesignerCapsLock = false;
/// <summary>
/// Tracks whether the caps-lock key is currently held to debounce toggles.
/// </summary>
bool NpcDesignerCapsKeyDown = false;
/// <summary>
/// Scroll offset for the currently visible scrollable editor list.
/// </summary>
int NpcDesignerScroll = 0;
/// <summary>
/// Selected NPC type index while creating a new NPC.
/// </summary>
int NpcDesignerSelectedType = -1;
/// <summary>
/// Selected NPC index in the global npcBunnies array.
/// </summary>
int NpcDesignerSelectedNpc = -1;
/// <summary>
/// Selected dialogue set index for dialogue, quest, and reward editing.
/// </summary>
int NpcDesignerDialogueSet = 0;
/// <summary>
/// Selected guide path index for path and guide-line editing.
/// </summary>
int NpcDesignerPathIndex = -1;
/// <summary>
/// Identifier of the text field currently receiving typed input.
/// </summary>
int NpcDesignerEditingField = -1;
int NpcDesignerEditingValueField = -1;
string NpcDesignerEditingValue = "";
int NpcDesignerEditingCursor = 0;
int NpcDesignerTextScrollField = -1;
int NpcDesignerTextScrollLine = 0;
bool NpcDesignerTextScrollManual = false;
bool NpcDesignerTextDirty = false;
int NpcDesignerTextDirtyTick = -9999;
/// <summary>
/// Whether the next valid level click moves the selected NPC.
/// </summary>
bool NpcDesignerMovingNpc = false;
/// <summary>
/// Whether arrow keys are currently recording guide path steps.
/// </summary>
bool NpcDesignerRecordingPath = false;
bool NpcDesignerEditingTeleport = false;
bool NpcDesignerTeleportIsNew = false;
int NpcDesignerTeleportEditX = 0;
int NpcDesignerTeleportEditY = 0;
int NpcDesignerTeleportOriginalX = 0;
int NpcDesignerTeleportOriginalY = 0;
bool NpcDesignerTeleportFirePressed = false;
/// <summary>
/// Whether normal player movement is allowed while the editor overlay remains open.
/// </summary>
bool NpcDesignerAllowPlayerMovement = false;
/// <summary>
/// Whether the current level NPC file has already been backed up this session.
/// </summary>
bool NpcDesignerBackedUp = false;
/// <summary>
/// Whether the edit-pick list is currently being used to choose an NPC to delete.
/// </summary>
bool NpcDesignerDeletePick = false;
/// <summary>
/// Most recently deleted NPC, kept for undo delete.
/// </summary>
npcBunniesCore::npcBunny NpcDesignerDeletedNpc;
/// <summary>
/// Whether an NPC is currently available for undo delete.
/// </summary>
bool NpcDesignerHasDeletedNpc = false;
int NpcDesignerLoadMonsterIndex = 0;
int NpcDesignerLoadBossIndex = 0;
int NpcDesignerLoadObjectIndex = 0;
/// <summary>
/// Whether the server has already been shown the NPC Designer command hint this level.
/// </summary>
bool NpcDesignerCommandHintShown = false;
/// <summary>
/// Buttons drawn during the current frame and available for click/keyboard activation.
/// </summary>
array<NpcDesignerButton@> NpcDesignerButtons;
DbWindow NpcDesignerWindow;
/// <summary>
/// NPC character names shown in create and character-selection menus.
/// </summary>
array<string> NpcDesignerNpcNames = {"Jazz", "Spaz", "Lori", "Frog", "Bird", "Devan", "Mario", "Sonic", "Tails", "JJ1", "Yoshi", "Eva"};
array<string> NpcDesignerMonsterNames = {"Bat", "Bee", "BeeBoy", "Bees", "Butterfly", "Crab", "Demon", "DoggyDogg", "Dragon", "Dragonfly", "FatChick", "Fencer", "Fish", "Hatter", "Helmut", "LabRat", "Lizard", "FloatLz", "XmasLz", "XmasFloat", "Monkey", "Monkey", "Turtle", "XmasTurt", "TubeTurt", "TufTurt", "Rapier", "Raven", "Skeleton", "Spark", "Sucker", "FloatSuck", "Cat", "PacGhost", "Moth", "Witch"};
array<int> NpcDesignerMonsterTypes = {npcBunniesAnimations::NpcMonster::Bat, npcBunniesAnimations::NpcMonster::Bee, npcBunniesAnimations::NpcMonster::BeeBoy, npcBunniesAnimations::NpcMonster::Bees, npcBunniesAnimations::NpcMonster::Butterfly, npcBunniesAnimations::NpcMonster::Crab, npcBunniesAnimations::NpcMonster::Demon, npcBunniesAnimations::NpcMonster::DoggyDogg, npcBunniesAnimations::NpcMonster::Dragon, npcBunniesAnimations::NpcMonster::Dragonfly, npcBunniesAnimations::NpcMonster::FatChick, npcBunniesAnimations::NpcMonster::Fencer, npcBunniesAnimations::NpcMonster::Fish, npcBunniesAnimations::NpcMonster::Hatter, npcBunniesAnimations::NpcMonster::Helmut, npcBunniesAnimations::NpcMonster::LabRat, npcBunniesAnimations::NpcMonster::Lizard, npcBunniesAnimations::NpcMonster::FloatLizard, npcBunniesAnimations::NpcMonster::XmasLizard, npcBunniesAnimations::NpcMonster::XmasFloatLizard, npcBunniesAnimations::NpcMonster::Monkey, npcBunniesAnimations::NpcMonster::StandMonkey, npcBunniesAnimations::NpcMonster::NormalTurtle, npcBunniesAnimations::NpcMonster::XmasNormalTurtle, npcBunniesAnimations::NpcMonster::TubeTurtle, npcBunniesAnimations::NpcMonster::TufTurtle, npcBunniesAnimations::NpcMonster::Rapier, npcBunniesAnimations::NpcMonster::Raven, npcBunniesAnimations::NpcMonster::Skeleton, npcBunniesAnimations::NpcMonster::Spark, npcBunniesAnimations::NpcMonster::Sucker, npcBunniesAnimations::NpcMonster::FloatSucker, npcBunniesAnimations::NpcMonster::Cat, npcBunniesAnimations::NpcMonster::PacmanGhost, npcBunniesAnimations::NpcMonster::Moth, npcBunniesAnimations::NpcMonster::Witch};
array<string> NpcDesignerBossNames = {"Bilsy", "XmasBilsy", "Bolly", "Bubba", "DevilDevan", "Queen", "Robot", "RocketTurtle", "TufBoss", "Tweedle", "Uterus"};
array<int> NpcDesignerBossTypes = {npcBunniesAnimations::NpcBoss::Bilsy, npcBunniesAnimations::NpcBoss::XmasBilsy, npcBunniesAnimations::NpcBoss::Bolly, npcBunniesAnimations::NpcBoss::Bubba, npcBunniesAnimations::NpcBoss::DevilDevan, npcBunniesAnimations::NpcBoss::Queen, npcBunniesAnimations::NpcBoss::Robot, npcBunniesAnimations::NpcBoss::RocketTurtle, npcBunniesAnimations::NpcBoss::TufBoss, npcBunniesAnimations::NpcBoss::Tweedle, npcBunniesAnimations::NpcBoss::Uterus};
array<string> NpcDesignerObjectNames = {"BubbleSh", "FireSh", "ElectroSh", "Morph", "BirdMorph", "BlasterPU", "BouncerPU", "IcePU", "SeekerPU", "RFPU", "ToasterPU", "Gun8PU", "Gun9PU"};
array<int> NpcDesignerObjectTypes = {npcBunniesAnimations::NpcObject::WaterShield, npcBunniesAnimations::NpcObject::FireShield, npcBunniesAnimations::NpcObject::LightningShield, npcBunniesAnimations::NpcObject::MorphMonitor, npcBunniesAnimations::NpcObject::BirdMonitor, npcBunniesAnimations::NpcObject::BlasterPowerup, npcBunniesAnimations::NpcObject::BouncerPowerup, npcBunniesAnimations::NpcObject::IcePowerup, npcBunniesAnimations::NpcObject::SeekerPowerup, npcBunniesAnimations::NpcObject::RFPowerup, npcBunniesAnimations::NpcObject::ToasterPowerup, npcBunniesAnimations::NpcObject::Gun8Powerup, npcBunniesAnimations::NpcObject::Gun9Powerup};
/// <summary>
/// Reward categories available as shop items.
/// </summary>
array<int> NpcDesignerShopRewardTypes = {
npcBunniesQuests::RewardType::RewardAmmo, npcBunniesQuests::RewardType::RewardAmmo, npcBunniesQuests::RewardType::RewardAmmo, npcBunniesQuests::RewardType::RewardAmmo,
npcBunniesQuests::RewardType::RewardAmmo, npcBunniesQuests::RewardType::RewardAmmo, npcBunniesQuests::RewardType::RewardAmmo, npcBunniesQuests::RewardType::RewardAmmo,
npcBunniesQuests::RewardType::RewardPowerup, npcBunniesQuests::RewardType::RewardPowerup, npcBunniesQuests::RewardType::RewardPowerup, npcBunniesQuests::RewardType::RewardPowerup, npcBunniesQuests::RewardType::RewardPowerup,
npcBunniesQuests::RewardType::RewardPowerup, npcBunniesQuests::RewardType::RewardPowerup, npcBunniesQuests::RewardType::RewardPowerup,
npcBunniesQuests::RewardType::RewardFastFire
};
/// <summary>
/// Weapon subtype paired with each shop reward category.
/// </summary>
array<int> NpcDesignerShopWeaponTypes = {
WEAPON::BOUNCER, WEAPON::ICE, WEAPON::SEEKER, WEAPON::RF,
WEAPON::TOASTER, WEAPON::TNT, WEAPON::GUN8, WEAPON::GUN9,
WEAPON::BLASTER, WEAPON::BOUNCER, WEAPON::ICE, WEAPON::SEEKER, WEAPON::RF,
WEAPON::TOASTER, WEAPON::GUN8, WEAPON::GUN9,
WEAPON::BLASTER
};
/// <summary>
/// Quest categories available in the quest editor.
/// </summary>
array<int> NpcDesignerQuestTypes = {
npcBunniesQuests::QuestType::Coins,
npcBunniesQuests::QuestType::Gems, npcBunniesQuests::QuestType::Gems, npcBunniesQuests::QuestType::Gems, npcBunniesQuests::QuestType::Gems,
npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster,
npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster,
npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster,
npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster,
npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster,
npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster,
npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster,
npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster,
npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster, npcBunniesQuests::QuestType::DefeatMonster,
npcBunniesQuests::QuestType::DefeatBoss, npcBunniesQuests::QuestType::DefeatBoss, npcBunniesQuests::QuestType::DefeatBoss, npcBunniesQuests::QuestType::DefeatBoss,
npcBunniesQuests::QuestType::DefeatBoss, npcBunniesQuests::QuestType::DefeatBoss, npcBunniesQuests::QuestType::DefeatBoss, npcBunniesQuests::QuestType::DefeatBoss,
npcBunniesQuests::QuestType::DefeatBoss, npcBunniesQuests::QuestType::DefeatBoss, npcBunniesQuests::QuestType::DefeatBoss, npcBunniesQuests::QuestType::DefeatBoss
};
/// <summary>
/// Gem, monster, or boss subtype paired with each quest category.
/// </summary>
array<int> NpcDesignerQuestSubTypes = {
0,
GEM::RED, GEM::GREEN, GEM::BLUE, GEM::PURPLE,
OBJECT::BAT, OBJECT::BEEBOY, OBJECT::BEES, OBJECT::BEE,
OBJECT::BUTTERFLY, OBJECT::CRAB, OBJECT::DEMON, OBJECT::DOGGYDOGG,
OBJECT::DRAGONFLY, OBJECT::DRAGON, OBJECT::FATCHICK, OBJECT::FENCER,
OBJECT::FISH, OBJECT::HATTER, OBJECT::HELMUT, OBJECT::LABRAT,
OBJECT::FLOATLIZARD, OBJECT::XMASLIZARD, OBJECT::LIZARD, OBJECT::STANDMONKEY,
OBJECT::MONKEY, OBJECT::XMASNORMTURTLE, OBJECT::TUBETURTLE, OBJECT::TUFTURT,
OBJECT::NORMTURTLE, OBJECT::RAPIER, OBJECT::RAVEN, OBJECT::SKELETON,
OBJECT::SPARK, OBJECT::FLOATSUCKER, OBJECT::SUCKER, OBJECT::CAT,
OBJECT::PACMANGHOST, OBJECT::MOTH, OBJECT::WITCH,
OBJECT::XMASBILSY, OBJECT::BILSY, OBJECT::BOLLY, OBJECT::BUBBA,
OBJECT::DEVANROBOT, OBJECT::DEVILDEVAN, OBJECT::QUEEN, OBJECT::ROBOT,
OBJECT::ROCKETTURTLE, OBJECT::TUFBOSS, OBJECT::TWEEDLEBOSS, OBJECT::UTERUS
};
/// <summary>
/// Reward categories available in the reward editor.
/// </summary>
array<int> NpcDesignerRewardTypes = {
npcBunniesQuests::RewardType::RewardCoins,
npcBunniesQuests::RewardType::RewardGems, npcBunniesQuests::RewardType::RewardGems, npcBunniesQuests::RewardType::RewardGems, npcBunniesQuests::RewardType::RewardGems,
npcBunniesQuests::RewardType::RewardAmmo, npcBunniesQuests::RewardType::RewardAmmo, npcBunniesQuests::RewardType::RewardAmmo, npcBunniesQuests::RewardType::RewardAmmo,
npcBunniesQuests::RewardType::RewardAmmo, npcBunniesQuests::RewardType::RewardAmmo, npcBunniesQuests::RewardType::RewardAmmo, npcBunniesQuests::RewardType::RewardAmmo,
npcBunniesQuests::RewardType::RewardPowerup, npcBunniesQuests::RewardType::RewardPowerup, npcBunniesQuests::RewardType::RewardPowerup, npcBunniesQuests::RewardType::RewardPowerup,
npcBunniesQuests::RewardType::RewardPowerup, npcBunniesQuests::RewardType::RewardPowerup, npcBunniesQuests::RewardType::RewardPowerup, npcBunniesQuests::RewardType::RewardPowerup,
npcBunniesQuests::RewardType::RewardFastFire, npcBunniesQuests::RewardType::RewardTeleport, npcBunniesQuests::RewardType::RewardMoveable, npcBunniesQuests::RewardType::RewardTrigger
};
/// <summary>
/// Gem or weapon subtype paired with each reward category.
/// </summary>
array<int> NpcDesignerRewardSubTypes = {
0,
GEM::RED, GEM::GREEN, GEM::BLUE, GEM::PURPLE,
WEAPON::BOUNCER, WEAPON::ICE, WEAPON::SEEKER, WEAPON::RF,
WEAPON::TOASTER, WEAPON::TNT, WEAPON::GUN8, WEAPON::GUN9,
WEAPON::BLASTER, WEAPON::BOUNCER, WEAPON::ICE, WEAPON::SEEKER,
WEAPON::RF, WEAPON::TOASTER, WEAPON::GUN8, WEAPON::GUN9,
0, 0, 0, 0
};
/// <summary>
/// Global editor state for clamp.
/// </summary>
int NdeClamp(int value, int low, int high)
{
if(value < low) return low;
if(value > high) return high;
return value;
}
/// <summary>
/// Global editor state for float clamp.
/// </summary>
float NdeClampFloat(float value, float low, float high)
{
if(value < low) return low;
if(value > high) return high;
return value;
}
float NdeRoundTileFloat(float value)
{
return int(value * 1000 + 0.5) / 1000.0;
}
/// <summary>
/// Global editor state for min.
/// </summary>
int NdeMin(int a, int b) { return a < b ? a : b; }
/// <summary>
/// Global editor state for max.
/// </summary>
int NdeMax(int a, int b) { return a > b ? a : b; }
/// <summary>
/// Global editor state for abs.
/// </summary>
int NdeAbs(int value) { return value < 0 ? -value : value; }
/// <summary>
/// Global editor state for panel width.
/// </summary>
int NdePanelWidth()
{
int width = jjResolutionWidth / 3;
if(width < 390) width = 390;
if(width > 520) width = 520;
if(NpcDesignerView == NDE_SHOP || NpcDesignerView == NDE_QUEST || NpcDesignerView == NDE_REWARD || NpcDesignerView == NDE_HELP || NpcDesignerView == NDE_LOAD_ANIMS)
{
width = jjResolutionWidth - 48;
if(width > 760) width = 760;
}
if(width > jjResolutionWidth - 24) width = jjResolutionWidth - 24;
return width;
}
/// <summary>
/// Global editor state for panel height.
/// </summary>
int NdePanelHeight()
{
return jjResolutionHeight - 24 - NDE_PANEL_OFFSET_Y;
}
/// <summary>
/// Global editor state for panel x.
/// </summary>
int NdePanelX() { return 12 + NDE_PANEL_OFFSET_X; }
/// <summary>
/// Global editor state for panel y.
/// </summary>
int NdePanelY() { return 12 + NDE_PANEL_OFFSET_Y; }
/// <summary>
/// Global editor state for pad.
/// </summary>
int NdePad() { return 10; }
/// <summary>
/// Kept for older editor drawing code; new DialogueBox helpers wrap instead of truncating.
/// </summary>
string NdeClipSmall(const string &in text, int maxPixels)
{
return text;
}
/// <summary>
/// Returns selected text without changing inline color codes.
/// </summary>
string NdeRed(bool selected, const string &in text)
{
return text;
}
/// <summary>
/// Clears the per-frame clickable button registry.
/// </summary>
void NdeClearButtons()
{
NpcDesignerButtons.resize(0);
NpcDesignerWindow.id = "npcDesigner";
NpcDesignerWindow.title = "NPC Designer";
NpcDesignerWindow.x = NdePanelX();
NpcDesignerWindow.y = NdePanelY();
NpcDesignerWindow.w = NdePanelWidth();
NpcDesignerWindow.h = NdePanelHeight();
NpcDesignerWindow.closeButton = false;
NpcDesignerWindow.draggable = false;
NpcDesignerWindow.titleBar = false;
NpcDesignerWindow.focusIndex = NpcDesignerFocus;
DbClearControls(@NpcDesignerWindow);
}
/// <summary>
/// Registers a clickable button rectangle and action payload.
/// </summary>
void NdeAddButton(int x, int y, int w, int h, int action, int a, int b, const string &in text)
{
NpcDesignerButton@ button = @NpcDesignerButton();
button.x = x; button.y = y; button.w = w; button.h = h;
button.action = action; button.a = a; button.b = b; button.text = text;
NpcDesignerButtons.insertLast(button);
DbAddControl(@NpcDesignerWindow, x, y, w, h, action, a, b, text);
}
/// <summary>
/// Draws and registers an editor button.
/// </summary>
void NdeDrawButton(jjCANVAS@ canvas, int x, int y, int w, int h, int action, int a, int b, const string &in text, bool selected = false)
{
NdeAddButton(x, y, w, h, action, a, b, text);
int index = int(NpcDesignerButtons.length) - 1;
if(index == NpcDesignerFocus || selected)
canvas.drawRectangle(x, y + NDE_FOCUS_OFFSET_Y, w, h, selected ? 24 : 15, SPRITE::TRANSLUCENT);
string shown = selected && action == NDE_ACT_FIELD && NpcDesignerEditingValueField == a ? NpcDesignerEditingValue : text;
DbDrawWrappedSmallInBox(canvas, x, y, shown, w, h);
if(selected && action == NDE_ACT_FIELD)
DbDrawEditableSmallCursor(canvas, x, y, shown, w, y + h, NpcDesignerEditingCursor, 0);
}
/// <summary>
/// Draws small-font text right-aligned to a pixel coordinate.
/// </summary>
void NdeDrawTextBox(jjCANVAS@ canvas, int x, int y, int w, int h, int field, const string &in text, const string &in placeholder)
{
NdeAddButton(x, y, w, h, NDE_ACT_FIELD, field, 0, text);
int index = int(NpcDesignerButtons.length) - 1;
bool selected = NpcDesignerEditingField == field;
if(index == NpcDesignerFocus || selected)
canvas.drawRectangle(x, y + NDE_FOCUS_OFFSET_Y, w, h, selected ? 24 : 15, SPRITE::TRANSLUCENT);
canvas.drawRectangle(x, y, w, h, 0, SPRITE::TRANSLUCENT);
string value = selected && NpcDesignerEditingValueField == field ? NpcDesignerEditingValue : text;
bool placeholderShown = value == "";
string shown = placeholderShown ? "||" + placeholder : value;
if(selected) npcBunniesEditorViews::NdeClampActiveTextScroll(value, w - 12, h - 12);
int scrollLine = selected && NpcDesignerTextScrollField == field ? NpcDesignerTextScrollLine : 0;
npcBunniesEditorViews::NdeDrawWrappedScrolled(canvas, x + 6, y + 6, shown, w - 12, y + h - 6, scrollLine);
if(selected)
DbDrawEditableSmallCursor(canvas, x + 6, y + 6, value, w - 12, y + h - 6, NpcDesignerEditingCursor, scrollLine);
}
void NdeDrawRight(jjCANVAS@ canvas, int right, int y, const string &in text)
{
canvas.drawString(right - jjGetStringWidth(text, STRING::SMALL, STRING::NORMAL), y, text, STRING::SMALL, STRING::NORMAL);
}
/// <summary>
/// Global editor state for inside panel.
/// </summary>
bool NdeInsidePanel(int tx, int ty)
{
return tx >= NdePanelX() && tx <= NdePanelX() + NdePanelWidth() && ty >= NdePanelY() && ty <= NdePanelY() + NdePanelHeight();
}
/// <summary>
/// Toggles the NPC Designer overlay for the server.
/// </summary>
void NpcDesigner_Toggle()
{
if(!npcBunniesCore::LocalPlayerHasNpcBunniesAdminAccess()) return;
npcBunniesEditorActions::NdeFlushTextEdit();
NpcDesignerOpen = !NpcDesignerOpen;
NpcDesignerHelpOnly = false;
NpcDesignerView = NDE_MAIN;
NpcDesignerFocus = 1;
NpcDesignerEditingField = -1;
NpcDesignerEditingCursor = 0;
NpcDesignerMovingNpc = false;
npcBunniesEditorActions::NdeCancelGuideEntryEdit();
NpcDesignerIgnoreInputUntilTick = jjGameTicks + 35;
}
/// <summary>
/// Opens the NPC Designer overlay and resets transient selection state.
/// </summary>
void NpcDesigner_Open()
{
if(!npcBunniesCore::LocalPlayerHasNpcBunniesAdminAccess()) return;
npcBunniesEditorActions::NdeFlushTextEdit();
NpcDesignerOpen = true;
NpcDesignerHelpOnly = false;
NpcDesignerView = NDE_MAIN;
NpcDesignerFocus = 1;
NpcDesignerEditingField = -1;
NpcDesignerEditingCursor = 0;
NpcDesignerMovingNpc = false;
NpcDesignerDeletePick = false;
npcBunniesEditorActions::NdeCancelGuideEntryEdit();
NpcDesignerIgnoreInputUntilTick = jjGameTicks + 35;
}
/// <summary>
/// Opens the public NPC help screen without granting editor access.
/// </summary>
void NpcDesigner_OpenPublicHelp()
{
npcBunniesEditorActions::NdeFlushTextEdit();
NpcDesignerOpen = true;
NpcDesignerHelpOnly = true;
NpcDesignerView = NDE_HELP;
NpcDesignerFocus = 0;
NpcDesignerScroll = 0;
NpcDesignerEditingField = -1;
NpcDesignerEditingCursor = 0;
NpcDesignerMovingNpc = false;
NpcDesignerDeletePick = false;
npcBunniesEditorActions::NdeCancelGuideEntryEdit();
NpcDesignerIgnoreInputUntilTick = jjGameTicks + 35;
}
/// <summary>
/// Global editor state for npc designer on local chat.
/// </summary>
bool NpcDesigner_OnLocalChat(string &in text, CHAT::Type type)
{
if(jjRegexMatch(text, "^!npcHelp$", true))
{
if(jjGameTicks - NpcDesignerLastCommandTick < 20) return true;
NpcDesignerLastCommandTick = jjGameTicks;
NpcDesigner_OpenPublicHelp();
return true;
}
if(!npcBunniesCore::LocalPlayerHasNpcBunniesAdminAccess()) return false;
if(jjRegexMatch(text, "^!npcDesigner$", true) || jjRegexMatch(text, "^!npcEditor$", true) || jjRegexMatch(text, "^!npcEdit$", true))
{
if(jjGameTicks - NpcDesignerLastCommandTick < 20) return true;
NpcDesignerLastCommandTick = jjGameTicks;
NpcDesigner_Open();
return true;
}
return false;
}
/// <summary>
/// Runs editor per-tick logic while the overlay is open.
/// </summary>
void NpcDesigner_OnMain()
{
if(npcBunniesCore::LocalPlayerHasNpcBunniesAdminAccess() && !NpcDesignerCommandHintShown && jjGameTicks > 70)
{
NpcDesignerCommandHintShown = true;
jjAlert("NpcBunniesAdmin: You can open the |||||NPC Designer||| with |||!npcEdit|||||, |||!npcEditor|||||, or |||!npcDesigner|||||.", false);
}
if(NpcDesignerOpen && !NpcDesignerHelpOnly && !npcBunniesCore::LocalPlayerHasNpcBunniesAdminAccess()) { npcBunniesEditorActions::NdeCancelGuideEntryEdit(); NpcDesignerOpen = false; return; }
if(NpcDesignerTextDirty && jjGameTicks - NpcDesignerTextDirtyTick > 35) npcBunniesEditorActions::NdeFlushTextEdit();
if(!NpcDesignerOpen) return;
jjKeyChat = 5;
if(NpcDesignerView == NDE_PATH_RECORD && (NpcDesignerRecordingPath || NpcDesignerEditingTeleport)) npcBunniesEditorActions::NdeRecordPathKeys();
}
/// <summary>
/// Consumes player input and routes it to editor navigation, typing, or path editing.
/// </summary>
void NpcDesigner_OnPlayerInput(jjPLAYER@ play)
{
if(!NpcDesignerOpen || !play.isLocal || (!NpcDesignerHelpOnly && !npcBunniesCore::HasNpcBunniesAdminAccess(play))) return;
jjKeyChat = 5;
if(jjGameTicks < NpcDesignerIgnoreInputUntilTick)
{
if(!NpcDesignerAllowPlayerMovement)
{
play.keyUp = false;
play.keyDown = false;
play.keyLeft = false;
play.keyRight = false;
play.keyFire = false;
play.keySelect = false;
}
return;
}
if(NpcDesignerEditingField >= 0) npcBunniesEditorActions::NdeTypeIntoField();
if(NpcDesignerEditingField >= 0 && jjGameTicks - NpcDesignerLastKey >= 10 && NpcDesignerButtons.length > 0)
{
bool handledEditingKey = false;
if(npcBunniesEditorActions::NdeShiftKeyDown() && jjKey[0x0D])
{
npcBunniesEditorActions::NdeInsertIntoActiveField("\n");
handledEditingKey = true;
}
else if(jjKey[0x0D])
{
npcBunniesEditorActions::NdeEndTextEdit();
handledEditingKey = true;
}
else if(jjKey[0x25]) { npcBunniesEditorActions::NdeMoveEditingCursor(-1); handledEditingKey = true; }
else if(jjKey[0x27]) { npcBunniesEditorActions::NdeMoveEditingCursor(1); handledEditingKey = true; }
else if(jjKey[0x26]) { npcBunniesEditorActions::NdeMoveEditingCursorVertical(-1); handledEditingKey = true; }
else if(jjKey[0x28]) { npcBunniesEditorActions::NdeMoveEditingCursorVertical(1); handledEditingKey = true; }
if(handledEditingKey)
{
NpcDesignerLastKey = jjGameTicks;
play.keyUp = false;
play.keyDown = false;
play.keyLeft = false;
play.keyRight = false;
play.keyFire = false;
play.keySelect = false;
return;
}
}
if(!NpcDesignerAllowPlayerMovement)
{
play.keyUp = false;
play.keyDown = false;
play.keyLeft = false;
play.keyRight = false;
}
if(NpcDesignerView == NDE_PATH_RECORD && (NpcDesignerRecordingPath || NpcDesignerEditingTeleport))
{
if(NpcDesignerEditingTeleport && play.keyFire) NpcDesignerTeleportFirePressed = true;
if(!NpcDesignerAllowPlayerMovement)
{
play.keyFire = false;
play.keySelect = false;
}
return;
}
if(NpcDesignerAllowPlayerMovement && NpcDesignerEditingField < 0 && jjGameTicks - NpcDesignerLastKey >= 10 && NpcDesignerButtons.length > 0 && jjKey[0x0D])
{
NpcDesignerLastKey = jjGameTicks;
npcBunniesEditorActions::NdeActivateFocus();
return;
}
if(!NpcDesignerAllowPlayerMovement && jjGameTicks - NpcDesignerLastKey >= 10 && NpcDesignerButtons.length > 0)
{
if(NpcDesignerEditingField >= 0 && npcBunniesEditorActions::NdeShiftKeyDown() && jjKey[0x0D])
{
NpcDesignerLastKey = jjGameTicks;
npcBunniesEditorActions::NdeInsertIntoActiveField("\n");
}
else if(NpcDesignerEditingField >= 0 && jjKey[0x0D])
{
NpcDesignerLastKey = jjGameTicks;
npcBunniesEditorActions::NdeEndTextEdit();
}
else if(NpcDesignerEditingField >= 0 && jjKey[0x25])
{
NpcDesignerLastKey = jjGameTicks;
npcBunniesEditorActions::NdeMoveEditingCursor(-1);
}
else if(NpcDesignerEditingField >= 0 && jjKey[0x27])
{
NpcDesignerLastKey = jjGameTicks;
npcBunniesEditorActions::NdeMoveEditingCursor(1);
}
else if(NpcDesignerEditingField >= 0 && jjKey[0x26])
{
NpcDesignerLastKey = jjGameTicks;
npcBunniesEditorActions::NdeMoveEditingCursorVertical(-1);
}
else if(NpcDesignerEditingField >= 0 && jjKey[0x28])
{
NpcDesignerLastKey = jjGameTicks;
npcBunniesEditorActions::NdeMoveEditingCursorVertical(1);
}
else if(NpcDesignerEditingField < 0 && (jjKey[0x26] || jjKey[0x25]))
{
NpcDesignerLastKey = jjGameTicks;
NpcDesignerWindow.focusIndex = NpcDesignerFocus;
DbMoveFocus(@NpcDesignerWindow, -1);
NpcDesignerFocus = NpcDesignerWindow.focusIndex;
}
else if(NpcDesignerEditingField < 0 && (jjKey[0x28] || jjKey[0x27]))
{
NpcDesignerLastKey = jjGameTicks;
NpcDesignerWindow.focusIndex = NpcDesignerFocus;
DbMoveFocus(@NpcDesignerWindow, 1);
NpcDesignerFocus = NpcDesignerWindow.focusIndex;
}
else if(NpcDesignerEditingField < 0 && (play.keyFire || play.keySelect || jjKey[0x0D]))
{
NpcDesignerLastKey = jjGameTicks;
npcBunniesEditorActions::NdeActivateFocus();
}
}
if(!NpcDesignerAllowPlayerMovement)
{
play.keyFire = false;
play.keySelect = false;
}
}
/// <summary>
/// Draws the active NPC Designer view and processes frame-local UI interactions.
/// </summary>
}
Jazz2Online © 1999-INFINITY (Site Credits). We have a Privacy Policy. Jazz Jackrabbit, Jazz Jackrabbit 2, Jazz Jackrabbit Advance and all related trademarks and media are ™ and © Epic Games. Lori Jackrabbit is © Dean Dodrill. J2O development powered by Loops of Fury and Chemical Beats.
Eat your lima beans, Johnny.