being.go 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308
  1. package world
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/beoran/woe/sitef"
  6. "github.com/beoran/woe/monolog"
  7. "math"
  8. )
  9. /* Aptitudes of a being, species or profession */
  10. type Aptitudes struct {
  11. Skills []BeingSkill
  12. Arts []BeingArt
  13. Techniques []BeingTechnique
  14. Exploits []BeingExploit
  15. }
  16. /* Kind of a being or "Kin" for short*/
  17. type Kin struct {
  18. Entity
  19. // Talent modifiers of the species
  20. Talents
  21. // Vitals modifiers of the species
  22. Vitals
  23. Aptitudes
  24. // Arts multiplier in %. If zero arts cannot be used.
  25. Arts float64
  26. // Technique multiplier in %. If zero techniques cannot be used.
  27. Techniques float64
  28. // Learning speed in %
  29. Learning float64
  30. // How much of the being is mechanical.
  31. // Affects healing arts and medication, and the ability to install parts.
  32. Mechanical float64
  33. // Level of Corruption
  34. Corruption float64
  35. // Level of "unliving", i,e, previously alive, matter in the being
  36. Unlife float64
  37. }
  38. func NewKin(id string, name string) * Kin {
  39. res := new(Kin)
  40. res.ID = id;
  41. res.Name = name
  42. return res
  43. }
  44. /* Kin modifier display as a string */
  45. func (me Kin) ToKinModifiers() string {
  46. return fmt.Sprintf("ARTS : %4.2f TECHS: %4.2f LEARN: %4.2f\n" +
  47. "MECHA: %4.2f CORRU: %4.2f UNLIF: %4.2f",
  48. me.Arts, me.Techniques, me.Learning, me.Mechanical,
  49. me.Corruption, me.Unlife)
  50. }
  51. /* Help for a kin */
  52. func (me Kin) AskLong() string {
  53. return me.Long + "\n\nTalent modifiers for " + me.Name +
  54. " kin:\n" + me.ToTalents() + "\n\nKin modifiers for " + me.Name +
  55. " kin:\n" + me.ToKinModifiers() + "\n"
  56. }
  57. /* Job of a being */
  58. type Job struct {
  59. Entity
  60. // Talent modifiers of the profession
  61. Talents
  62. // Vitals modifiers of the profession
  63. Vitals
  64. // Map of skills that this job starts with and their levels.
  65. Skills map[string] int
  66. // Same for arts and techniques and exploits
  67. Arts map[string] int
  68. Techniques map[string] int
  69. Exploits map[string] int
  70. // if a player can choose this or not
  71. Playable bool
  72. }
  73. /* Help for a job */
  74. func (me Job) AskLong() string {
  75. return me.Long + "\n\nTalent modifiers for " + me.Name +
  76. " job:\n" + me.ToTalents() + "\n"
  77. }
  78. /* Gender of a being */
  79. type Gender struct {
  80. Entity
  81. // Talent modifiers of the gender
  82. Talents
  83. // Vitals modifiers of the gender
  84. Vitals
  85. }
  86. /* Help for a gender */
  87. func (me Gender) AskLong() string {
  88. return me.Long + "\n\nGender modifiers for " + me.Name +
  89. " gender:\n" + me.ToTalents() + "\n"
  90. }
  91. /* Struct, list and map of all genders in WOE. */
  92. var Genders = struct {
  93. Female Gender
  94. Male Gender
  95. Intersex Gender
  96. Genderless Gender
  97. }{
  98. Gender {
  99. Entity : Entity{ID: "gender_female", Name: "Female",
  100. Short: "Female gender",
  101. Long: "No matter the day and age, there are still plenty of beings who are female. Females are slighly more agile and charismatic than those who have another gender.",
  102. },
  103. Talents : Talents {Agility: 1, Charisma: 1 },
  104. },
  105. Gender {
  106. Entity : Entity{ID: "gender_male", Name: "Male",
  107. Short: "Male gender",
  108. Long: "No matter the day and age, there are still plenty of beings who are male. Males are slighly more strong and studious than those who have another gender.",
  109. },
  110. Talents : Talents {Strength: 1, Intelligence: 1 },
  111. },
  112. Gender {
  113. Entity : Entity{ID: "gender_intersex", Name: "Intersex",
  114. Short: "Intersexed",
  115. Long: "Not every being can be clearly defined as being male or female. Sometimes, certain beings end up characteristics of both. Intersexed are slighly more dexterous and wise than those who have another gender.",
  116. },
  117. Talents : Talents {Dexterity: 1, Wisdom: 1 },
  118. },
  119. Gender {
  120. Entity : Entity{ID: "gender_none", Name: "Genderless",
  121. Short: "No gender",
  122. Long: "Some beings lack reproductive sytems and are therefore genderless. Genderless are slighly more tough and emotionally balanced than those who have another gender.",
  123. },
  124. Talents : Talents {Toughness: 1, Emotion: 1 },
  125. },
  126. }
  127. func EntitylikeToGender(me Entitylike) (*Gender) {
  128. v, ok := me.(*Gender)
  129. if ok {
  130. return v
  131. } else {
  132. return nil
  133. }
  134. }
  135. type EntitylikeSlice []Entitylike
  136. var GenderList = []Gender{Genders.Female, Genders.Male,
  137. Genders.Intersex, Genders.Genderless }
  138. var GenderEntityList = EntitylikeSlice{&Genders.Female, &Genders.Male,
  139. &Genders.Intersex, &Genders.Genderless }
  140. var GenderMap = map[string]*Gender {
  141. Genders.Female.ID : &Genders.Female,
  142. Genders.Male.ID : &Genders.Male,
  143. Genders.Intersex.ID : &Genders.Intersex,
  144. Genders.Genderless.ID : &Genders.Genderless,
  145. }
  146. type EntityIterator interface {
  147. Each(cb func (Entitylike) (Entitylike)) (Entitylike)
  148. }
  149. func (me EntitylikeSlice) Each(cb func (Entitylike) (Entitylike)) (Entitylike) {
  150. for i := 0; i < len(me) ; i++ {
  151. res := cb(me[i])
  152. if (res != nil) {
  153. return res
  154. }
  155. }
  156. return nil
  157. }
  158. func (me EntitylikeSlice) Filter(cb func (Entitylike) (Entitylike)) (EntitylikeSlice) {
  159. result := make(EntitylikeSlice, 0)
  160. for i := 0; i < len(me) ; i++ {
  161. res := cb(me[i])
  162. if (res != nil) {
  163. result = append(result, res)
  164. }
  165. }
  166. return result
  167. }
  168. /* Finds the name irrespecful of the case */
  169. func (me EntitylikeSlice) FindName(name string) (Entitylike) {
  170. return me.Each(func (e Entitylike) (Entitylike) {
  171. if strings.ToLower(e.AsEntity().Name) == strings.ToLower(name) {
  172. return e
  173. } else {
  174. return nil
  175. }
  176. })
  177. }
  178. /* Finds the ID */
  179. func (me EntitylikeSlice) FindID(id string) (Entitylike) {
  180. if id == "" {
  181. return nil
  182. }
  183. return me.Each(func (e Entitylike) (Entitylike) {
  184. if strings.ToLower(e.AsEntity().ID) == id {
  185. return e
  186. } else {
  187. return nil
  188. }
  189. })
  190. }
  191. /* Filters the list by privilege level (only those allowed by the level are retained) */
  192. func (me EntitylikeSlice) FilterPrivilege(privilege Privilege) (EntitylikeSlice) {
  193. return me.Filter(func (e Entitylike) (Entitylike) {
  194. if (e.AsEntity().Privilege <= privilege) {
  195. return e
  196. } else {
  197. return nil
  198. }
  199. })
  200. }
  201. /* All Kins of WOE */
  202. var KinList = [] Kin {
  203. Kin {
  204. Entity: Entity {
  205. ID: "kin_human", Name: "Human",
  206. Short: "The primordial conscious beings on Earth.",
  207. Long:
  208. `Humans are the primordial kind of conscious beings on Earth.
  209. They excel at nothing in particular, but are fast learners.`,
  210. },
  211. // No talents because humans get no talent bonuses
  212. // No stats either because no bonuses there either.
  213. Arts : 1.0,
  214. Techniques : 1.0,
  215. Learning: 1.5,
  216. },
  217. {
  218. Entity: Entity {
  219. ID: "kin_neosa", Name: "Neosa",
  220. Short: "Nimble beings, skilled in the Arts.",
  221. Long:
  222. `Neosa are descendents of humans genetically modified to be lite, agile
  223. and skilled with the Numen Arts. They are less tough and strong, and less adept
  224. with techniques. They can be recognized by their long and pointy ears.`,
  225. },
  226. // AGI+1 EMO+1 STR-1 TOU-1
  227. Talents : Talents {Strength : -1, Toughness: -1,
  228. Agility : 1, Emotion : 1, },
  229. Arts : 1.2,
  230. Techniques : 0.8,
  231. Learning : 1.0,
  232. },
  233. {
  234. Entity: Entity {
  235. ID: "kin_mantu", Name: "Mantu",
  236. Short: "Hardy, stocky, furry beings, skilled in the Techniques.",
  237. Long:
  238. `Mantu are descendents of humans genetically modified to be hardy, stocky
  239. and skilled with Techniques. They are somewhat less agine and less adept with
  240. Numen Arts than humans. They have a soft fur which covers their whole body.`,
  241. },
  242. // STR+1 1 TOU+1 AGI-1 EMO-1
  243. Talents : Talents {Strength : +1, Toughness: +1,
  244. Agility : -1, Emotion : -1, },
  245. Arts : 0.8,
  246. Techniques : 1.2,
  247. Learning : 1.0,
  248. },
  249. {
  250. Entity: Entity {
  251. ID: "kin_cyborg", Name: "Cyborg",
  252. Short: "Human enhanced with robotic parts. ",
  253. Long:
  254. `Cyborgs are humans who either through neccesity or through their own will,
  255. have been enhanced with robotic parts. They are far more skilled with
  256. Techniques, and can install some Parts, but their Nummen arts are only half
  257. as effective. They are partially mechanical and healing arts and medication
  258. is not as effective on them, but they can be repaired.`,
  259. },
  260. // STR+1 1 TOU+1 DEX+1 INT+1
  261. Talents : Talents {Strength : +1, Toughness: +1,
  262. Dexterity : +1, Intelligence: +1, },
  263. Arts : 0.5,
  264. Techniques : 1.5,
  265. Mechanical : 0.5,
  266. Learning : 1.1,
  267. },
  268. {
  269. Entity: Entity {
  270. ID: "kin_android", Name: "Android",
  271. Short: "Human shaped biomchanical robot at the service of humans. ",
  272. Long:
  273. `Androids are conscious human shaped robots with the imperative to serve humans.
  274. Highly effective with Techniques, and can install many Parts, but cannot use
  275. any Numen arts. Since thay are not alive, they technically cannot die.`,
  276. },
  277. // STR+1 1 TOU+1 DEX+1 INT+1
  278. Talents : Talents {Strength : +2, Toughness: +2,
  279. Dexterity : +2, Intelligence: +2, },
  280. Arts : 0.0,
  281. Techniques : 2.0,
  282. Mechanical : 1.0,
  283. Learning : 1.0,
  284. },
  285. {
  286. Entity: Entity {
  287. ID: "kin_maverick", Name: "Maverick",
  288. Short: "Human shaped biomechanical robot running wild. ",
  289. Long:
  290. `Mavericks are androids in which the imperative to serve humans has
  291. been destroyed or disabled. Highly effective with Techniques, and can install
  292. many Parts, but cannot use any Numen arts. Since thay are not alive, they
  293. technically cannot die. They are feared by Humans and hated by Androids.`,
  294. Privilege: PRIVILEGE_IMPLEMENTOR,
  295. },
  296. // STR+1 1 TOU+1 DEX+1 INT+1
  297. Talents : Talents {Strength : +3, Toughness: +3,
  298. Dexterity : +2, Intelligence: +2, Charisma: -2 },
  299. Arts : 0.0,
  300. Techniques : 2.0,
  301. Mechanical : 1.0,
  302. Learning : 1.0,
  303. },
  304. {
  305. Entity: Entity {
  306. ID: "kin_robot", Name: "Robot",
  307. Short: "Non conscious mechanical robot.",
  308. Long:
  309. `In the wars of the past many robots were built for offense or defense.
  310. Unfortunately, they are self repairing and often even able to replicate
  311. if they find suitable materials. No wonder they are still prowling
  312. the Earth millennia after.`,
  313. Privilege: PRIVILEGE_IMPLEMENTOR,
  314. },
  315. // STR+1 1 TOU+1 DEX+1 INT+1
  316. Talents : Talents {Strength : +4, Toughness: +4,
  317. Dexterity : +2, Intelligence: +2, Charisma: -4},
  318. Arts : 0.0,
  319. Techniques : 2.0,
  320. Mechanical: 1.0,
  321. Learning : 1.0,
  322. },
  323. {
  324. Entity: Entity {
  325. ID: "kin_drone", Name: "Drone",
  326. Short: "Flying combat robot. ",
  327. Long:
  328. `Out of control robots are a pain, out of control flying robots even more so!
  329. They might be less though than normal robots, but they move extremely quickly.
  330. `,
  331. Privilege: PRIVILEGE_IMPLEMENTOR,
  332. },
  333. Talents : Talents {Strength : +2, Toughness: +2,
  334. Agility: +4, Dexterity : +2, Intelligence: +2, Charisma: -4},
  335. Arts : 0.0,
  336. Techniques : 2.0,
  337. Mechanical : 1.0,
  338. Learning : 1.0,
  339. },
  340. {
  341. Entity: Entity {
  342. ID: "kin_turret", Name: "Turret",
  343. Short: "Immobile automated defense system. ",
  344. Long:
  345. `
  346. The ancients would set up robotic defense system to guard certain areas.
  347. These defense systems might be immobile, but they are deadly accurate.
  348. Furthermore they are extremely resillient and self repairing.
  349. No wonder they are still active after all these years.
  350. `,
  351. Privilege: PRIVILEGE_IMPLEMENTOR,
  352. },
  353. Talents : Talents {Strength : +2, Toughness: +4,
  354. Agility: -4, Dexterity : +4, Intelligence: +4, Charisma: -4},
  355. Arts : 0.0,
  356. Techniques : 2.0,
  357. Mechanical : 1.0,
  358. Learning : 1.0,
  359. },
  360. {
  361. Entity: Entity {
  362. ID: "kin_beast", Name: "Beast",
  363. Short: "Beast that prowls the wild. ",
  364. Long:
  365. `Due to the damage to the ecosystem, beasts have rapidly evolved in the last
  366. 60000 years. As a result, most all of them, even the plant eaters, are ferocious
  367. and aggressive, to protect themselves and their offspring from Humans.`,
  368. Privilege: PRIVILEGE_IMPLEMENTOR,
  369. },
  370. Talents : Talents {Strength : +2, Toughness: +2,
  371. Agility : +1, Intelligence: -5, },
  372. Arts : 1.0,
  373. Techniques : 1.0,
  374. Learning : 1.0,
  375. },
  376. {
  377. Entity: Entity {
  378. ID: "kin_bird", Name: "Bird",
  379. Short: "Flying being that prowls the wild. ",
  380. Long:
  381. `Beasts can be dangerous, flying beasts are all the more so!
  382. They might be less resillient, but all the more agile.`,
  383. Privilege: PRIVILEGE_IMPLEMENTOR,
  384. },
  385. Talents : Talents {Strength : +1, Toughness: +1,
  386. Agility : +3, Intelligence: -5, },
  387. Arts : 1.0,
  388. Techniques : 1.0,
  389. Learning : 1.0,
  390. },
  391. {
  392. Entity: Entity {
  393. ID: "kin_fish", Name: "Fish",
  394. Short: "Fish like being that swims the seas or rivers. ",
  395. Long:
  396. `Now you know why you were always told not to swim in rivers or seas.
  397. Fish dart through the water, attacking with their razor sharp teeth.
  398. `,
  399. Privilege: PRIVILEGE_IMPLEMENTOR,
  400. },
  401. Talents : Talents {Strength : +3, Toughness: +2,
  402. Agility : +2, Intelligence: -5, },
  403. Arts : 1.0,
  404. Techniques : 1.0,
  405. Learning : 1.0,
  406. },
  407. {
  408. Entity: Entity {
  409. ID: "kin_amphibian", Name: "Amphibian",
  410. Short: "Being that lives both on land and in the water. ",
  411. Long:
  412. `Covered with a slimy skin and often toxic, these being can not only swim
  413. but also purse you on land.`,
  414. Privilege: PRIVILEGE_IMPLEMENTOR,
  415. },
  416. Talents : Talents {Strength : +1, Toughness: +2,
  417. Agility : +1, Dexterity: +1, Intelligence: -5, },
  418. Arts : 1.0,
  419. Techniques : 1.0,
  420. Learning : 1.0,
  421. },
  422. {
  423. Entity: Entity {
  424. ID: "kin_reptile", Name: "Reptile",
  425. Short: "Scaly creepy crawling beasts.",
  426. Long:
  427. `Reptiles have been around for a long time, and it looks they will be around for
  428. a long time still. They may be slow, especially in colder weather, nevertheless
  429. they remain dangerous.
  430. `,
  431. Privilege: PRIVILEGE_IMPLEMENTOR,
  432. },
  433. Talents : Talents {Strength : +2, Toughness: +2,
  434. Agility: -1, Intelligence: -5, },
  435. Arts : 1.0,
  436. Techniques : 1.0,
  437. Learning : 1.0,
  438. },
  439. {
  440. Entity: Entity {
  441. ID: "kin_crustacean", Name: "Custacian",
  442. Short: "Beast protected by a tough shell",
  443. Long:
  444. `You might find it hard to inflict any damage to these well armoured beings.
  445. Their shells protect them against damage and allow them to live in the water
  446. and as well on the land.`,
  447. Privilege: PRIVILEGE_IMPLEMENTOR,
  448. },
  449. Talents : Talents {Strength : +2, Toughness: +4,
  450. Intelligence: -5, },
  451. Arts : 1.0,
  452. Techniques : 1.0,
  453. Learning : 1.0,
  454. },
  455. {
  456. Entity: Entity {
  457. ID: "kin_insect", Name: "Insect",
  458. Short: "Beast with articulated legs and bodies.",
  459. Long:
  460. `The climate of Earth hs shifted dramaticaly over the last 60000 years,
  461. and as a result, larger creepy crawlers became more successful.
  462. `,
  463. Privilege: PRIVILEGE_IMPLEMENTOR,
  464. },
  465. Talents : Talents {Strength : +2, Toughness: +4, Intelligence: -5, },
  466. Arts : 1.0,
  467. Techniques : 1.0,
  468. Learning : 1.0,
  469. },
  470. {
  471. Entity: Entity {
  472. ID: "kin_aquatic", Name: "beast",
  473. Short: "Aquatic beast. ",
  474. Long:
  475. `Whether in the rivers or the deep seas, these soft bodies creatures
  476. are often toxic and quite dangerous.`,
  477. Privilege: PRIVILEGE_IMPLEMENTOR,
  478. },
  479. Talents : Talents {Strength : +2, Dexterity: +2, Intelligence: -5, },
  480. Arts : 1.0,
  481. Techniques : 1.0,
  482. Learning : 1.0,
  483. },
  484. {
  485. Entity: Entity {
  486. ID: "kin_corrupted", Name: "corrupted",
  487. Short: "Beast corupted by Omen. ",
  488. Long:
  489. `Some animals became corrupted by Omen. As a result, they became much stronger
  490. and more resillient. Fortunately, the Omen is weak against certain Numen arts.
  491. Beware, their attacks might be contageous...`,
  492. Privilege: PRIVILEGE_IMPLEMENTOR,
  493. },
  494. Talents : Talents {Strength : +4, Toughness: +4,
  495. Agility : +1, Intelligence: -3, Wisdom: -5 },
  496. Arts : 1.0,
  497. Techniques : 1.0,
  498. Corruption: 1.0,
  499. Learning : 1.0,
  500. },
  501. {
  502. Entity: Entity {
  503. ID: "kin_deceased", Name: "Deceased",
  504. Short: "Deceased biological being animated by Omen. ",
  505. Long:
  506. `Some living beings become corrupted by Omen to the point that they remain
  507. animated even after their biological bodies have already stopped functioning.
  508. Such beings are termed the Deceased. They are resillient, strong and cunning.
  509. Fortunately, the Omen is weak against certain Numen arts. But beware, their
  510. attacks might be contageous...
  511. `,
  512. Privilege: PRIVILEGE_IMPLEMENTOR,
  513. },
  514. Talents : Talents {Strength : +2, Toughness: +2,
  515. Agility : +1, Intelligence: -1, Wisdom: -7 },
  516. Arts : 1.0,
  517. Techniques : 1.0,
  518. Learning : 1.0,
  519. Corruption: 1.0,
  520. Unlife: 1.0,
  521. },
  522. }
  523. var KinEntityList EntitylikeSlice
  524. func init() {
  525. KinEntityList = make(EntitylikeSlice, len(KinList))
  526. for i := range(KinList) {
  527. e := KinList[i];
  528. monolog.Debug("KinList: %s", e.Name)
  529. KinEntityList[i] = &e
  530. }
  531. }
  532. func EntitylikeToKin(me Entitylike) (*Kin) {
  533. v, ok := me.(*Kin)
  534. if ok {
  535. return v
  536. } else {
  537. return nil
  538. }
  539. }
  540. /* All jobs of WOE
  541. * agent officer guardian
  542. * worker brawler builder
  543. * hunter gunsman rogue
  544. * explorer ranger rebel
  545. * tinker engineer wrecker
  546. * homemaker musician trader
  547. * scholar scientist hacker
  548. * medic cleric artist
  549. * esper dilettante (not playable) Danger
  550. *
  551. *
  552. * hunter scholar esper worker medic agent officer cleric guardian ranger
  553. * wrecker engineer tinker scientist
  554. *
  555. *
  556. *
  557. Agent STR + 2
  558. Worker TOU + 2
  559. Engineer DEX + 2
  560. Hunter AGI + 2
  561. Scholar INT + 2
  562. Medic WIS + 2
  563. Cleric CHA + 2
  564. *
  565. *
  566. */
  567. var JobList = [] Job {
  568. { Entity: Entity {
  569. ID: "job_agent", Name: "Agent",
  570. Short: "Agent employed by the government of Eruta.",
  571. Long:
  572. `Agents work for the government of Eruta. They are given all sorts of tasks, but tend to focus on capturing criminals. Physical strength is their forte.
  573. `,
  574. },
  575. Talents : Talents { Strength: +2 },
  576. Skills : map[string] int{
  577. "skill_sword" : 10,
  578. "skill_heavy_gear" : 10,
  579. "skill_acrobatics" : 5,
  580. "skill_cannon" : 5,
  581. "skill_weaponsmith" : 5,
  582. },
  583. Playable: true,
  584. },
  585. { Entity: Entity {
  586. ID: "job_worker", Name: "Worker",
  587. Short: "Worker in construction or mining.",
  588. Long:
  589. `Workers take on the more heavy jobs such as construction and mining. They are a tough lot.
  590. `,
  591. },
  592. Talents : Talents { Toughness: +2 },
  593. Skills : map[string] int{
  594. "skill_maul" : 10,
  595. "skill_heavy_gear" : 10,
  596. "skill_toiling" : 5,
  597. "skill_explosives" : 5,
  598. "skill_mining" : 5,
  599. },
  600. Playable: true,
  601. },
  602. { Entity: Entity {
  603. ID: "job_engineer", Name: "Engineer",
  604. Short: "Expert in machines and technology.",
  605. Long:
  606. `Engineers are experts in technology. They can construct and repair most any machine. They tend to be higly dexterous.
  607. `,
  608. },
  609. Talents : Talents { Toughness: +2 },
  610. Skills : map[string] int{
  611. "skill_gun" : 10,
  612. "skill_medium_gear" : 10,
  613. "skill_engineering" : 5,
  614. "skill_fist" : 5,
  615. "skill_gunsmith" : 5,
  616. },
  617. Playable: true,
  618. },
  619. {Entity: Entity {
  620. ID: "job_hunter", Name: "Hunter",
  621. Short: "Hunter who chases beasts and mavericks.",
  622. Long:
  623. `Hunters protect human settlements from Beasts and Mavericks, and try to keep their numbers down. They excel in Agility.
  624. `,
  625. },
  626. Talents : Talents { Agility: +2 },
  627. Skills : map[string] int{
  628. "skill_polearm" : 10,
  629. "skill_medium_gear" : 10,
  630. "skill_shield" : 5,
  631. "skill_gun" : 5,
  632. "skill_survival" : 5,
  633. },
  634. Playable: true,
  635. },
  636. {Entity: Entity {
  637. ID: "job_scholar", Name: "Scholar",
  638. Short: "Scholar who studies science.",
  639. Long:
  640. `Scolars focus in studying science and discovering what was previously unknown. Reknowned for their intelligence.
  641. `,
  642. },
  643. Talents : Talents { Intelligence: +2 },
  644. Skills : map[string] int{
  645. "skill_staff" : 10,
  646. "skill_light_gear" : 10,
  647. "skill_science" : 5,
  648. "skill_lore" : 5,
  649. "skill_artistic" : 5,
  650. },
  651. Playable: true,
  652. },
  653. {Entity: Entity {
  654. ID: "job_medic", Name: "Medic",
  655. Short: "Medic who heals the wounded and cures the ill.",
  656. Long:
  657. `Medics focus on healing the wounded and curng the ill. Need wisdom to deal with their patients.
  658. `,
  659. },
  660. Talents : Talents { Intelligence: +2 },
  661. Skills : map[string] int{
  662. "skill_knife" : 10,
  663. "skill_light_gear" : 10,
  664. "skill_medical" : 5,
  665. "skill_bravery" : 5,
  666. "skill_gun" : 5,
  667. },
  668. Playable: true,
  669. },
  670. {Entity: Entity {
  671. ID: "job_cleric", Name: "Cleric",
  672. Short: "Clerics tend to the spiritual.",
  673. Long:
  674. `Clerics tend to the spiritual well being of others in the name of Lord Kei. It is a job that requires high Charisma.`,
  675. },
  676. Talents : Talents { Charisma: +2 },
  677. Skills : map[string] int{
  678. "skill_fist" : 10,
  679. "skill_light_gear" : 10,
  680. "skill_shield" : 5,
  681. "skill_social" : 5,
  682. "skill_arcane" : 5,
  683. },
  684. Playable: true,
  685. },
  686. }
  687. var JobEntityList EntitylikeSlice
  688. func init() {
  689. JobEntityList = make(EntitylikeSlice, len(JobList))
  690. for i := range(JobList) {
  691. e := JobList[i];
  692. monolog.Debug("JobList: %s", e.Name)
  693. JobEntityList[i] = &e
  694. }
  695. }
  696. func EntitylikeToJob(me Entitylike) (*Job) {
  697. v, ok := me.(*Job)
  698. if ok {
  699. return v
  700. } else {
  701. return nil
  702. }
  703. }
  704. type LabeledPointer struct {
  705. ID string
  706. labeled * Labeled
  707. }
  708. type GenderPointer struct {
  709. ID string
  710. gender * Gender
  711. }
  712. //}
  713. /* Vital statistic of a Being. */
  714. type Vital struct {
  715. Now int `xml:"N,attr"`
  716. Max int `xml:"X,attr"`
  717. }
  718. /* Report a vital statistic as a Now/Max string */
  719. func (me * Vital) ToNowMax() string {
  720. return fmt.Sprintf("%4d/%4d", me.Now , me.Max)
  721. }
  722. // alias of the above, since I'm lazy at times
  723. func (me * Vital) TNM() string {
  724. return me.ToNowMax()
  725. }
  726. /* Report a vital statistic as a rounded percentage */
  727. func (me * Vital) ToPercentage() string {
  728. percentage := (me.Now * 100) / me.Max
  729. return fmt.Sprintf("%d", percentage)
  730. }
  731. /* Report a vital statistic as a bar of characters */
  732. func (me * Vital) ToBar(full string, empty string, length int) string {
  733. numfull := (me.Now * length) / me.Max
  734. numempty := length - numfull
  735. return strings.Repeat(empty, numempty) + strings.Repeat(full, numfull)
  736. }
  737. type Talents struct {
  738. Strength int `xml:"Talents>STR,omitempty"`
  739. Toughness int `xml:"Talents>TOU,omitempty"`
  740. Agility int `xml:"Talents>AGI,omitempty"`
  741. Dexterity int `xml:"Talents>DEX,omitempty"`
  742. Intelligence int `xml:"Talents>INT,omitempty"`
  743. Wisdom int `xml:"Talents>WIS,omitempty"`
  744. Charisma int `xml:"Talents>CHA,omitempty"`
  745. Emotion int `xml:"Talents>EMO,omitempty"`
  746. }
  747. type Vitals struct {
  748. HP Vital
  749. MP Vital
  750. JP Vital
  751. LP Vital
  752. }
  753. type EquipmentValues struct {
  754. Offense int
  755. Protection int
  756. Block int
  757. Rapidity int
  758. Yield int
  759. }
  760. type Being struct {
  761. Entity
  762. // Essentials
  763. * Gender
  764. * Kin
  765. * Job
  766. Level int
  767. // A being has talents.
  768. Talents
  769. // A being has vitals
  770. Vitals
  771. // A being has Equipment values
  772. EquipmentValues
  773. // A being has aptitudes
  774. Aptitudes
  775. // Skills map[string]BeingSkill
  776. // Arts array
  777. // Arts []Art
  778. // Affects array
  779. // Affects []Affect
  780. // Equipment
  781. Equipment
  782. // Inventory
  783. Inventory
  784. // Location pointer
  785. Room * Room
  786. }
  787. var BasicTalent Talents = Talents {
  788. Strength : 10,
  789. Toughness : 10,
  790. Agility : 10,
  791. Dexterity : 10,
  792. Intelligence : 10,
  793. Wisdom : 10,
  794. Charisma : 10,
  795. Emotion : 10,
  796. }
  797. // Derived stats
  798. func (me *Talents) Force() int {
  799. return (me.Strength * 2 + me.Wisdom) / 3
  800. }
  801. func (me *Talents) Vitality() int {
  802. return (me.Toughness * 2 + me.Charisma) / 3
  803. }
  804. func (me * Talents) Quickness() int {
  805. return (me.Agility * 2 + me.Intelligence) / 3
  806. }
  807. func (me * Talents) Knack() int {
  808. return (me.Dexterity * 2 + me.Emotion) / 3
  809. }
  810. func (me * Talents) Understanding() int {
  811. return (me.Intelligence * 2 + me.Toughness) / 3
  812. }
  813. func (me * Talents) Grace() int {
  814. return (me.Charisma * 2 + me.Agility) / 3
  815. }
  816. func (me * Talents) Zeal() int {
  817. return (me.Wisdom * 2 + me.Strength) / 3
  818. }
  819. func (me * Talents) Numen() int {
  820. return (me.Emotion * 2 + me.Dexterity) / 3
  821. }
  822. /*
  823. Stats of beings:
  824. Talents:
  825. *
  826. * Talents describe the basic constitution of a being.
  827. Strength: explosive physical strength
  828. Toughness: physical resillience
  829. Agility: Speed of motion and bodily balance
  830. Dexterity: Fine motor sills and hand eye coordination
  831. Intelligence: Book smarts and studiousness
  832. Wisdom: Insight and intution
  833. Emotion: Emotional control and insight.
  834. Charisma: Social abilities and appeal to others
  835. Force: Physical and mental vigor.
  836. Vitality: Resistance against damage.
  837. Quickness: Phyisical and mental speed.
  838. Knack: Manual and mental adroitness
  839. Understanding: Deep insight though stubborn work.
  840. Grace: Appeal and delicacy of motion and presence.
  841. Zeal: Mental and religious perspicacity.
  842. Numen: Effectiveness of arts through passion and quick hands.
  843. HP: Hull Power/ Health Power: Protection against wounds. When 0, the being is
  844. likely to get stunned and vulnerable against LP damage.
  845. MP: Motion Power. Needed for motion and performing techniques.
  846. JP: Junction Power. Needed for Numen arts.
  847. LP: Life Power. Resilience to actual wounds. When 0, the being dies or is
  848. destroyed.
  849. Offense: Effectiveness of weapon (ranged or melee).
  850. Protection: Effectiveness of armor.
  851. Blocking: Efectiveness of shield or parrying weapon.
  852. Rapidity: Gain or loss of speed due to armor (may be negative).
  853. Calculations:
  854. Life Power LP Vitality / 2 + KIN_LP_BONUS
  855. Husk Power HP (((Level * Vitality) div 5) + Level*2 + Vitality*2 + 8) * RACE_HP_MUL
  856. Junction Power JP ((Level * Numen) div 4) + Level*2 + Numen*2) * RACE_JP_MUL
  857. Motion Power MP (((Level * Zeal) div 4) + Level * 2 + Zeal * 2) + 30) * RACE_MP_MUL
  858. XXX: this will be changd to only include Equipment related values, skill and talent are added to the calculation later.
  859. Offense OFF Quality of equipped weapon
  860. Protection PRO Sum of quality of equipped gear.
  861. Blocking BLO (shield quality ) OR ( weapon skill + weapon quality ) if learned weapon's parry technique, otherwise ineffective.
  862. Rapidity RAP - weight of armor - weight of shield - weight of weapon.
  863. Yield YIE Numen - interference penalty of gear - interference penalty of shield - interference of weapon + quality of staff if equipped + quality of equipped Focus.
  864. Offense
  865. Protection
  866. Block
  867. Rapidity
  868. Yield
  869. */
  870. // Generates a prompt for use with the being/character
  871. func (me * Being) ToPrompt() string {
  872. if (me.Kin != nil) && (me.Kin.Arts > 0.0) {
  873. return fmt.Sprintf("HP:%s MP:%s LP:%s JP:%s", me.HP.TNM(), me.MP.TNM(), me.LP.TNM(), me.JP.TNM())
  874. } else {
  875. return fmt.Sprintf("HP:%s MP:%s LP:%s", me.HP.TNM(), me.MP.TNM(), me.LP.TNM())
  876. }
  877. }
  878. func (me * Being) GenderName() string {
  879. if ( me.Gender == nil ) {
  880. return "????"
  881. }
  882. return me.Gender.Name
  883. }
  884. func (me * Being) KinName() string {
  885. if ( me.Kin == nil ) {
  886. return "????"
  887. }
  888. return me.Kin.Name
  889. }
  890. func (me * Being) JobName() string {
  891. if ( me.Job == nil ) {
  892. return "????"
  893. }
  894. return me.Job.Name
  895. }
  896. // Generates an overview of the essentials of the being as a string.
  897. func (me * Being) ToEssentials() string {
  898. return fmt.Sprintf("%s lvl %d %s %s %s", me.Name, me.Level, me.GenderName(), me.KinName(), me.JobName())
  899. }
  900. // Generates an overview of the physical talents of the being as a string.
  901. func (me * Talents) ToBodyTalents() string {
  902. return fmt.Sprintf("STR: %3d TOU: %3d AGI: %3d DEX: %3d", me.Strength, me.Toughness, me.Agility, me.Dexterity)
  903. }
  904. // Generates an overview of the mental talents of the being as a string.
  905. func (me * Talents) ToMindTalents() string {
  906. return fmt.Sprintf("INT: %3d WIS: %3d CHA: %3d EMO: %3d", me.Intelligence, me.Wisdom, me.Charisma, me.Emotion)
  907. }
  908. // Generates an overview of the physical derived talents of the being as a string.
  909. func (me * Talents) ToBodyDerived() string {
  910. return fmt.Sprintf("FOR: %3d VIT: %3d QUI: %3d KNA: %3d", me.Force(), me.Vitality(), me.Quickness(), me.Knack())
  911. }
  912. // Generates an overview of the mental derived talents of the being as a string.
  913. func (me * Talents) ToMindDerived() string {
  914. return fmt.Sprintf("UND: %3d GRA: %3d ZEA: %3d NUM: %3d", me.Understanding(), me.Grace(), me.Zeal(), me.Numen())
  915. }
  916. // Generates an overview of the derived talents of the being as a string.
  917. func (me * Talents) ToDerived() string {
  918. status := me.ToBodyDerived();
  919. status += "\n" + me.ToMindDerived();
  920. return status
  921. }
  922. // Generates an overview of all talents as a string.
  923. func (me * Talents) ToTalents() string {
  924. status := me.ToBodyTalents();
  925. status += "\n" + me.ToMindTalents();
  926. return status
  927. }
  928. // Generates an overview of the equipment values of the being as a string.
  929. func (me * EquipmentValues) ToEquipmentValues() string {
  930. return fmt.Sprintf("OFF: %3d PRO: %3d BLO: %3d RAP: %3d YIE: %3d", me.Offense, me.Protection, me.Block, me.Rapidity, me.Yield)
  931. }
  932. // Generates an overview of the status of the being as a string.
  933. func (me * Being) ToStatus() string {
  934. status := me.ToEssentials()
  935. status += "\n" + me.ToTalents();
  936. status += "\n" + me.ToDerived();
  937. status += "\n" + me.ToEquipmentValues();
  938. status += "\n" + me.ToPrompt();
  939. status += "\n"
  940. return status
  941. }
  942. func (me * Talents) GrowFrom(from Talents) {
  943. me.Strength += from.Strength
  944. me.Toughness += from.Toughness
  945. me.Agility += from.Agility
  946. me.Dexterity += from.Dexterity
  947. me.Intelligence += from.Intelligence
  948. me.Wisdom += from.Wisdom
  949. me.Charisma += from.Charisma
  950. me.Emotion += from.Emotion
  951. }
  952. func (me * Vital) NewMax(max int) {
  953. oldmax := me.Max
  954. me.Max = max
  955. delta := me.Max - oldmax
  956. me.Now += delta
  957. if (me.Now > me.Max) {
  958. me.Now = me.Max
  959. }
  960. if (me.Now < 0) {
  961. me.Now = 0
  962. }
  963. }
  964. func (me * Being) RecalculateVitals() {
  965. newhp := (me.Level * me.Vitality() / 5 ) + me.Level * 2 + me.Vitality() * 2
  966. newhp += 8
  967. me.Vitals.HP.NewMax(newhp)
  968. me.Vitals.LP.NewMax((me.Vitality() / 2 + 4))
  969. newjp := (me.Level * me.Numen()) / 4 + me.Level * 2 + me.Numen() * 2
  970. newjpf := float64(newjp)
  971. newmp := (me.Level * me.Zeal()) / 4 + me.Level * 2 + me.Zeal() * 2 + 32
  972. newmpf := float64(newmp)
  973. if me.Kin != nil {
  974. newjpf *= me.Kin.Arts
  975. newmpf *= me.Kin.Techniques
  976. }
  977. me.Vitals.MP.NewMax(int(math.Floor(newjpf)))
  978. me.Vitals.JP.NewMax(int(math.Floor(newmpf)))
  979. }
  980. func (me * Being) Init(kind string, name string, privilege Privilege,
  981. kin Entitylike, gender Entitylike, job Entitylike) (* Being) {
  982. if me == nil {
  983. return me
  984. }
  985. me.Entity.InitKind(kind, name, privilege)
  986. realkin := EntitylikeToKin(kin)
  987. realgen := EntitylikeToGender(gender)
  988. realjob := EntitylikeToJob(job)
  989. monolog.Info("Init being: Kin: %v" , realkin)
  990. monolog.Info("Init being: Gender: %v", realgen)
  991. monolog.Info("Init being: Job: %v" , realjob)
  992. me.Kin = realkin
  993. me.Gender = realgen
  994. me.Job = realjob
  995. me.Talents.GrowFrom(BasicTalent)
  996. me.Talents.GrowFrom(me.Kin.Talents)
  997. me.Talents.GrowFrom(me.Gender.Talents)
  998. me.Talents.GrowFrom(me.Job.Talents)
  999. me.Level = 1
  1000. me.RecalculateVitals()
  1001. return me
  1002. }
  1003. func NewBeing(kind string, name string, privilege Privilege,
  1004. kin Entitylike, gender Entitylike, job Entitylike) (* Being) {
  1005. res := &Being{}
  1006. res.Init(kind, name, privilege, kin, gender, job)
  1007. return res
  1008. }
  1009. func (me *Being) Type() string {
  1010. return "being"
  1011. }
  1012. func (me *Being) Save(datadir string) {
  1013. SaveSavable(datadir, me)
  1014. }
  1015. func LoadBeing(datadir string, nameid string) * Being {
  1016. res, _ := LoadLoadable(datadir, nameid, new(Being)).(*Being)
  1017. return res
  1018. }
  1019. func (me * Talents) SaveSitef(rec * sitef.Record) (err error) {
  1020. rec.PutStruct("", *me)
  1021. return nil
  1022. }
  1023. func (me * Vitals) SaveSitef(rec * sitef.Record) (err error) {
  1024. rec.PutStruct("", *me)
  1025. return nil
  1026. }
  1027. func (me * EquipmentValues) SaveSitef(rec * sitef.Record) (err error) {
  1028. rec.PutStruct("", *me)
  1029. return nil
  1030. }
  1031. func (me * Aptitudes) SaveSitef(rec * sitef.Record) (err error) {
  1032. nskills := len(me.Skills)
  1033. rec.PutInt("skills", nskills)
  1034. for i := 0 ; i < nskills; i ++ {
  1035. rec.PutArrayIndex("skills", i, me.Skills[i].skill.ID)
  1036. }
  1037. return nil
  1038. }
  1039. func (me * Inventory) SaveSitef(rec * sitef.Record) (err error) {
  1040. return nil
  1041. }
  1042. // Save a being to a sitef record.
  1043. func (me * Being) SaveSitef(rec * sitef.Record) (err error) {
  1044. me.Entity.SaveSitef(rec)
  1045. rec.PutInt("level", me.Level)
  1046. if me.Gender != nil {
  1047. rec.Put("gender", me.Gender.ID)
  1048. }
  1049. if me.Job != nil {
  1050. rec.Put("job", me.Job.ID)
  1051. }
  1052. if me.Kin != nil {
  1053. rec.Put("kin", me.Kin.ID)
  1054. }
  1055. me.Talents.SaveSitef(rec)
  1056. me.Vitals.SaveSitef(rec)
  1057. me.EquipmentValues.SaveSitef(rec)
  1058. me.Aptitudes.SaveSitef(rec)
  1059. me.Inventory.SaveSitef(rec)
  1060. if me.Room != nil {
  1061. rec.Put("room", me.Room.ID)
  1062. }
  1063. return nil
  1064. }
  1065. func (me * Talents) LoadSitef(rec sitef.Record) (err error) {
  1066. rec.GetStruct("", me)
  1067. return nil
  1068. }
  1069. func (me * Vitals) LoadSitef(rec sitef.Record) (err error) {
  1070. rec.GetStruct("", me)
  1071. return nil
  1072. }
  1073. func (me * EquipmentValues) LoadSitef(rec sitef.Record) (err error) {
  1074. rec.GetStruct("", me)
  1075. return nil
  1076. }
  1077. func (me * Aptitudes) LoadSitef(rec sitef.Record) (err error) {
  1078. // rec.GetStruct("", *me)
  1079. return nil
  1080. }
  1081. func (me * Inventory) LoadSitef(rec sitef.Record) (err error) {
  1082. // rec.GetStruct("", *me)
  1083. return nil
  1084. }
  1085. // Load a being from a sitef record.
  1086. func (me * Being) LoadSitef(rec sitef.Record) (err error) {
  1087. me.Entity.LoadSitef(rec)
  1088. me.Level = rec.GetIntDefault("level", 1)
  1089. me.Gender = EntitylikeToGender(GenderEntityList.FindID(rec.Get("gender")))
  1090. me.Job = EntitylikeToJob(JobEntityList.FindID(rec.Get("job")))
  1091. me.Kin = EntitylikeToKin(KinEntityList.FindID(rec.Get("kin")))
  1092. me.Talents.LoadSitef(rec)
  1093. me.Vitals.LoadSitef(rec)
  1094. me.EquipmentValues.LoadSitef(rec)
  1095. me.Aptitudes.LoadSitef(rec)
  1096. me.Inventory.LoadSitef(rec)
  1097. if (rec.Get("room") != "") {
  1098. var err error
  1099. me.Room, err = DefaultWorld.LoadRoom(rec.Get("room"))
  1100. if err != nil {
  1101. monolog.WriteError(err)
  1102. return err
  1103. }
  1104. }
  1105. return nil
  1106. }