|
360 | 360 | [:set-character character] |
361 | 361 | [::char5e/set-character id character]]}))) |
362 | 362 |
|
| 363 | +(defn descriptive-character-label |
| 364 | + "Build a descriptive label like 'High Elf Ranger 3' from character properties. |
| 365 | + Used as the summary name when the user hasn't set a character name." |
| 366 | + [race subrace classes levels] |
| 367 | + (let [race-part (or subrace race) |
| 368 | + class-parts (when (seq classes) |
| 369 | + (s/join "/" |
| 370 | + (map (fn [cls] |
| 371 | + (let [{:keys [class-name class-level]} (levels cls)] |
| 372 | + (str class-name " " class-level))) |
| 373 | + classes)))] |
| 374 | + (cond |
| 375 | + (and race-part class-parts) (str race-part " " class-parts) |
| 376 | + race-part race-part |
| 377 | + class-parts class-parts |
| 378 | + :else "Adventurer"))) |
| 379 | + |
363 | 380 | (defn make-summary [built-char] |
364 | 381 | (let [classes (char5e/classes built-char) |
365 | 382 | levels (char5e/levels built-char) |
|
375 | 392 | hair (char5e/hair built-char) |
376 | 393 | eyes (char5e/eyes built-char) |
377 | 394 | skin (char5e/skin built-char) |
378 | | - ;alignment (char5e/get-prop built-char ::alignment) ;This is not available? |
379 | | - ;background (char5e/get-prop built-char ::background) ;This is not available? |
380 | | - ] |
381 | | - (cond-> {::char5e/character-name (or character-name "")} |
| 395 | + ;; When user hasn't set a name, auto-generate a descriptive label |
| 396 | + ;; for the summary (what lists/parties display). |
| 397 | + display-name (if (s/blank? character-name) |
| 398 | + (descriptive-character-label race subrace classes levels) |
| 399 | + character-name)] |
| 400 | + (cond-> {::char5e/character-name display-name} |
382 | 401 | image-url (assoc ::char5e/image-url image-url) |
383 | 402 | faction-image-url (assoc ::char5e/faction-image-url faction-image-url) |
384 | 403 | race (assoc ::char5e/race-name race) |
|
433 | 452 | {:dispatch [:show-error-message "You must provide values for all ability scores"]})))))) |
434 | 453 |
|
435 | 454 | ;; Manual save — dispatched from character builder UI with built-char in scope. |
| 455 | +;; If the user hasn't set a name, generates a random one and persists it. |
436 | 456 | (reg-event-fx |
437 | 457 | :save-character |
438 | 458 | (fn [{:keys [db]} [_ built-character]] |
439 | | - (let [{:keys [:db/id] :as strict} (char5e/to-strict (:character db)) |
440 | | - summary (make-summary built-character)] |
| 459 | + (let [character-name (char5e/character-name built-character) |
| 460 | + needs-name? (s/blank? character-name) |
| 461 | + ;; Generate a random name for unnamed characters on manual save |
| 462 | + rand-name (when needs-name? (generate-random-name built-character)) |
| 463 | + ;; Update entity in db so the name persists across future edits |
| 464 | + db' (if needs-name? |
| 465 | + (assoc-in db [:character ::entity/values ::char5e/character-name] rand-name) |
| 466 | + db) |
| 467 | + {:keys [:db/id] :as strict} (char5e/to-strict (:character db')) |
| 468 | + summary (cond-> (make-summary built-character) |
| 469 | + ;; Override summary name with the generated name |
| 470 | + ;; (make-summary produced a descriptive label since entity was blank) |
| 471 | + needs-name? (assoc ::char5e/character-name rand-name))] |
441 | 472 | (if (every? |
442 | 473 | (fn [ability-kw] |
443 | 474 | (nat-int? (get-in built-character [:base-abilities ability-kw]))) |
444 | 475 | char5e/ability-keys) |
445 | | - {:dispatch [:set-loading true] |
| 476 | + {:db db' |
| 477 | + :dispatch [:set-loading true] |
446 | 478 | :http {:method :post |
447 | | - :headers (authorization-headers db) |
| 479 | + :headers (authorization-headers db') |
448 | 480 | :url (url-for-route routes/dnd-e5-char-list-route) |
449 | 481 | :transit-params (assoc strict :orcpub.entity.strict/summary summary) |
450 | 482 | :on-success [:character-save-success]}} |
|
1191 | 1223 | character-interceptors |
1192 | 1224 | update-value-field) |
1193 | 1225 |
|
| 1226 | +(defn generate-random-name |
| 1227 | + "Generate a random name from the built character's race/subrace/sex. |
| 1228 | + Falls back to a random human name for unsupported or custom races." |
| 1229 | + [built-char] |
| 1230 | + (let [race-kw (common/name-to-kw (char5e/race built-char) "orcpub.dnd.e5.character.random") |
| 1231 | + subrace-kw (common/name-to-kw (char5e/subrace built-char) "orcpub.dnd.e5.character.random") |
| 1232 | + sex-kw (common/name-to-kw (char5e/sex built-char) "orcpub.dnd.e5.character.random")] |
| 1233 | + (:name (char-rand5e/random-name-result |
| 1234 | + {:race race-kw |
| 1235 | + :subrace (when (= ::char-rand5e/human race-kw) subrace-kw) |
| 1236 | + :sex sex-kw})))) |
| 1237 | + |
1194 | 1238 | ;; Generate a random name based on character's race/subrace/sex. |
1195 | 1239 | ;; built-char passed from component (description-fields). |
1196 | 1240 | (reg-event-fx |
1197 | 1241 | ::char5e/set-random-name |
1198 | 1242 | (fn [_ [_ built-char]] |
1199 | | - (let [race-name (char5e/race built-char) |
1200 | | - race-kw (common/name-to-kw race-name "orcpub.dnd.e5.character.random") |
1201 | | - subrace-name (char5e/subrace built-char) |
1202 | | - subrace-kw (common/name-to-kw subrace-name "orcpub.dnd.e5.character.random") |
1203 | | - sex (char5e/sex built-char) |
1204 | | - sex-kw (common/name-to-kw sex "orcpub.dnd.e5.character.random")] |
1205 | | - {:dispatch [:update-value-field ::char5e/character-name (:name |
1206 | | - (char-rand5e/random-name-result |
1207 | | - {:race race-kw |
1208 | | - :subrace (when (= ::char-rand5e/human race-kw) subrace-kw) |
1209 | | - :sex sex-kw}))]}))) |
| 1243 | + {:dispatch [:update-value-field ::char5e/character-name |
| 1244 | + (generate-random-name built-char)]})) |
1210 | 1245 | (reg-event-db |
1211 | 1246 | :select-option |
1212 | 1247 | character-interceptors |
|
0 commit comments