diff --git a/CLAUDE.md b/CLAUDE.md index 39abf24..3137e4e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -8,7 +8,7 @@ Accessible tabletop RPG gaming engine for the Alien RPG space station USCSS CETO ## Architecture -**alien-rpg.el** (main engine, ~1370 lines, lexical-binding): +**alien-rpg.el** (main engine, ~1660 lines, lexical-binding): - **Data**: `alien-rpg-rooms` (112 rooms as connection graph), `alien-rpg-decks` (10 decks A-J), `alien-rpg-character` (mutable during session), `alien-rpg-state` (mutable, auto-saved). Station name in `alien-rpg-station-name`. - **Room IDs**: ASCII slugs (e.g., `B-ridici-stredisko`). Display names use Czech diacritics (`Řídící středisko`). @@ -18,7 +18,12 @@ Accessible tabletop RPG gaming engine for the Alien RPG space station USCSS CETO - **No průlez rooms**: Průlezy (hatches between decks) are NOT separate rooms. They are direct connections between the rooms they physically sit in. Cross-deck connections noted in room `:desc`. - **Dice calculator**: `SPC G r` — black base dice (attribute + skill) + yellow stress dice. Player rolls physical dice. - **Weapons/Armor**: Structured plists — weapons: `(:name :modifier :damage :range :ammo :weight)`, armor: `(:name :level :weight)`. -- **State**: Health, stress, resolve, story-points, injuries, conditions, weapons, armor, gear, tiny-items, notes. Auto-saves via `alien-rpg--autosave`. No buddy/rival/xp (not used in this campaign). +- **State**: Health, stress, resolve, story-points, injuries, conditions, weapons, armor, gear, tiny-items, notes, room-notes. Auto-saves via `alien-rpg--autosave`. No buddy/rival/xp (not used in this campaign). +- **Room notes**: Per-room notes stored as alist `((room-id note1 note2 ...) ...)` in `:room-notes`. Timestamped. Displayed in `where-am-i` and `find-room` output. +- **Sorting**: All `completing-read` candidate lists sorted alphabetically via `alien-rpg--sort-candidates`. +- **View mode**: `alien-rpg-view-mode` (derived from `special-mode`) applied to `*Alien RPG*` buffer with local keybindings. +- **Dispatch**: `alien-rpg-dispatch` lists all commands in completing-read for discoverability. +- **Inventory management**: Commands to remove/modify gear, weapons (including ammo), injuries, conditions, armor, tiny items. - **Character**: prof. Héctor Navarre, biochemický inženýr, 74 let. Attributes and skills editable via `SPC G e`. - **Output**: All commands output to `*Alien RPG*` buffer via `switch-to-buffer` (not `pop-to-buffer` — avoids Doom popup behavior that confuses screen readers). @@ -26,6 +31,8 @@ Accessible tabletop RPG gaming engine for the Alien RPG space station USCSS CETO | Key | Command | Function | |-----|---------|----------| +| `SPC` | Dispatch | `alien-rpg-dispatch` | +| `?` | Nápověda | `alien-rpg-help` | | `w` | Kde jsem | `alien-rpg-where-am-i` | | `m` | Přesun | `alien-rpg-move` | | `t` | Teleport | `alien-rpg-teleport` | @@ -45,10 +52,20 @@ Accessible tabletop RPG gaming engine for the Alien RPG space station USCSS CETO | `W` | Zbraň | `alien-rpg-add-weapon` | | `a` | Brnění | `alien-rpg-add-armor` | | `c` | Stav/condition | `alien-rpg-add-condition` | -| `n` | Poznámka | `alien-rpg-add-note` | -| `N` | Poznámky | `alien-rpg-show-notes` | +| `n` | Poznámka k místnosti | `alien-rpg-add-room-note` | +| `N` | Poznámky | `alien-rpg-show-room-notes` | +| `x` | Globální poznámka | `alien-rpg-add-note` | | `q` | Uložit | `alien-rpg-save-state` | | `Q` | Načíst | `alien-rpg-load-state` | +| `v g` | Spravovat výbavu | `alien-rpg-manage-gear` | +| `v w` | Spravovat zbraně | `alien-rpg-manage-weapon` | +| `v a` | Spravovat brnění | `alien-rpg-manage-armor` | +| `v j` | Spravovat zranění | `alien-rpg-manage-injury` | +| `v c` | Spravovat podmínky | `alien-rpg-manage-condition` | +| `v t` | Spravovat drobné věci | `alien-rpg-manage-tiny-items` | + +**Local keybindings** (in `*Alien RPG*` buffer via `alien-rpg-view-mode`): +`m` přesun, `w` kde jsem, `t` teleport, `s` stav, `d` paluba, `r` kostky, `f` místnost, `p` cesta, `n` poznámka k místnosti, `N` poznámky, `SPC` dispatch, `?` nápověda, `q` zavřít. **Reference docs** (org-mode, Czech): - `paluby/paluba-{A..J}.org` + `paluba-GH.org` — deck descriptions diff --git a/alien-rpg.el b/alien-rpg.el index 42eb8f7..080db55 100644 --- a/alien-rpg.el +++ b/alien-rpg.el @@ -638,7 +638,8 @@ :injuries () :conditions () :story-points 0 - :notes ()) + :notes () + :room-notes nil) "Dynamický herní stav.") (defvar alien-rpg-state-file @@ -681,6 +682,25 @@ (lambda (r) (string= (plist-get r :deck) deck-id)) alien-rpg-rooms)) +(defun alien-rpg--sort-candidates (candidates) + "Seřaď alist CANDIDATES abecedně podle car." + (sort (copy-sequence candidates) (lambda (a b) (string< (car a) (car b))))) + +(defun alien-rpg--room-notes (room-id) + "Poznámky k místnosti ROOM-ID." + (cdr (assoc room-id (plist-get alien-rpg-state :room-notes)))) + +(defun alien-rpg--output (title &rest body-fn) + "Výstup do *Alien RPG* bufferu s alien-rpg-view-mode." + (with-current-buffer (get-buffer-create "*Alien RPG*") + (let ((inhibit-read-only t)) + (erase-buffer) + (dolist (fn body-fn) + (funcall fn))) + (goto-char (point-min)) + (alien-rpg-view-mode)) + (switch-to-buffer "*Alien RPG*")) + (defun alien-rpg--skill-total (skill-key) "Celkový počet (atribut + dovednost)." (let* ((attrs (plist-get alien-rpg-character :attributes)) @@ -752,6 +772,8 @@ (setq alien-rpg-state (plist-put alien-rpg-state :resolve 4))) (unless (plist-member alien-rpg-state :tiny-items) (setq alien-rpg-state (plist-put alien-rpg-state :tiny-items nil))) + (unless (plist-member alien-rpg-state :room-notes) + (setq alien-rpg-state (plist-put alien-rpg-state :room-notes nil))) (message "Načteno: %s" file)))) (defun alien-rpg--autosave () @@ -772,11 +794,9 @@ ;; INTERAKTIVNI PRIKAZY ;; ==================================================================== -(defun alien-rpg-where-am-i () - "Kde jsem — popis pro screen reader." - (interactive) - (let* ((room (alien-rpg--current-room)) - (deck (alien-rpg--get-deck (plist-get room :deck))) +(defun alien-rpg--insert-room-info (room) + "Vlož informace o místnosti ROOM do aktuálního bufferu." + (let* ((deck (alien-rpg--get-deck (plist-get room :deck))) (my-deck (plist-get room :deck)) (connected (alien-rpg--connected-rooms room)) (same-deck (cl-remove-if-not @@ -791,43 +811,54 @@ (string-match-p "centralni-sachta" (plist-get r :id)))) connected))) + (insert (format "%s [%s]\n" (plist-get room :name) (plist-get room :id))) + (insert (format "Paluba %s: %s, %s\n" + (plist-get deck :id) (plist-get deck :name) (plist-get room :location))) + (when (plist-get room :desc) + (insert (format "%s\n" (plist-get room :desc)))) + (let ((rnotes (alien-rpg--room-notes (plist-get room :id)))) + (when rnotes + (insert "Poznámky:\n") + (dolist (rn rnotes) + (insert (format " %s\n" rn))))) + (when same-deck + (insert (format "Východy: %s\n" + (mapconcat (lambda (r) + (format "%s [%s]" + (plist-get r :name) + (plist-get r :id))) + same-deck ", ")))) + (when cross-deck + (insert (format "Průchody: %s\n" + (mapconcat (lambda (r) + (let ((d (alien-rpg--get-deck (plist-get r :deck)))) + (format "%s [%s] (paluba %s)" + (plist-get r :name) + (plist-get r :id) + (if d (plist-get d :id) (plist-get r :deck))))) + cross-deck ", ")))) + (when shaft-rooms + (let ((deck-ids (cl-remove-duplicates + (mapcar (lambda (r) (plist-get r :deck)) shaft-rooms) + :test #'string=))) + (insert (format "Šachta: %s\n" + (mapconcat (lambda (did) + (let ((d (alien-rpg--get-deck did))) + (if d + (format "%s %s" did (plist-get d :name)) + did))) + deck-ids ", "))))))) + +(defun alien-rpg-where-am-i () + "Kde jsem — popis pro screen reader." + (interactive) + (let ((room (alien-rpg--current-room))) (with-current-buffer (get-buffer-create "*Alien RPG*") (let ((inhibit-read-only t)) (erase-buffer) - (insert (format "%s [%s]\n" (plist-get room :name) (plist-get room :id))) - (insert (format "Paluba %s: %s, %s\n" - (plist-get deck :id) (plist-get deck :name) (plist-get room :location))) - (when (plist-get room :desc) - (insert (format "%s\n" (plist-get room :desc)))) - (when same-deck - (insert (format "Východy: %s\n" - (mapconcat (lambda (r) - (format "%s [%s]" - (plist-get r :name) - (plist-get r :id))) - same-deck ", ")))) - (when cross-deck - (insert (format "Průchody: %s\n" - (mapconcat (lambda (r) - (let ((d (alien-rpg--get-deck (plist-get r :deck)))) - (format "%s [%s] (paluba %s)" - (plist-get r :name) - (plist-get r :id) - (if d (plist-get d :id) (plist-get r :deck))))) - cross-deck ", ")))) - (when shaft-rooms - (let ((deck-ids (cl-remove-duplicates - (mapcar (lambda (r) (plist-get r :deck)) shaft-rooms) - :test #'string=))) - (insert (format "Šachta: %s\n" - (mapconcat (lambda (did) - (let ((d (alien-rpg--get-deck did))) - (if d - (format "%s %s" did (plist-get d :name)) - did))) - deck-ids ", ")))))) + (alien-rpg--insert-room-info room)) (goto-char (point-min)) - (special-mode)) + (alien-rpg-view-mode)) (switch-to-buffer "*Alien RPG*"))) (defun alien-rpg-move () @@ -835,9 +866,10 @@ (interactive) (let* ((room (alien-rpg--current-room)) (connected (alien-rpg--connected-rooms room)) - (candidates (mapcar (lambda (r) - (cons (alien-rpg--room-label r) (plist-get r :id))) - connected)) + (candidates (alien-rpg--sort-candidates + (mapcar (lambda (r) + (cons (alien-rpg--room-label r) (plist-get r :id))) + connected))) (choice (completing-read (format "%s -> " (plist-get room :id)) candidates nil t)) @@ -849,9 +881,10 @@ (defun alien-rpg-teleport () "Teleport kamkoliv." (interactive) - (let* ((candidates (mapcar (lambda (r) - (cons (alien-rpg--room-label r) (plist-get r :id))) - alien-rpg-rooms)) + (let* ((candidates (alien-rpg--sort-candidates + (mapcar (lambda (r) + (cons (alien-rpg--room-label r) (plist-get r :id))) + alien-rpg-rooms))) (choice (completing-read "Teleport: " candidates nil t)) (target-id (cdr (assoc choice candidates)))) (setq alien-rpg-state (plist-put alien-rpg-state :current-room target-id)) @@ -861,63 +894,18 @@ (defun alien-rpg-find-room () "Info o místnosti." (interactive) - (let* ((candidates (mapcar (lambda (r) - (cons (alien-rpg--room-label r) r)) - alien-rpg-rooms)) + (let* ((candidates (alien-rpg--sort-candidates + (mapcar (lambda (r) + (cons (alien-rpg--room-label r) r)) + alien-rpg-rooms))) (choice (completing-read "Místnost: " candidates nil t)) - (room (cdr (assoc choice candidates))) - (deck (alien-rpg--get-deck (plist-get room :deck))) - (my-deck (plist-get room :deck)) - (connected (alien-rpg--connected-rooms room)) - (same-deck (cl-remove-if-not - (lambda (r) (string= (plist-get r :deck) my-deck)) - connected)) - (shaft-rooms (cl-remove-if-not - (lambda (r) (string-match-p "centralni-sachta" - (plist-get r :id))) - connected)) - (cross-deck (cl-remove-if - (lambda (r) (or (string= (plist-get r :deck) my-deck) - (string-match-p "centralni-sachta" - (plist-get r :id)))) - connected))) + (room (cdr (assoc choice candidates)))) (with-current-buffer (get-buffer-create "*Alien RPG*") (let ((inhibit-read-only t)) (erase-buffer) - (insert (format "%s [%s]\n" (plist-get room :name) (plist-get room :id))) - (insert (format "Paluba %s: %s, %s\n" - (plist-get deck :id) (plist-get deck :name) (plist-get room :location))) - (when (plist-get room :desc) - (insert (format "%s\n" (plist-get room :desc)))) - (when same-deck - (insert (format "Východy: %s\n" - (mapconcat (lambda (r) - (format "%s [%s]" - (plist-get r :name) - (plist-get r :id))) - same-deck ", ")))) - (when cross-deck - (insert (format "Průchody: %s\n" - (mapconcat (lambda (r) - (let ((d (alien-rpg--get-deck (plist-get r :deck)))) - (format "%s [%s] (paluba %s)" - (plist-get r :name) - (plist-get r :id) - (if d (plist-get d :id) (plist-get r :deck))))) - cross-deck ", ")))) - (when shaft-rooms - (let ((deck-ids (cl-remove-duplicates - (mapcar (lambda (r) (plist-get r :deck)) shaft-rooms) - :test #'string=))) - (insert (format "Šachta: %s\n" - (mapconcat (lambda (did) - (let ((d (alien-rpg--get-deck did))) - (if d - (format "%s %s" did (plist-get d :name)) - did))) - deck-ids ", ")))))) + (alien-rpg--insert-room-info room)) (goto-char (point-min)) - (special-mode)) + (alien-rpg-view-mode)) (switch-to-buffer "*Alien RPG*"))) (defun alien-rpg-find-path () @@ -925,9 +913,10 @@ (interactive) (let* ((start (plist-get alien-rpg-state :current-room)) (start-room (alien-rpg--get-room start)) - (candidates (mapcar (lambda (r) - (cons (alien-rpg--room-label r) (plist-get r :id))) - alien-rpg-rooms)) + (candidates (alien-rpg--sort-candidates + (mapcar (lambda (r) + (cons (alien-rpg--room-label r) (plist-get r :id))) + alien-rpg-rooms))) (choice (completing-read "Cesta do: " candidates nil t)) (goal (cdr (assoc choice candidates))) (goal-room (alien-rpg--get-room goal)) @@ -958,16 +947,17 @@ (insert "\n"))) (insert "Cesta nenalezena.\n"))) (goto-char (point-min)) - (special-mode)) + (alien-rpg-view-mode)) (switch-to-buffer "*Alien RPG*"))) (defun alien-rpg-deck-overview () "Přehled paluby." (interactive) - (let* ((candidates (mapcar (lambda (d) - (cons (format "%s %s" (plist-get d :id) (plist-get d :name)) - (plist-get d :id))) - alien-rpg-decks)) + (let* ((candidates (alien-rpg--sort-candidates + (mapcar (lambda (d) + (cons (format "%s %s" (plist-get d :id) (plist-get d :name)) + (plist-get d :id))) + alien-rpg-decks))) (choice (completing-read "Paluba: " candidates nil t)) (deck-id (cdr (assoc choice candidates))) (deck (alien-rpg--get-deck deck-id)) @@ -983,7 +973,7 @@ (plist-get r :name) (plist-get r :location))))) (goto-char (point-min)) - (special-mode)) + (alien-rpg-view-mode)) (switch-to-buffer "*Alien RPG*"))) (defun alien-rpg-station-overview () @@ -1004,7 +994,7 @@ ("E" (insert " ---\n")) ("H" (insert " (průlezy G<->H)\n ---\n")))))) (goto-char (point-min)) - (special-mode)) + (alien-rpg-view-mode)) (switch-to-buffer "*Alien RPG*"))) (defun alien-rpg-key-locations () @@ -1030,7 +1020,7 @@ Průlezy F<->G: F1<->G1, F2<->G2, F5<->G5, F6<->G6, F7<->G7, F8<->G8 Průlezy G<->H: G3<->H3, G4<->H4, G7<->H7, G8<->H8, G9<->H9 ")) (goto-char (point-min)) - (special-mode)) + (alien-rpg-view-mode)) (switch-to-buffer "*Alien RPG*")) (defun alien-rpg-status () @@ -1109,7 +1099,7 @@ Průlezy G<->H: G3<->H3, G4<->H4, G7<->H7, G8<->H8, G9<->H9 ;; Signature (insert (format "Signature: %s\n" (or (plist-get ch :signature-item) "--")))) (goto-char (point-min)) - (special-mode)) + (alien-rpg-view-mode)) (switch-to-buffer "*Alien RPG*"))) (defun alien-rpg-skills () @@ -1141,7 +1131,7 @@ Průlezy G<->H: G3<->H3, G4<->H4, G7<->H7, G8<->H8, G9<->H9 (insert (format "%d %-18s (%s %d)\n" total name abbr attr))))) (insert (format "\nTalent: %s\n" (plist-get alien-rpg-character :talent)))) (goto-char (point-min)) - (special-mode)) + (alien-rpg-view-mode)) (switch-to-buffer "*Alien RPG*"))) ;; --- Upravy stavu --- @@ -1199,7 +1189,8 @@ Průlezy G<->H: G3<->H3, G4<->H4, G7<->H7, G8<->H8, G9<->H9 ("Command" . (:skills :command)) ("Manipulation" . (:skills :manipulation)) ("Medical Aid" . (:skills :medical-aid)))) - (all-names (append (mapcar #'car st-choices) (mapcar #'car attr-choices) (mapcar #'car skill-choices))) + (all-names (sort (append (mapcar #'car st-choices) (mapcar #'car attr-choices) (mapcar #'car skill-choices)) + #'string<)) (choice (completing-read "Editovat: " all-names nil t)) (st-match (assoc choice st-choices)) (attr-match (assoc choice attr-choices)) @@ -1232,18 +1223,19 @@ Průlezy G<->H: G3<->H3, G4<->H4, G7<->H7, G8<->H8, G9<->H9 "Kolik kostek hodit — vyber dovednost." (interactive) (let* ((stress (plist-get alien-rpg-state :stress)) - (choices (mapcar (lambda (sk) - (let* ((key (car sk)) - (attr-key (cdr sk)) - (name (cdr (assq key alien-rpg-skill-names))) - (attr-val (plist-get (plist-get alien-rpg-character :attributes) attr-key)) - (skill-val (plist-get (plist-get alien-rpg-character :skills) key)) - (base (+ attr-val skill-val)) - (attr-abbr (cdr (assq attr-key alien-rpg-attr-abbrevs)))) - (cons (format "%-18s %d cerne + %d zlute = %d celkem" - name base stress (+ base stress)) - (list name base attr-abbr attr-val skill-val)))) - alien-rpg-skill-attributes)) + (choices (alien-rpg--sort-candidates + (mapcar (lambda (sk) + (let* ((key (car sk)) + (attr-key (cdr sk)) + (name (cdr (assq key alien-rpg-skill-names))) + (attr-val (plist-get (plist-get alien-rpg-character :attributes) attr-key)) + (skill-val (plist-get (plist-get alien-rpg-character :skills) key)) + (base (+ attr-val skill-val)) + (attr-abbr (cdr (assq attr-key alien-rpg-attr-abbrevs)))) + (cons (format "%-18s %d cerne + %d zlute = %d celkem" + name base stress (+ base stress)) + (list name base attr-abbr attr-val skill-val)))) + alien-rpg-skill-attributes))) (choice (completing-read "Hod na: " choices nil t)) (data (cdr (assoc choice choices))) (name (nth 0 data)) @@ -1256,7 +1248,7 @@ Průlezy G<->H: G3<->H3, G4<->H4, G7<->H7, G8<->H8, G9<->H9 (insert (format "%d zlutych kostek (stress)\n" stress)) (insert (format "%d kostek celkem\n" (+ base stress)))) (goto-char (point-min)) - (special-mode)) + (alien-rpg-view-mode)) (switch-to-buffer "*Alien RPG*"))) (defun alien-rpg-add-injury (injury) @@ -1332,9 +1324,295 @@ Průlezy G<->H: G3<->H3, G4<->H4, G7<->H7, G8<->H8, G9<->H9 (dolist (n notes) (insert (format "%s\n" n))) (insert "(žádné poznámky)\n"))) (goto-char (point-min)) - (special-mode)) + (alien-rpg-view-mode)) (switch-to-buffer "*Alien RPG*")) +;; ==================================================================== +;; POZNAMKY K MISTNOSTEM +;; ==================================================================== + +(defun alien-rpg-add-room-note (note) + "Přidej poznámku k aktuální místnosti." + (interactive "sPoznámka k místnosti: ") + (let* ((room-id (plist-get alien-rpg-state :current-room)) + (room (alien-rpg--get-room room-id)) + (room-notes (plist-get alien-rpg-state :room-notes)) + (entry (assoc room-id room-notes)) + (timestamped (format "[%s] %s" (format-time-string "%H:%M") note))) + (if entry + (setcdr entry (append (cdr entry) (list timestamped))) + (setq alien-rpg-state + (plist-put alien-rpg-state :room-notes + (append room-notes (list (list room-id timestamped)))))) + (alien-rpg--autosave) + (message "%s: %s" (plist-get room :name) note))) + +(defun alien-rpg-show-room-notes () + "Zobraz všechny poznámky k místnostem." + (interactive) + (let ((room-notes (plist-get alien-rpg-state :room-notes)) + (global-notes (plist-get alien-rpg-state :notes))) + (with-current-buffer (get-buffer-create "*Alien RPG*") + (let ((inhibit-read-only t)) + (erase-buffer) + (if room-notes + (dolist (entry room-notes) + (let* ((rid (car entry)) + (notes (cdr entry)) + (room (alien-rpg--get-room rid))) + (insert (format "%s [%s]:\n" + (if room (plist-get room :name) rid) rid)) + (dolist (n notes) + (insert (format " %s\n" n))) + (insert "\n"))) + (insert "(žádné poznámky k místnostem)\n")) + (when global-notes + (insert "Globální poznámky:\n") + (dolist (n global-notes) + (insert (format " %s\n" n))))) + (goto-char (point-min)) + (alien-rpg-view-mode)) + (switch-to-buffer "*Alien RPG*"))) + +;; ==================================================================== +;; SPRAVA INVENTARE +;; ==================================================================== + +(defun alien-rpg-manage-gear () + "Spravuj výbavu — odeber předmět." + (interactive) + (let ((extra (plist-get alien-rpg-state :extra-gear))) + (if (not extra) + (message "(žádná přidaná výbava)") + (let* ((choice (completing-read "Odebrat výbavu: " extra nil t)) + (new-list (remove choice extra))) + (setq alien-rpg-state (plist-put alien-rpg-state :extra-gear new-list)) + (alien-rpg--autosave) + (message "Odebráno: %s" choice))))) + +(defun alien-rpg-manage-weapon () + "Spravuj zbraně — odeber, uprav munici, nebo přepiš." + (interactive) + (let ((weapons (plist-get alien-rpg-state :weapons))) + (if (not weapons) + (message "(žádné zbraně)") + (let* ((names (mapcar (lambda (w) + (format "%s mod%+d/DMG%d/%s/%dks" + (plist-get w :name) + (or (plist-get w :modifier) 0) + (or (plist-get w :damage) 0) + (or (plist-get w :range) "?") + (or (plist-get w :ammo) 0))) + weapons)) + (choice (completing-read "Zbraň: " names nil t)) + (idx (cl-position choice names :test #'string=)) + (weapon (nth idx weapons)) + (action (completing-read + (format "%s: " (plist-get weapon :name)) + '("Munice +/-" "Odebrat" "Upravit") nil t))) + (cond + ((string= action "Munice +/-") + (let* ((current (or (plist-get weapon :ammo) 0)) + (delta (read-number (format "Munice [%d] +/-: " current) -1)) + (new-ammo (max 0 (+ current delta)))) + (plist-put weapon :ammo new-ammo) + (alien-rpg--autosave) + (message "%s munice: %d (%s%d)" + (plist-get weapon :name) new-ammo + (if (>= delta 0) "+" "") delta))) + ((string= action "Odebrat") + (setq alien-rpg-state + (plist-put alien-rpg-state :weapons + (append (cl-subseq weapons 0 idx) + (cl-subseq weapons (1+ idx))))) + (alien-rpg--autosave) + (message "Odebráno: %s" (plist-get weapon :name))) + ((string= action "Upravit") + (let* ((name (read-string "Zbraň: " (plist-get weapon :name))) + (modifier (read-number "Modifier: " (or (plist-get weapon :modifier) 0))) + (damage (read-number "Damage: " (or (plist-get weapon :damage) 1))) + (range (completing-read "Range: " + '("Engaged" "Short" "Medium" "Long" "Extreme") nil t + nil nil (or (plist-get weapon :range) "Short"))) + (ammo (read-number "Ammo: " (or (plist-get weapon :ammo) 0))) + (weight (read-number "Weight: " (or (plist-get weapon :weight) 1)))) + (plist-put weapon :name name) + (plist-put weapon :modifier modifier) + (plist-put weapon :damage damage) + (plist-put weapon :range range) + (plist-put weapon :ammo ammo) + (plist-put weapon :weight weight) + (alien-rpg--autosave) + (message "Upraveno: %s mod%+d/DMG%d/%s" name modifier damage range)))))))) + +(defun alien-rpg-manage-injury () + "Odeber zranění." + (interactive) + (let ((injuries (plist-get alien-rpg-state :injuries))) + (if (not injuries) + (message "(žádná zranění)") + (let* ((choice (completing-read "Odebrat zranění: " injuries nil t)) + (new-list (remove choice injuries))) + (setq alien-rpg-state (plist-put alien-rpg-state :injuries new-list)) + (alien-rpg--autosave) + (message "Vyléčeno: %s" choice))))) + +(defun alien-rpg-manage-condition () + "Odeber stav/podmínku." + (interactive) + (let ((conditions (plist-get alien-rpg-state :conditions))) + (if (not conditions) + (message "(žádné stavy)") + (let* ((choice (completing-read "Odebrat stav: " conditions nil t)) + (new-list (remove choice conditions))) + (setq alien-rpg-state (plist-put alien-rpg-state :conditions new-list)) + (alien-rpg--autosave) + (message "Odebráno: %s" choice))))) + +(defun alien-rpg-manage-armor () + "Odeber brnění." + (interactive) + (let ((armor (plist-get alien-rpg-state :armor))) + (if (not armor) + (message "(žádné brnění)") + (when (y-or-n-p (format "Odebrat %s? " (plist-get armor :name))) + (setq alien-rpg-state (plist-put alien-rpg-state :armor nil)) + (alien-rpg--autosave) + (message "Brnění odebráno."))))) + +(defun alien-rpg-manage-tiny-items () + "Odeber drobný předmět." + (interactive) + (let ((items (plist-get alien-rpg-state :tiny-items))) + (if (not items) + (message "(žádné drobné předměty)") + (let* ((choice (completing-read "Odebrat: " items nil t)) + (new-list (remove choice items))) + (setq alien-rpg-state (plist-put alien-rpg-state :tiny-items new-list)) + (alien-rpg--autosave) + (message "Odebráno: %s" choice))))) + +;; ==================================================================== +;; DISPATCH, HELP, VIEW MODE +;; ==================================================================== + +(defvar alien-rpg--dispatch-commands + '(("Brnění — přidat" . alien-rpg-add-armor) + ("Brnění — spravovat" . alien-rpg-manage-armor) + ("Deck přehled" . alien-rpg-deck-overview) + ("Dovednosti" . alien-rpg-skills) + ("Editovat stat" . alien-rpg-set-stat) + ("Health +/-" . alien-rpg-set-health) + ("Kde jsem" . alien-rpg-where-am-i) + ("Klíčová místa" . alien-rpg-key-locations) + ("Kostky" . alien-rpg-dice) + ("Načíst stav" . alien-rpg-load-state) + ("Nápověda" . alien-rpg-help) + ("Najít cestu" . alien-rpg-find-path) + ("Najít místnost" . alien-rpg-find-room) + ("Podmínka — přidat" . alien-rpg-add-condition) + ("Podmínka — odebrat" . alien-rpg-manage-condition) + ("Poznámka globální" . alien-rpg-add-note) + ("Poznámka k místnosti" . alien-rpg-add-room-note) + ("Poznámky" . alien-rpg-show-room-notes) + ("Přehled stanice" . alien-rpg-station-overview) + ("Přesun" . alien-rpg-move) + ("Resolve +/-" . alien-rpg-set-resolve) + ("Stav postavy" . alien-rpg-status) + ("Stress +/-" . alien-rpg-set-stress) + ("Teleport" . alien-rpg-teleport) + ("Uložit stav" . alien-rpg-save-state) + ("Výbava — přidat" . alien-rpg-add-gear) + ("Výbava — spravovat" . alien-rpg-manage-gear) + ("Zbraň — přidat" . alien-rpg-add-weapon) + ("Zbraň — spravovat" . alien-rpg-manage-weapon) + ("Zranění — přidat" . alien-rpg-add-injury) + ("Zranění — odebrat" . alien-rpg-manage-injury)) + "Všechny příkazy pro dispatch.") + +(defun alien-rpg-dispatch () + "Vyber příkaz ze seznamu." + (interactive) + (let* ((names (mapcar #'car alien-rpg--dispatch-commands)) + (choice (completing-read "Příkaz: " names nil t)) + (fn (cdr (assoc choice alien-rpg--dispatch-commands)))) + (call-interactively fn))) + +(defun alien-rpg-help () + "Zobraz nápovědu — klávesové zkratky." + (interactive) + (with-current-buffer (get-buffer-create "*Alien RPG*") + (let ((inhibit-read-only t)) + (erase-buffer) + (insert "Alien RPG — klávesové zkratky\n\n") + (insert "SPC G SPC Dispatch (všechny příkazy)\n") + (insert "SPC G ? Tato nápověda\n\n") + (insert "--- Navigace ---\n") + (insert "SPC G w Kde jsem\n") + (insert "SPC G m Přesun (sousední místnost)\n") + (insert "SPC G t Teleport (kamkoliv)\n") + (insert "SPC G f Najít místnost (info)\n") + (insert "SPC G p Najít cestu\n") + (insert "SPC G d Přehled paluby\n") + (insert "SPC G o Přehled stanice\n") + (insert "SPC G k Klíčová místa\n\n") + (insert "--- Postava ---\n") + (insert "SPC G s Stav postavy (herní karta)\n") + (insert "SPC G i Dovednosti (seřazené)\n") + (insert "SPC G h Health +/-\n") + (insert "SPC G S Stress +/-\n") + (insert "SPC G r Kostky (dice calc)\n") + (insert "SPC G e Editovat stat/skill\n\n") + (insert "--- Inventář přidat ---\n") + (insert "SPC G g Přidat výbavu\n") + (insert "SPC G W Přidat zbraň\n") + (insert "SPC G a Přidat brnění\n") + (insert "SPC G j Přidat zranění\n") + (insert "SPC G c Přidat podmínku\n\n") + (insert "--- Inventář spravovat ---\n") + (insert "SPC G v g Spravovat výbavu\n") + (insert "SPC G v w Spravovat zbraně\n") + (insert "SPC G v a Spravovat brnění\n") + (insert "SPC G v j Spravovat zranění\n") + (insert "SPC G v c Spravovat podmínky\n") + (insert "SPC G v t Spravovat drobné věci\n\n") + (insert "--- Poznámky ---\n") + (insert "SPC G n Poznámka k místnosti\n") + (insert "SPC G N Zobrazit poznámky\n") + (insert "SPC G x Globální poznámka\n\n") + (insert "--- Uložení ---\n") + (insert "SPC G q Uložit\n") + (insert "SPC G Q Načíst\n\n") + (insert "--- V bufferu *Alien RPG* ---\n") + (insert "m přesun | w kde jsem | t teleport | s stav\n") + (insert "d paluba | r kostky | f místnost | p cesta\n") + (insert "n poznámka k místnosti | N poznámky | SPC dispatch\n") + (insert "? tato nápověda | q zavřít\n")) + (goto-char (point-min)) + (alien-rpg-view-mode)) + (switch-to-buffer "*Alien RPG*")) + +(defvar alien-rpg-view-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map special-mode-map) + (define-key map "m" #'alien-rpg-move) + (define-key map "w" #'alien-rpg-where-am-i) + (define-key map "t" #'alien-rpg-teleport) + (define-key map "s" #'alien-rpg-status) + (define-key map "d" #'alien-rpg-deck-overview) + (define-key map "r" #'alien-rpg-dice) + (define-key map "p" #'alien-rpg-find-path) + (define-key map "f" #'alien-rpg-find-room) + (define-key map "n" #'alien-rpg-add-room-note) + (define-key map "N" #'alien-rpg-show-room-notes) + (define-key map " " #'alien-rpg-dispatch) + (define-key map "?" #'alien-rpg-help) + map) + "Keymap pro *Alien RPG* buffer.") + +(define-derived-mode alien-rpg-view-mode special-mode "Alien-RPG" + "Režim pro *Alien RPG* buffer. Klávesy: m w t s d r p f n N SPC ?") + ;; ==================================================================== ;; DOOM EMACS KEYBINDINGS ;; ==================================================================== @@ -1342,6 +1620,8 @@ Průlezy G<->H: G3<->H3, G4<->H4, G7<->H7, G8<->H8, G9<->H9 (with-eval-after-load 'doom-keybinds (map! :leader (:prefix ("G" . "Alien RPG") + :desc "Dispatch" "SPC" #'alien-rpg-dispatch + :desc "Nápověda" "?" #'alien-rpg-help :desc "Kde jsem" "w" #'alien-rpg-where-am-i :desc "Přesun" "m" #'alien-rpg-move :desc "Teleport" "t" #'alien-rpg-teleport @@ -1361,10 +1641,18 @@ Průlezy G<->H: G3<->H3, G4<->H4, G7<->H7, G8<->H8, G9<->H9 :desc "Zbran" "W" #'alien-rpg-add-weapon :desc "Brneni" "a" #'alien-rpg-add-armor :desc "Stav/condition" "c" #'alien-rpg-add-condition - :desc "Poznámka" "n" #'alien-rpg-add-note - :desc "Poznamky" "N" #'alien-rpg-show-notes + :desc "Pozn. místnost" "n" #'alien-rpg-add-room-note + :desc "Poznamky" "N" #'alien-rpg-show-room-notes + :desc "Glob. pozn." "x" #'alien-rpg-add-note :desc "Uložit" "q" #'alien-rpg-save-state - :desc "Načíst" "Q" #'alien-rpg-load-state))) + :desc "Načíst" "Q" #'alien-rpg-load-state + (:prefix ("v" . "Inventář") + :desc "Výbava" "g" #'alien-rpg-manage-gear + :desc "Zbraně" "w" #'alien-rpg-manage-weapon + :desc "Brnění" "a" #'alien-rpg-manage-armor + :desc "Zranění" "j" #'alien-rpg-manage-injury + :desc "Podmínky" "c" #'alien-rpg-manage-condition + :desc "Drobné věci" "t" #'alien-rpg-manage-tiny-items)))) (provide 'alien-rpg) ;;; alien-rpg.el ends here