src/robots/rpg-shopkeeper.lisp @ 8163984906d6
Flesh out armor gen
author |
Steve Losh <steve@stevelosh.com> |
date |
Thu, 19 Jan 2017 18:23:28 +0000 |
parents |
496f6e33e468 |
children |
421231bbf89f |
(in-package :magitek.robots.rpg-shopkeeper)
(named-readtables:in-readtable :chancery)
;;;; Utils --------------------------------------------------------------------
(eval-when (:compile-toplevel :load-toplevel :execute)
(defun muffenize (str)
(symb '* (string-upcase (substitute #\- #\space str)) '*)))
;;;; General ------------------------------------------------------------------
(define-rule (bonus :distribution (:zipf :exponent 1.8))
1 2 3 4 5)
;;;; Materials ----------------------------------------------------------------
(defclass* material ()
(kind name multiplier))
(defun make-material (kind name multiplier)
(make-instance 'material :kind kind :name name :multiplier multiplier))
(defmethod print-object ((o material) s)
(print-unreadable-object (o s :type t)
(princ (material-name o) s)))
(defmacro define-material (kind name multiplier)
`(defparameter ,(muffenize name)
(make-material ,kind ,name ,multiplier)))
(define-material :metal "iron" 1.0)
(define-material :metal "steel" 1.5)
(define-material :metal "silver" 5.0)
(define-material :metal "meteoric iron" 10.0)
(define-material :metal "mithril" 50.0)
(define-material :metal "adamantine" 60.0)
(define-material :textile "cloth" 1.0)
(define-material :textile "leather" 1.5)
(define-material :textile "silk" 2.0)
(define-material :textile "spider silk" 6.0)
(define-material :wood "pine" 1.0) ; http://www.wood-database.com/wood-articles/bow-woods/
(define-material :wood "poplar" 1.2)
(define-material :wood "walnut" 1.3)
(define-material :wood "maple" 2.0)
(define-material :wood "oak" 3.0)
(define-material :wood "yew" 5.0)
(define-material :wood "rosewood" 10.0)
(define-rule (metal :distribution :zipf)
!*iron*
!*steel*
!*silver*
!*meteoric-iron*
!*mithril*
!*adamantine*)
(define-rule (textile :distribution :weighted)
(1.00 !*cloth*)
(1.00 !*leather*)
(0.80 !*silk*)
(0.01 !*spider-silk*))
(define-rule (wood :distribution (:zipf :exponent 0.8))
!*pine*
!*poplar*
!*walnut*
!*maple*
!*oak*
!*yew*
!*rosewood*)
(define-string material-picture-wood
"carved with images of"
"covered in carvings of"
"painted with pictures of")
(define-string material-picture-metal
"engraved with an image of"
"painted with images of")
(define-string material-picture-textile
"embroidered with images of")
(defun material-picture (material)
(ecase (material-kind material)
(:metal (material-picture-metal))
(:wood (material-picture-wood))
(:textile (material-picture-textile))))
;;;; Monsters -----------------------------------------------------------------
(defclass* monster ()
(singular multiplier plural adjective))
(defun make-monster (singular multiplier plural adjective)
(make-instance 'monster
:singular singular
:multiplier multiplier
:plural plural
:adjective adjective))
(defmethod print-object ((o monster) s)
(print-unreadable-object (o s :type t)
(princ (monster-singular o) s)))
(defmacro define-monster (singular multiplier plural adjective)
`(defparameter ,(muffenize singular)
(make-monster
,singular
,multiplier
,plural
,adjective)))
(define-monster "goblin" 1.00 "goblins" "goblin")
(define-monster "kobold" 1.00 "kobolds" "kobold")
(define-monster "elf" 1.00 "elves" "elven")
(define-monster "dwarf" 1.00 "dwarves" "dwarven")
(define-monster "halfling" 1.00 "halflings" "halfling")
(define-monster "gnome" 1.00 "gnomes" "gnomish")
(define-monster "gnoll" 1.10 "gnolls" "gnollish")
(define-monster "ogre" 1.20 "ogres" "ogre")
(define-monster "troll" 1.60 "trolls" "troll")
(define-monster "vampire" 5.00 "vampires" "vampire")
(define-monster "dragon" 9.00 "dragons" "dragon")
(define-rule (monster :distribution :weighted)
(1.00 !*goblin*)
(1.00 !*kobold*)
(1.00 !*elf*)
(1.00 !*dwarf*)
(1.00 !*halfling*)
(1.00 !*gnome*)
(1.00 !*ogre*)
(1.00 !*troll*)
(1.00 !*gnoll*)
(0.10 !*vampire*)
(0.01 !*dragon*))
;;;; Roles --------------------------------------------------------------------
(define-rule role
"cleric"
"warrior"
"wizard"
"rogue")
;;;; Elements -----------------------------------------------------------------
(define-rule element
("ice" "icy")
("fire" "flaming")
("electricity" "electrified")
("poison" "venomous"))
;;;; Pieces -------------------------------------------------------------------
(defclass* piece ()
(name base-value))
(defmethod print-object ((o piece) stream)
(print-unreadable-object (o stream :type t)
(princ (piece-name o) stream)))
(defmacro define-piece (name base-value)
`(defparameter ,(muffenize name)
(make-instance 'piece
:name ,name
:base-value ,base-value)))
;;;; Ornaments ----------------------------------------------------------------
(define-string ornament-scene
([monster monster-plural] "fighting" [monster monster-plural])
("a famous" [monster monster-singular] role))
(define-string word-adjective
"mysterious"
"ancient"
"glowing")
(define-string word-noun
"runes"
"symbols")
(define-string ornament-words
("covered in" word-adjective word-noun))
(define-rule (ornament :arguments (material))
!$(!(material-picture material) ornament-scene)
!$ornament-words
nil)
;;;; Enchantments -------------------------------------------------------------
(define-rule enchant-armor
(:protection monster)
(:resistance element)
(:bonus bonus))
(define-rule enchant-weapon
(:slaying monster)
(:element element)
(:bonus bonus))
(defun enchantment-multiplier (enchantment)
(declare (optimize (debug 3)))
(ecase (first enchantment)
((nil) 1.0)
((:protection :slaying) (+ 2.0 (monster-multiplier (second enchantment))))
((:resistance :element) 5.0)
(:bonus (expt 2.0 (second enchantment)))))
;;;; Armor --------------------------------------------------------------------
(defclass* armor ()
(material piece enchantment ornament))
(define-piece "scale mail" 50)
(define-piece "ring mail" 50)
(define-piece "chain mail" 150)
(define-piece "breastplate" 200)
(define-piece "plate mail" 350)
(define-rule (piece-armor :distribution (:zipf :exponent 0.6))
!*scale-mail*
!*ring-mail*
!*chain-mail*
!*breastplate*
!*plate-mail*)
(define-piece "robe" 10)
(define-piece "shirt" 5)
(define-piece "pants" 5)
(define-piece "dress" 9)
(define-piece "skirt" 5)
(define-rule piece-clothing
!*robe*
!*shirt*
!*pants*
!*dress*
!*skirt*)
(define-rule vanilla-armor
(metal piece-armor)
(textile piece-clothing))
(define-rule (armor% :distribution :weighted)
(2 (vanilla-armor nil))
(1 (vanilla-armor enchant-armor)))
(defun armor ()
(destructuring-bind ((material piece) enchantment)
(armor%)
(make-instance 'armor
:material material
:piece piece
:enchantment enchantment
:ornament (ornament material))))
(defun armor-value (armor)
(let ((enchantment (armor-enchantment armor)))
(* (+ (* (-> armor armor-piece piece-base-value)
(-> armor armor-material material-multiplier))
(if enchantment 100 0))
(enchantment-multiplier enchantment)
(if (armor-ornament armor) 1.5 1.0))))
(defgeneric enchanted-armor-description
(base enchantment-type enchantment-arguments))
(defmethod enchanted-armor-description
(base (e (eql :protection)) enchantment-args)
(destructuring-bind (monster) enchantment-args
(format nil "~A of protection from ~A" base (monster-plural monster))))
(defmethod enchanted-armor-description
(base (e (eql :resistance)) enchantment-args)
(destructuring-bind ((noun adjective)) enchantment-args
(declare (ignore adjective))
(format nil "~A of ~A resistance" base noun)))
(defmethod enchanted-armor-description
(base (e (eql :bonus)) enchantment-args)
(destructuring-bind (val) enchantment-args
(format nil "+~D ~A" val base)))
(defun vanilla-armor-description (vanilla-armor)
(format nil "~A ~A"
(-> vanilla-armor armor-material material-name)
(-> vanilla-armor armor-piece piece-name)))
(defun armor-description (armor)
(let ((vanilla-description (vanilla-armor-description armor))
(enchantment (armor-enchantment armor))
(ornament (armor-ornament armor)))
(concatenate 'string
(if enchantment
(enchanted-armor-description vanilla-description
(first enchantment)
(rest enchantment))
vanilla-description)
(if ornament
(format nil ", ~A" ornament)
""))))
; ;;;; Weapons ------------------------------------------------------------------
; (define-rule melee-weapon
; "dagger"
; "longsword"
; "short sword"
; "hand axe"
; "battleaxe"
; "spear"
; "halberd"
; "scythe"
; "scimitar"
; "lance"
; "hammer"
; "staff"
; "mace"
; "flail")
; (define-rule (bow-weapon :distribution :weighted)
; (2 "shortbow")
; (2 "longbow")
; (1 "crossbow")
; (1 "compound bow"))
; (define-rule vanilla-weapon
; (metal melee-weapon)
; (wood bow-weapon))
; (define-rule (weapon :distribution :weighted)
; (1 (vanilla-weapon nil))
; (1 (vanilla-weapon weapon-enchantment)))
; (defgeneric enchanted-weapon-description
; (base enchantment-type enchantment-arguments))
; (defmethod enchanted-weapon-description
; (base (e (eql :slaying)) enchantment-args)
; (destructuring-bind (monster) enchantment-args
; (format nil "~A of ~A-slaying" base (monster-singular monster))))
; (defmethod enchanted-weapon-description
; (base (e (eql :element)) enchantment-args)
; (destructuring-bind (element) enchantment-args
; (format nil "~A ~A" (second element) base)))
; (defmethod enchanted-weapon-description
; (base (e (eql :bonus)) enchantment-args)
; (destructuring-bind (val) enchantment-args
; (format nil "+~D ~A" val base)))
; (defun vanilla-weapon-description (vanilla-weapon)
; (destructuring-bind (material piece) vanilla-weapon
; (format nil "~A ~A" (material-name material) piece)))
; (defun weapon-description (weapon)
; (destructuring-bind (vanilla enchant) weapon
; (let ((vanilla-description (vanilla-weapon-description vanilla)))
; (if enchant
; (enchanted-weapon-description vanilla-description
; (first enchant)
; (rest enchant))
; vanilla-description))))
;;;; Flavor -------------------------------------------------------------------
(define-string sales-pitch
"Only used once!"
"Brand new!"
"The blood will wash right off..."
("I bought it from" [monster monster-adjective a] role :. ".")
"Look at the workmanship!"
"This is gonna go fast!")
;;;; Main ---------------------------------------------------------------------
(define-rule item
; !(weapon-description @weapon)
armor)
(defun item-description (item)
(etypecase item
(armor (armor-description item))))
(defun item-value (item)
(format nil "~:D"
(ceiling (etypecase item
(armor (armor-value item))))))
(define-string for-the-low-price
"only"
"just"
"yours for the low, low price of"
"for you, only"
"a steal at"
"on sale for")
(defun offer ()
(let ((item (item)))
$("FOR SALE:" [!item item-description cap] :. "."
[for-the-low-price cap] !(item-value item) "GP."
:. #\newline #\newline :.
sales-pitch)))
;;;; API ----------------------------------------------------------------------
(defun random-string ()
(offer))