CharCreation.svelte 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. <script>
  2. import { Name } from '$lib/components';
  3. import { addComponent, removeEntity } from '$lib/ecs';
  4. import { onMount } from 'svelte';
  5. import Select from '../Select.svelte';
  6. import { newGame } from './game';
  7. import { applyProfession, enumProfessions } from './profession';
  8. import { enumSkills, purgeSkills } from './skill';
  9. import Stats from './Stats.svelte';
  10. import Skills from './Skills.svelte';
  11. import { getInventory, purgeInventory } from '$lib/inventory';
  12. import Equipment from './Equipment.svelte';
  13. import Inventory from './Inventory.svelte';
  14. import { fromTemplate } from '$lib/builder';
  15. import { getEquipped, purgeEquipment } from './equipment';
  16. import { playerTemplate } from './player';
  17. import { notNullish } from '$lib/util';
  18. let { game } = $props();
  19. const game0 = newGame();
  20. let charNameWidget;
  21. let tick = $state(false);
  22. let error = $state('');
  23. let playerName = $state('I.I.');
  24. const professions = enumProfessions();
  25. const skills = enumSkills();
  26. let professionIx = $state(0);
  27. let selectedProfession = $state(professions[0]);
  28. let tmpChar = $state();
  29. // skip char-creation (for debug purposes)
  30. const autostart = false;
  31. onMount(() => {
  32. charNameWidget.focus();
  33. tmpChar = fromTemplate(game0.world, playerTemplate);
  34. if (autostart) {
  35. start();
  36. }
  37. });
  38. let inventory = $state([]);
  39. let equipment = $state([]);
  40. $effect(() => {
  41. if (notNullish(tmpChar)) {
  42. purgeInventory(game0.world, tmpChar);
  43. purgeEquipment(game0.world, tmpChar);
  44. purgeSkills(game0.world, tmpChar);
  45. applyProfession(game0.world, tmpChar, professions[professionIx]);
  46. inventory = getInventory(game0.world, tmpChar);
  47. equipment = getEquipped(game0.world, tmpChar);
  48. selectedProfession = professions[professionIx];
  49. }
  50. });
  51. $effect(() => {
  52. tick;
  53. error = '';
  54. });
  55. const start = () => {
  56. purgeEquipment(game0.world, tmpChar);
  57. purgeInventory(game0.world, tmpChar);
  58. removeEntity(game0.world, tmpChar);
  59. tmpChar = undefined;
  60. addComponent(game0.world, Name, game0.pc, {
  61. name: playerName,
  62. });
  63. applyProfession(game0.world, game0.pc, professions[professionIx]);
  64. // NOTE: line below doesn't work because of Svelte reactivity conflict with bitECS
  65. /* applyProfession(game0.world, game0.pc, selectedProfession); */
  66. game = game0;
  67. };
  68. const finishCharacter = () => {
  69. /*
  70. if (freeStatPoints > 0) {
  71. error = 'Free stat points left!';
  72. return;
  73. }
  74. */
  75. start();
  76. };
  77. </script>
  78. <section class="cc-grid">
  79. <div class="cc-leftside">
  80. <h2>New character</h2>
  81. <input bind:this={charNameWidget} bind:value={playerName} /> the {selectedProfession.name}
  82. <div>
  83. <h3>Profession</h3>
  84. <Select options={professions} bind:index={professionIx} />
  85. </div>
  86. <div>
  87. <h3>Hobby</h3>
  88. </div>
  89. <Stats game={game0} bind:tick />
  90. <Skills world={game0.world} char={tmpChar} tick={selectedProfession} />
  91. <div>{error}</div>
  92. <button onclick={finishCharacter}>Ok</button>
  93. </div>
  94. <div class="cc-rightside">
  95. Starting equipment
  96. <Inventory world={game0.world} {inventory} />
  97. <Equipment world={game0.world} {equipment} />
  98. </div>
  99. </section>
  100. <style>
  101. .cc-grid {
  102. display: grid;
  103. grid-template-columns: 1fr 1fr;
  104. grid-template-areas:
  105. "leftside rightside";
  106. }
  107. .cc-leftside {
  108. grid-area: leftside;
  109. }
  110. .cc-rightside {
  111. grid-area: rightside;
  112. }
  113. </style>