Skip to content

Commit 8c0d4c3

Browse files
committed
v1.0.4 - custom buttons and more
1 parent 75e4b14 commit 8c0d4c3

File tree

7 files changed

+157
-41
lines changed

7 files changed

+157
-41
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ Default keybind is HOME
9898
- `button` (string or Button) - Button 1, defaults to "OK"
9999
- `button2` (string or Button) - Button 2, if you want one
100100
- Button 2 is also the "cancel" button for "comment" and "mod" types
101+
- `customButtons` (array of Buttons) - Adds additional custom buttons. You probably want to provide x and y values for them
101102
- `width` (float) - Width of the popup, default is 350 (normal popup type only)
102103
- `background` (string, int, or [filename](#texture-files-can-be-read-from)) - Background color of the popup
103104
- Main ones are brown, blue, green, purple, grey, lightgrey, transparent (GJ_square0#.png)
@@ -114,6 +115,7 @@ Default keybind is HOME
114115
- `width` (float) - Custom width for the button
115116
- `height` (float) - Maybe you wanna change the height too idk
116117
- `x`, `y` (float) - Custom positioning for the button (0, 0 is the middle of the button row)
118+
- `z` (int) - Z order for the button. Buttons with a higher Z order will be placed in front of others
117119
- `scale` (float) - Scale factor for the whole button
118120
- `onClick` ([Callback](#callbacks)) - Spawns something when the button is clicked
119121
- `pulse` (object) - Enables size pulsing for the button
@@ -154,7 +156,6 @@ Extra properties exclusive to icon/shop type:
154156

155157
**Extra properties exclusive to mod type:**
156158
- `platformer` (bool) - Use moons instead of stars
157-
- This popup actually DOES function but I hardcoded it to use Generation Retro
158159

159160
Advanced example:
160161
```json

changelog.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
# 1.0.4
2+
- Added `customButtons` property for popups which allows you to add more buttons
3+
- Added `z` property for popup buttons which modify Z ordering
4+
- Added an option to spawn the queued textbox when you die in a level
5+
- Added options to rebind the Shift and Alt modifier keys
6+
- SHIFT+ESC keybind now also cancels queued textboxes
7+
- Changed "mod" popup's submit button to not actually go through
8+
- Fixed crash when button `texture` property is a nonexistent file (and also made it check more locations)
9+
110
# 1.0.3
211
- `Sound` object now supports an array of sounds to randomly choose from
312
- Improved error popup (now shows location of JSON errors)

mod.json

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
},
77
"id": "colon.customtextboxes",
88
"name": "Custom Textboxes",
9-
"version": "v1.0.3",
9+
"version": "v1.0.4",
1010
"developer": "Colon",
1111
"description": "Display custom popups, chests, and more",
1212
"resources": {
@@ -24,13 +24,13 @@
2424
"key_popup": {
2525
"type": "custom:keybind",
2626
"name": "Popup keybind",
27-
"description": "Press this key to spawn the popup defined in <cy>custom_popups.json</c>\n\n<cg>Shift + this key</c> will queue the popup\n<cg>Alt + this key</c> will spawn the secondary one.",
27+
"description": "Press this key to spawn the popup defined in <cy>custom_popups.json</c>\n\n<cg>Shift + this key</c> will queue the popup\n<cg>Alt + this key</c> will spawn the secondary one.\n<cl>(these modifier keys can be changed below)</c>",
2828
"default": 36
2929
},
3030
"key_dialogue": {
3131
"type": "custom:keybind",
3232
"name": "Dialogue keybind",
33-
"description": "Press this key to spawn the dialogue box defined in <cy>custom_dialogues.json</c>\n\n<cg>Shift + this key</c> will queue the dialogue\n<cg>Alt + this key</c> will spawn the secondary one.",
33+
"description": "Press this key to spawn the dialogue box defined in <cy>custom_dialogues.json</c>\n\n<cg>Shift + this key</c> will queue the dialogue\n<cg>Alt + this key</c> will spawn the secondary one.\n<cl>(these modifier keys can be changed below)</c>",
3434
"default": 33
3535
},
3636
"key_chest": {
@@ -52,6 +52,28 @@
5252
"description": "Plays a sound effect when a textbox is successfully queued up (by holding SHIFT)",
5353
"type": "bool",
5454
"default": false
55-
}
55+
},
56+
"onDeath": {
57+
"name": "Spawn queued on death",
58+
"description": "Also spawns the queued textbox when you die in-game. Why not.",
59+
"type": "bool",
60+
"default": false
61+
},
62+
63+
"shiftRebind": {
64+
"name": "Queue modifier key",
65+
"description": "Spawning a textbox while holding this key will queue it up instead, making it appear the next time you click a menu button.",
66+
"type": "string",
67+
"one-of": ["Shift", "Alt", "Ctrl", "Command", "None"],
68+
"default": "Shift"
69+
},
70+
71+
"altRebind": {
72+
"name": "Alt modifier key",
73+
"description": "Spawning a textbox while holding this key will spawn the alt one instead, using the <cy>to-show-alt</c> JSON key.",
74+
"type": "string",
75+
"one-of": ["Shift", "Alt", "Ctrl", "Command", "None"],
76+
"default": "Alt"
77+
}
5678
}
5779
}

src/CustomAlert.cpp

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ void CustomAlert::showPopup(std::string id)
4747
}
4848

4949
if (hasButton) {
50-
auto okContainer = iconLayer->getChildByType<CCMenu>(0);
51-
auto okParent = okContainer->getChildByType<CCMenuItemSpriteExtra>(0);
50+
auto okParent = popup->m_buttonMenu->getChildByType<CCMenuItemSpriteExtra>(0);
5251
customizeButton(okParent, popup, button1, "OK");
5352
}
5453

@@ -58,6 +57,8 @@ void CustomAlert::showPopup(std::string id)
5857

5958
setBorder(popup->m_mainLayer, data);
6059

60+
setupCustomButtons(popup, data);
61+
6162
customizeIcon(iconLayer->getChildByType<GJItemIcon>(0)->m_player, data);
6263

6364
popup->show();
@@ -92,14 +93,16 @@ void CustomAlert::showPopup(std::string id)
9293

9394

9495
// Buttons
95-
CCMenu* buttonMenu = purchaseLayer->getChildByType<CCMenu>(0);
96+
CCMenu* buttonMenu = popup->m_buttonMenu;
9697
if (hasButton) customizeButton(buttonMenu->getChildByType<CCMenuItemSpriteExtra>(1), popup, button1, "Buy");
9798
if (data.contains("button2")) customizeButton(buttonMenu->getChildByType<CCMenuItemSpriteExtra>(0), popup, data["button2"], "Cancel");
9899

99100
if (data.contains("customTexture")) setupCustomTexture(purchaseLayer, data);
100101

101102
createCloseButton(popup, data, {-124, 87});
102103

104+
setupCustomButtons(popup, data);
105+
103106
customizeIcon(purchaseLayer->getChildByType<GJItemIcon>(0)->m_player, data);
104107

105108
popup->show();
@@ -123,7 +126,11 @@ void CustomAlert::showPopup(std::string id)
123126
popup->setID("custom_modpopup"_spr);
124127
popup->show();
125128

129+
popup->m_submitButton->setTarget(popup, menu_selector(RateStarsLayer::onClose));
130+
126131
if (hasButton) customizeButton(popup->m_submitButton, popup, button1, "Submit");
132+
133+
setupCustomButtons(popup, data);
127134
}
128135

129136

@@ -148,6 +155,8 @@ void CustomAlert::showPopup(std::string id)
148155

149156
if (hasButton) customizeButton(comment->m_buttonMenu->getChildByType<CCMenuItemSpriteExtra>(-1), comment, button1, "");
150157
if (data.contains("button2")) customizeButton(comment->m_buttonMenu->getChildByType<CCMenuItemSpriteExtra>(-2), comment, data["button2"], "");
158+
159+
setupCustomButtons(comment, data);
151160
}
152161

153162

@@ -181,6 +190,8 @@ void CustomAlert::showPopup(std::string id)
181190

182191
if (hasButton) customizeButton(popup->m_buttonMenu->getChildByType<CCMenuItemSpriteExtra>(0), popup, button1, "OK");
183192
if (data.contains("button2")) customizeButton(popup->m_buttonMenu->getChildByType<CCMenuItemSpriteExtra>(1), popup, data["button2"], "Cancel");
193+
194+
setupCustomButtons(popup, data);
184195
}
185196
}
186197

@@ -247,6 +258,8 @@ void customizeButton(CCMenuItemSpriteExtra* buttonBase, CCObject* parent, matjso
247258
CCLabelBMFont* label = button->getChildByType<CCLabelBMFont>(0);
248259
if (!label) return;
249260

261+
CCScale9Sprite* slice = button->getChildByType<CCScale9Sprite>(0);
262+
250263
if (fallback == "") fallback = label->m_sInitialStringUTF8;
251264
std::string str = getText(data, fallback);
252265

@@ -255,8 +268,9 @@ void customizeButton(CCMenuItemSpriteExtra* buttonBase, CCObject* parent, matjso
255268

256269
// ====== //
257270

258-
if (data.contains("texture")) {
259-
button->updateBGImage(getStr(data, "texture").c_str());
271+
if (slice && data.contains("texture")) {
272+
auto customTexture = getCustomTexture(getStr(data, "texture").c_str(), "GJ_button_06.png", true);
273+
set9SpriteFrame(slice, customTexture); // button->updateBGImage() is very prone to crashes
260274
}
261275

262276
else if (data.contains("background")) {
@@ -281,7 +295,6 @@ void customizeButton(CCMenuItemSpriteExtra* buttonBase, CCObject* parent, matjso
281295
float w = getNum(data, "width", std::clamp(label->getContentWidth() + 14.0f, size.width, 150.0f));
282296
float h = getNum(data, "height", size.height);
283297

284-
CCScale9Sprite* slice = button->getChildByType<CCScale9Sprite>(0);
285298
if (slice && (w != size.width || h != size.height)) {
286299
buttonBase->setContentSize({w, h});
287300
label->setPositionX(w / 2.0f);
@@ -296,6 +309,7 @@ void customizeButton(CCMenuItemSpriteExtra* buttonBase, CCObject* parent, matjso
296309

297310
if (data.contains("x") && data["x"].isNumber()) buttonBase->setPositionX(getNum(data, "x", 0.0f));
298311
if (data.contains("y") && data["y"].isNumber()) buttonBase->setPositionY(getNum(data, "y", 0.0f));
312+
if (data.contains("z") && data["z"].isNumber()) buttonBase->setZOrder(getInt(data, "z", 0));
299313

300314
if (data.contains("pulse")) {
301315
auto pulseData = data["pulse"];
@@ -376,4 +390,33 @@ void setupCustomTexture(CCLayer* layer, matjson::Value data) {
376390
customSprite->setPosition(iconImg->getPosition());
377391
customSprite->setScale(scale);
378392
layer->addChild(customSprite);
393+
}
394+
395+
void setupCustomButtons(FLAlertLayer* layer, matjson::Value data) {
396+
if (!data.contains("extraButtons")) return;
397+
auto dat = data["extraButtons"];
398+
399+
if (dat.isObject()) createExtraButton(layer, dat);
400+
401+
else if (dat.isArray()) {
402+
auto arr = dat.asArray().unwrap();
403+
for (auto b : arr) {
404+
createExtraButton(layer, b);
405+
}
406+
}
407+
}
408+
409+
void createExtraButton(FLAlertLayer* layer, matjson::Value data) {
410+
// just create a default button sprite and change the properties in customizeButton()
411+
// can probably improve on this later but it works for now
412+
413+
auto msg = getText(data, "OK");
414+
auto bSprite = ButtonSprite::create(msg.c_str());
415+
if (!bSprite) return;
416+
417+
auto bItem = CCMenuItemExt::createSpriteExtra(bSprite, [layer](auto) { layer->keyBackClicked(); });
418+
bItem->setID("custom_button"_spr);
419+
420+
customizeButton(bItem, layer, data, msg);
421+
layer->m_buttonMenu->addChild(bItem);
379422
}

src/CustomAlert.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ void createCloseButton(FLAlertLayer* parent, matjson::Value data, CCPoint positi
3838
void customizeButton(CCMenuItemSpriteExtra* button, CCObject* parent, matjson::Value data, std::string fallback);
3939
void customizeIcon(CCSprite* icon, matjson::Value data);
4040

41+
void setupCustomButtons(FLAlertLayer* layer, matjson::Value data);
42+
void createExtraButton(FLAlertLayer* layer, matjson::Value data);
43+
4144
void setupCustomTexture(CCLayer* layer, matjson::Value data);
4245

4346
inline std::map<std::string, int> BUTTON_COLORS = {

src/main.cpp

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <Geode/modify/CCMenuItemSpriteExtra.hpp>
33
#include <Geode/modify/CCKeyboardDispatcher.hpp>
44
#include <Geode/modify/DialogLayer.hpp>
5+
#include <Geode/modify/PlayLayer.hpp>
56

67
#include "utils.hpp"
78
#include "CustomAlert.hpp"
@@ -38,9 +39,9 @@ void clearQueue() {
3839
queuedChest = "";
3940
}
4041

41-
void playQueueSound() {
42+
void playQueueSound(bool lower = false) {
4243
if (!Mod::get()->getSettingValue<bool>("shiftSound")) return;
43-
FMODAudioEngine::sharedEngine()->playEffect("counter003.ogg");
44+
FMODAudioEngine::sharedEngine()->playEffect("counter003.ogg", lower ? 0.7f : 1.0f, 1, 0.8f);
4445
}
4546

4647
std::string getTargetID(std::string path, bool alt) {
@@ -94,8 +95,17 @@ bool dontShowPopupHere() {
9495
return CCScene::get() == nullptr || CCScene::get()->getChildByType<KeyPickerPopup>(0) != nullptr;
9596
}
9697

97-
bool getShift() { return CCKeyboardDispatcher::get()->getShiftKeyPressed(); }
98-
bool getAlt() { return CCKeyboardDispatcher::get()->getAltKeyPressed(); }
98+
bool getModifier(std::string key) {
99+
auto val = Mod::get()->getSettingValue<std::string>(key);
100+
if (val == "Shift") return CCKeyboardDispatcher::get()->getShiftKeyPressed();
101+
if (val == "Alt") return CCKeyboardDispatcher::get()->getAltKeyPressed();
102+
if (val == "Ctrl") return CCKeyboardDispatcher::get()->getControlKeyPressed();
103+
if (val == "Command") return CCKeyboardDispatcher::get()->getCommandKeyPressed();
104+
return false;
105+
}
106+
107+
bool getShift() { return getModifier("shiftRebind"); }
108+
bool getAlt() { return getModifier("altRebind"); }
99109

100110
void prepPopup() {
101111
if (dontShowPopupHere()) return;
@@ -143,32 +153,25 @@ bool killAllAlerts() {
143153
killed = true;
144154
}
145155
}
156+
157+
// Clear queue
158+
159+
if (!killed && (!queuedChest.empty() || !queuedPopup.empty() || !queuedTextbox.empty())) {
160+
killed = true;
161+
playQueueSound(true);
162+
}
163+
clearQueue(); // to be safe
164+
146165
return killed;
147166
}
148167

149-
// Button queueing
150-
class $modify(CCMenuItemSpriteExtra) {
151-
void activate() {
152-
if (queuedPopup != "") {
153-
runPopup(queuedPopup);
154-
}
155-
else if (queuedTextbox != "") {
156-
runTextbox(queuedTextbox);
157-
}
158-
else if (queuedChest != "") {
159-
runChest(queuedChest);
160-
}
161-
else {
162-
CCMenuItemSpriteExtra::activate();
163-
}
164-
}
165-
};
166168

169+
// Handle key presses
167170
class $modify(CCKeyboardDispatcher) {
168171
bool dispatchKeyboardMSG(enumKeyCodes key, bool down, bool repeat) {
169172
if (repeat || !down || key == KEY_None || key == KEY_Unknown) return CCKeyboardDispatcher::dispatchKeyboardMSG(key, down, repeat);
170173

171-
else if (key == KEY_Escape && getShift()) {
174+
else if (key == KEY_Escape && CCKeyboardDispatcher::get()->getShiftKeyPressed()) {
172175
if (killAllAlerts()) return false;
173176
}
174177

@@ -180,6 +183,37 @@ class $modify(CCKeyboardDispatcher) {
180183
}
181184
};
182185

186+
bool playQueue() {
187+
if (queuedPopup != "") {
188+
runPopup(queuedPopup);
189+
return true;
190+
}
191+
else if (queuedTextbox != "") {
192+
runTextbox(queuedTextbox);
193+
return true;
194+
}
195+
else if (queuedChest != "") {
196+
runChest(queuedChest);
197+
return true;
198+
}
199+
return false;
200+
}
201+
202+
// Button queueing
203+
class $modify(CCMenuItemSpriteExtra) {
204+
void activate() {
205+
if (!playQueue()) CCMenuItemSpriteExtra::activate();
206+
}
207+
};
208+
209+
// Run queued textbox on death (it's funny, why not)
210+
class $modify(PlayLayer) {
211+
void destroyPlayer(PlayerObject* player, GameObject* obj) {
212+
PlayLayer::destroyPlayer(player, obj);
213+
if (obj != m_anticheatSpike && Mod::get()->getSettingValue<bool>("onDeath")) playQueue();
214+
}
215+
};
216+
183217
$on_mod(Loaded) {
184218
checkMissingFiles();
185-
}
219+
}

0 commit comments

Comments
 (0)