Skip to content

Commit abaf80f

Browse files
committed
Allow editing Cadence abilities and Refinement recipes in CRUD GUI
1 parent 93a8c9a commit abaf80f

2 files changed

Lines changed: 109 additions & 46 deletions

File tree

modules/contentManager/app.py

Lines changed: 101 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,19 @@
4747
st.sidebar.warning(f"**{w['type']} [{w['name']}]**: {w['msg']}")
4848

4949

50-
def edit_list(data_list, key_prefix):
50+
def edit_list(data_list, key_prefix, item_pool=None):
51+
if item_pool is None:
52+
item_pool = [it["Name"] for i in [manager.unified_data["items"]] for it in i]
53+
5154
to_delete = None
5255
for i, entry in enumerate(data_list):
5356
col1, col2, col3 = st.columns([3, 2, 1])
5457
with col1:
55-
# Safely find index of current item
56-
item_names = [it["Name"] for i in [manager.unified_data["items"]] for it in i]
5758
current_index = 0
58-
if entry["Item"] in item_names:
59-
current_index = item_names.index(entry["Item"])
59+
if entry["Item"] in item_pool:
60+
current_index = item_pool.index(entry["Item"])
6061

61-
new_name = st.selectbox(f"Item {i}", item_names, index=current_index, key=f"{key_prefix}_name_{i}")
62+
new_name = st.selectbox(f"Item {i}", item_pool, index=current_index, key=f"{key_prefix}_name_{i}")
6263
entry["Item"] = new_name
6364

6465
with col2:
@@ -73,41 +74,75 @@ def edit_list(data_list, key_prefix):
7374
st.rerun()
7475

7576
if st.button("➕ Add Entry", key=f"{key_prefix}_add"):
76-
data_list.append({"Item": manager.unified_data["items"][0]["Name"], "Quantity": 1})
77+
data_list.append({"Item": item_pool[0], "Quantity": 1})
7778
st.rerun()
7879

79-
def edit_dict_list(data_dict, key_prefix, label_name="Stat"):
80+
def edit_recipes(recipes, key_prefix):
8081
to_delete = None
81-
keys = list(data_dict.keys())
82-
for i, key in enumerate(keys):
83-
col1, col2, col3 = st.columns([3, 2, 1])
84-
with col1:
85-
stat_names = [s["Name"] for s in manager.unified_data["stats"]]
86-
current_index = 0
87-
if key in stat_names:
88-
current_index = stat_names.index(key)
89-
90-
new_key = st.selectbox(f"{label_name} {i}", stat_names, index=current_index, key=f"{key_prefix}_key_{i}")
91-
if new_key != key:
92-
data_dict[new_key] = data_dict.pop(key)
93-
st.rerun()
82+
item_names = [i["Name"] for i in manager.unified_data["items"]]
83+
for i, recipe in enumerate(recipes):
84+
with st.container(border=True):
85+
col1, col2, col3, col4, col5 = st.columns([2, 1, 2, 1, 0.5])
86+
with col1:
87+
recipe["InputItem"] = st.selectbox("In", item_names, index=item_names.index(recipe["InputItem"]) if recipe["InputItem"] in item_names else 0, key=f"{key_prefix}_in_{i}")
88+
with col2:
89+
recipe["InputQuantity"] = st.number_input("Qty", value=recipe["InputQuantity"], min_value=1, key=f"{key_prefix}_in_q_{i}")
90+
with col3:
91+
recipe["OutputItem"] = st.selectbox("Out", item_names, index=item_names.index(recipe["OutputItem"]) if recipe["OutputItem"] in item_names else 0, key=f"{key_prefix}_out_{i}")
92+
with col4:
93+
recipe["OutputQuantity"] = st.number_input("Qty", value=recipe["OutputQuantity"], min_value=1, key=f"{key_prefix}_out_q_{i}")
94+
with col5:
95+
if st.button("🗑️", key=f"{key_prefix}_del_{i}"):
96+
to_delete = i
97+
98+
if to_delete is not None:
99+
recipes.pop(to_delete)
100+
st.rerun()
101+
102+
if st.button("➕ Add Recipe", key=f"{key_prefix}_add"):
103+
recipes.append({"InputItem": item_names[0], "InputQuantity": 1, "OutputItem": item_names[0], "OutputQuantity": 1})
104+
st.rerun()
105+
106+
def edit_cadence_abilities(abilities_list, key_prefix):
107+
to_delete = None
108+
all_ability_names = [a["Name"] for a in manager.unified_data["abilities"]]
109+
stat_names = [s["Name"] for s in manager.unified_data["stats"]]
110+
111+
for i, ab_entry in enumerate(abilities_list):
112+
with st.container(border=True):
113+
col1, col2, col3 = st.columns([3, 2, 1])
114+
with col1:
115+
# The nested structure is {"Ability": {"Name": "...", "Description": "..."}, "Requirements": [...], "PrimaryStat": "..."}
116+
current_ab_name = ab_entry["Ability"]["Name"]
117+
new_ab_name = st.selectbox(f"Ability {i}", all_ability_names, index=all_ability_names.index(current_ab_name) if current_ab_name in all_ability_names else 0, key=f"{key_prefix}_ab_{i}")
94118

95-
with col2:
96-
data_dict[new_key] = st.number_input(f"Value {i}", value=data_dict[new_key], key=f"{key_prefix}_val_{i}")
119+
if new_ab_name != current_ab_name:
120+
source_ab = next(a for a in manager.unified_data["abilities"] if a["Name"] == new_ab_name)
121+
ab_entry["Ability"]["Name"] = source_ab["Name"]
122+
ab_entry["Ability"]["Description"] = source_ab["Description"]
97123

98-
with col3:
99-
if st.button("🗑️", key=f"{key_prefix}_del_{i}"):
100-
to_delete = key
101-
124+
with col2:
125+
ab_entry["PrimaryStat"] = st.selectbox(f"Stat {i}", stat_names, index=stat_names.index(ab_entry["PrimaryStat"]) if ab_entry["PrimaryStat"] in stat_names else 0, key=f"{key_prefix}_stat_{i}")
126+
127+
with col3:
128+
if st.button("🗑️ Remove Ability", key=f"{key_prefix}_del_{i}"):
129+
to_delete = i
130+
131+
st.write("**Requirements**")
132+
edit_list(ab_entry["Requirements"], f"{key_prefix}_req_{i}")
133+
102134
if to_delete is not None:
103-
del data_dict[to_delete]
135+
abilities_list.pop(to_delete)
136+
st.rerun()
137+
138+
if st.button("➕ Add Ability to Cadence", key=f"{key_prefix}_add"):
139+
source_ab = manager.unified_data["abilities"][0]
140+
abilities_list.append({
141+
"Ability": {"Name": source_ab["Name"], "Description": source_ab["Description"]},
142+
"Requirements": [],
143+
"PrimaryStat": "Magic"
144+
})
104145
st.rerun()
105-
106-
if st.button(f"➕ Add {label_name}", key=f"{key_prefix}_add"):
107-
available = [s["Name"] for s in manager.unified_data["stats"] if s["Name"] not in data_dict]
108-
if available:
109-
data_dict[available[0]] = 1
110-
st.rerun()
111146

112147
# --- Page Rendering ---
113148

@@ -133,6 +168,11 @@ def edit_dict_list(data_dict, key_prefix, label_name="Stat"):
133168
new_item.update({"DurationSeconds": 10, "Type": "Single", "Requirements": [], "Rewards": [], "PrimaryStat": "Vitality", "RequiredStats": {}, "StatRewards": {}, "Requires": [], "UnlocksCadences": []})
134169
elif page == "Items":
135170
new_item.update({"ItemType": "Material", "Augments": []})
171+
elif page == "Cadences":
172+
new_item.update({"Abilities": []})
173+
elif page == "Refinements":
174+
new_item = {"Name": "New Refinement", "PrimaryStat": "Strength", "Recipes": []}
175+
136176
manager.unified_data[page.lower()].append(new_item)
137177
st.rerun()
138178

@@ -142,9 +182,13 @@ def edit_dict_list(data_dict, key_prefix, label_name="Stat"):
142182
with st.form(f"edit_{page}_{selected_name}"):
143183
st.subheader(f"Editing: {selected_name}")
144184

145-
name = st.text_input("Name", item["Name"])
146-
description = st.text_area("Description", item.get("Description", ""))
147-
185+
if page != "Refinements": # Refinements use 'Ability' as name, handled in data_io
186+
name = st.text_input("Name", item["Name"])
187+
description = st.text_area("Description", item.get("Description", ""))
188+
else:
189+
name = st.selectbox("Ability Base", [a["Name"] for a in manager.unified_data["abilities"]], index=[a["Name"] for a in manager.unified_data["abilities"]].index(item["Name"]) if item["Name"] in [a["Name"] for a in manager.unified_data["abilities"]] else 0)
190+
description = "" # Not used for refinements
191+
148192
if page == "Quests":
149193
col1, col2, col3 = st.columns(3)
150194
with col1:
@@ -158,25 +202,26 @@ def edit_dict_list(data_dict, key_prefix, label_name="Stat"):
158202
st.subheader("Unlocks & Dependencies")
159203
requires = st.multiselect("Prerequisite Quests", [q["Name"] for q in manager.unified_data["quests"] if q["Name"] != name], default=item["Requires"])
160204
unlocks_c = st.multiselect("Unlocks Cadences", [c["Name"] for c in manager.unified_data["cadences"]], default=item["UnlocksCadences"])
161-
162-
# Complex nested data (Requirements/Rewards) are hard in standard Streamlit forms
163-
# so we'll just show them as JSON for now or implement outside form
164-
st.info("Requirements and Rewards are managed below the form for technical reasons.")
165205

166-
if page == "Items":
206+
elif page == "Items":
167207
i_type = st.selectbox("Type", ["Material", "Currency", "Consumable", "Spell", "KeyItem"], index=["Material", "Currency", "Consumable", "Spell", "KeyItem"].index(item["ItemType"]))
208+
209+
elif page == "Refinements":
210+
stat = st.selectbox("Primary Stat", [s["Name"] for s in manager.unified_data["stats"]], index=[s["Name"] for s in manager.unified_data["stats"]].index(item["PrimaryStat"]))
168211

169212
if st.form_submit_button("Update Basic Info"):
170213
item["Name"] = name
171-
item["Description"] = description
214+
if "Description" in item: item["Description"] = description
172215
if page == "Quests":
173216
item["DurationSeconds"] = duration
174217
item["Type"] = q_type
175218
item["PrimaryStat"] = stat
176219
item["Requires"] = requires
177220
item["UnlocksCadences"] = unlocks_c
178-
if page == "Items":
221+
elif page == "Items":
179222
item["ItemType"] = i_type
223+
elif page == "Refinements":
224+
item["PrimaryStat"] = stat
180225
st.success("Updated basic info in memory.")
181226
st.rerun()
182227

@@ -193,8 +238,20 @@ def edit_dict_list(data_dict, key_prefix, label_name="Stat"):
193238

194239
st.subheader("📈 Stat Rewards")
195240
edit_dict_list(item["StatRewards"], "rew_stat")
241+
242+
elif page == "Cadences":
243+
st.subheader("⚡ Abilities")
244+
edit_cadence_abilities(item["Abilities"], "cad_ab")
245+
246+
elif page == "Refinements":
247+
st.subheader("🧪 Recipes")
248+
edit_recipes(item["Recipes"], "ref_rec")
249+
250+
elif page == "Abilities":
251+
st.info("Abilities themselves are simple Name/Description. Use the Cadence page to assign them and define requirements.")
196252

197253
if st.button("🔥 Delete Entity", type="secondary"):
198254
manager.unified_data[page.lower()].remove(item)
199255
st.warning(f"Deleted {selected_name} from memory.")
200256
st.rerun()
257+

modules/contentManager/data_io.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ def __init__(self, data_dir=DATA_DIR):
1919
"cadences": [],
2020
"locations": [],
2121
"refinements": [],
22-
"stats": []
22+
"stats": [],
23+
"abilities": []
2324
}
2425
self.load_all()
2526

@@ -36,7 +37,8 @@ def load_all(self):
3637
"items.json", "stat_augments.json", "quests.json",
3738
"quest_details.json", "quest_unlocks.json",
3839
"quest_cadence_unlocks.json", "cadences.json",
39-
"locations.json", "refinements.json", "stats.json"
40+
"locations.json", "refinements.json", "stats.json",
41+
"cadence_abilities.json"
4042
]
4143
for f in files:
4244
self.raw_data[f] = self._load_json(f)
@@ -47,6 +49,10 @@ def load_all(self):
4749
self._unify_locations()
4850
self._unify_refinements()
4951
self._unify_stats()
52+
self._unify_abilities()
53+
54+
def _unify_abilities(self):
55+
self.unified_data["abilities"] = [a.copy() for a in self.raw_data["cadence_abilities.json"]]
5056

5157
def _unify_items(self):
5258
augments = { a["Item"]: a["Augments"] for a in self.raw_data["stat_augments.json"] }

0 commit comments

Comments
 (0)