Wolfqueenxx97

TTRPG?

Feb 25th, 2025
34
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 254.16 KB | None | 0 0
  1.  
  2. <!DOCTYPE html>
  3. <html lang="en">
  4. <head>
  5. <meta charset="UTF-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>DIGIMON: WORLDS BEYOND THE CODE</title>
  8. <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700&family=Orbitron:wght@500;700&display=swap">
  9. <style>
  10. :root {
  11. --primary-color: #f088ff; /* Light purple */
  12. --primary-dark: #5a4aad;
  13. --secondary-color: #4169e1; /* Royal blue */
  14. --accent-color: #87cefa; /* Light sky blue */
  15. --dark-blue: #191970; /* Midnight blue */
  16. --text-color: #333333;
  17. --bg-color: #f0f8ff; /* Alice blue */
  18. --card-bg: #ffffff;
  19. --border-color: #d0d0ff;
  20. --success-color: #2ecc71;
  21. --danger-color: #e74c3c;
  22. --warning-color: #f39c12;
  23. }
  24.  
  25. * {
  26. box-sizing: border-box;
  27. font-family: 'Montserrat', sans-serif;
  28. }
  29.  
  30. body {
  31. color: var(--text-color);
  32. margin: 0;
  33. padding: 0;
  34. line-height: 1.6;
  35. background-color: #f5f5f5;
  36. background-image:
  37. linear-gradient(45deg, #f0f0ff 25%, transparent 25%),
  38. linear-gradient(-45deg, #f0f0ff 25%, transparent 25%),
  39. linear-gradient(45deg, transparent 75%, #f0f0ff 75%),
  40. linear-gradient(-45deg, transparent 75%, #f0f0ff 75%);
  41. background-size: 20px 20px;
  42. background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
  43. min-height: 100vh;
  44. }
  45.  
  46. .main-container {
  47. max-width: 1200px;
  48. margin: 0 auto;
  49. padding: 30px 20px;
  50. }
  51.  
  52. .game-header {
  53. text-align: center;
  54. padding: 25px;
  55. margin-bottom: 30px;
  56. background: linear-gradient(135deg, var(--dark-blue), var(--secondary-color));
  57. border-radius: 15px;
  58. box-shadow: 0 10px 30px rgba(0,0,0,0.15);
  59. position: relative;
  60. overflow: hidden;
  61. }
  62.  
  63. .game-header::before {
  64. content: '';
  65. position: absolute;
  66. top: 0;
  67. left: 0;
  68. right: 0;
  69. bottom: 0;
  70. background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MCIgaGVpZ2h0PSI2MCIgdmlld0JveD0iMCAwIDYwIDYwIj48cGF0aCBkPSJNMzAgMzBtLTI1IDAgYTI1LDI1IDAgMSwwIDUwLDAgYTI1LDI1IDAgMSwwIC01MCwwIiBmaWxsPSJub25lIiBzdHJva2U9InJnYmEoMjU1LDI1NSwyNTUsMC4xKSIgc3Ryb2tlLXdpZHRoPSIyIj48L3BhdGg+PC9zdmc+');
  71. background-size: 100px 100px;
  72. opacity: 0.1;
  73. }
  74.  
  75. .game-title {
  76. color: white;
  77. margin: 0;
  78. font-family: 'Orbitron', sans-serif;
  79. font-size: 2.8rem;
  80. text-shadow: 0 2px 10px rgba(0,0,0,0.3);
  81. letter-spacing: 1px;
  82. }
  83.  
  84. .game-subtitle {
  85. display: block;
  86. color: var(--primary-color);
  87. font-weight: 700;
  88. font-size: 2.2rem;
  89. text-shadow: 0 0 10px rgba(255,255,255,0.7);
  90. margin-top: 5px;
  91. }
  92.  
  93. .tab-container {
  94. width: 100%;
  95. margin-bottom: 30px;
  96. box-shadow: 0 5px 20px rgba(0,0,0,0.1);
  97. border-radius: 15px;
  98. overflow: hidden;
  99. }
  100.  
  101. .tabs {
  102. display: flex;
  103. flex-wrap: wrap;
  104. background-color: var(--dark-blue);
  105. padding: 5px 5px 0;
  106. position: relative;
  107. }
  108.  
  109. .tab {
  110. padding: 12px 20px;
  111. cursor: pointer;
  112. transition: all 0.3s;
  113. background-color: rgba(135, 206, 250, 0.2);
  114. color: white;
  115. border-radius: 10px 10px 0 0;
  116. margin-right: 5px;
  117. margin-bottom: 0;
  118. font-weight: 500;
  119. position: relative;
  120. overflow: hidden;
  121. border-bottom: 3px solid transparent;
  122. }
  123.  
  124. .tab:hover {
  125. background-color: rgba(135, 206, 250, 0.3);
  126. }
  127.  
  128. .tab.active {
  129. background-color: var(--card-bg);
  130. color: var(--primary-color);
  131. font-weight: 600;
  132. border-bottom: 3px solid var(--primary-color);
  133. }
  134.  
  135. .tab::after {
  136. content: '';
  137. position: absolute;
  138. bottom: 0;
  139. left: 0;
  140. width: 100%;
  141. height: 3px;
  142. background-color: var(--accent-color);
  143. transform: scaleX(0);
  144. transition: transform 0.3s;
  145. }
  146.  
  147. .tab:hover::after {
  148. transform: scaleX(1);
  149. }
  150.  
  151. .tab-content {
  152. display: none;
  153. padding: 25px;
  154. background-color: var(--card-bg);
  155. border-radius: 0 0 15px 15px;
  156. }
  157.  
  158. .tab-content.active {
  159. display: block;
  160. animation: fadeIn 0.5s;
  161. }
  162.  
  163. @keyframes fadeIn {
  164. from { opacity: 0; transform: translateY(10px); }
  165. to { opacity: 1; transform: translateY(0); }
  166. }
  167.  
  168. h1, h2, h3, h4 {
  169. color: var(--secondary-color);
  170. font-family: 'Orbitron', sans-serif;
  171. margin-top: 0;
  172. }
  173.  
  174. .card {
  175. background-color: var(--card-bg);
  176. border-radius: 12px;
  177. box-shadow: 0 5px 15px rgba(0,0,0,0.07);
  178. padding: 25px;
  179. margin-bottom: 25px;
  180. border-left: 5px solid var(--primary-color);
  181. position: relative;
  182. overflow: hidden;
  183. transition: all 0.3s;
  184. }
  185.  
  186. .card:hover {
  187. box-shadow: 0 8px 25px rgba(0,0,0,0.1);
  188. transform: translateY(-2px);
  189. }
  190.  
  191. .card::after {
  192. content: '';
  193. position: absolute;
  194. top: 0;
  195. right: 0;
  196. width: 150px;
  197. height: 150px;
  198. background-image: linear-gradient(135deg, rgba(106, 90, 205, 0.1) 0%, rgba(255, 255, 255, 0) 60%);
  199. border-radius: 0 0 0 100%;
  200. }
  201.  
  202. .card-title {
  203. position: relative;
  204. border-bottom: 2px solid var(--secondary-color);
  205. padding-bottom: 12px;
  206. margin-bottom: 20px;
  207. font-weight: 700;
  208. color: var(--dark-blue);
  209. display: inline-block;
  210. }
  211.  
  212. .card-title::after {
  213. content: '';
  214. position: absolute;
  215. bottom: -2px;
  216. left: 0;
  217. width: 100%;
  218. height: 2px;
  219. background: linear-gradient(90deg, var(--primary-color) 0%, var(--accent-color) 100%);
  220. }
  221.  
  222. .flex-container {
  223. display: flex;
  224. flex-wrap: wrap;
  225. gap: 20px;
  226. }
  227.  
  228. .grid-container {
  229. display: grid;
  230. grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
  231. gap: 25px;
  232. }
  233.  
  234. .form-group {
  235. margin-bottom: 20px;
  236. }
  237.  
  238. .form-row {
  239. display: flex;
  240. flex-wrap: wrap;
  241. gap: 15px;
  242. margin-bottom: 20px;
  243. align-items: flex-start;
  244. }
  245.  
  246. .form-row .form-group {
  247. flex: 1 1 200px;
  248. margin-bottom: 0;
  249. }
  250.  
  251. label {
  252. display: block;
  253. margin-bottom: 8px;
  254. font-weight: 600;
  255. color: var(--dark-blue);
  256. font-size: 0.9rem;
  257. text-transform: uppercase;
  258. letter-spacing: 0.5px;
  259. }
  260.  
  261. input[type="text"],
  262. input[type="number"],
  263. select,
  264. textarea {
  265. width: 100%;
  266. padding: 12px 15px;
  267. border: 1px solid var(--border-color);
  268. border-radius: 8px;
  269. font-size: 1rem;
  270. transition: all 0.3s;
  271. background-color: #f9f9ff;
  272. }
  273.  
  274. input[type="text"]:focus,
  275. input[type="number"]:focus,
  276. select:focus,
  277. textarea:focus {
  278. outline: none;
  279. border-color: var(--primary-color);
  280. box-shadow: 0 0 0 3px rgba(106, 90, 205, 0.1);
  281. }
  282.  
  283. input[type="radio"],
  284. input[type="checkbox"] {
  285. margin-right: 8px;
  286. transform: scale(1.2);
  287. accent-color: var(--primary-color);
  288. }
  289.  
  290. .radio-container,
  291. .checkbox-container {
  292. display: flex;
  293. gap: 20px;
  294. flex-wrap: wrap;
  295. }
  296.  
  297. .radio-container label,
  298. .checkbox-container label {
  299. display: flex;
  300. align-items: center;
  301. text-transform: none;
  302. font-weight: normal;
  303. margin-bottom: 0;
  304. cursor: pointer;
  305. padding: 8px;
  306. border-radius: 8px;
  307. transition: all 0.2s;
  308. }
  309.  
  310. .radio-container label:hover,
  311. .checkbox-container label:hover {
  312. background-color: rgba(106, 90, 205, 0.05);
  313. }
  314.  
  315. .stat-container {
  316. display: flex;
  317. flex-wrap: wrap;
  318. gap: 15px;
  319. margin-bottom: 25px;
  320. }
  321.  
  322. .stat-box {
  323. flex: 1 1 120px;
  324. border: 2px solid var(--primary-color);
  325. border-radius: 10px;
  326. text-align: center;
  327. padding: 15px 10px;
  328. background-color: rgba(135, 206, 250, 0.1);
  329. box-shadow: 0 3px 10px rgba(0,0,0,0.05);
  330. transition: all 0.3s;
  331. position: relative;
  332. overflow: hidden;
  333. }
  334.  
  335. .stat-box:hover {
  336. transform: translateY(-3px);
  337. box-shadow: 0 5px 15px rgba(0,0,0,0.1);
  338. }
  339.  
  340. .stat-box::after {
  341. content: '';
  342. position: absolute;
  343. top: -20px;
  344. right: -20px;
  345. width: 60px;
  346. height: 60px;
  347. background-color: rgba(106, 90, 205, 0.1);
  348. border-radius: 50%;
  349. }
  350.  
  351. .stat-name {
  352. font-weight: 700;
  353. margin-bottom: 8px;
  354. color: var(--dark-blue);
  355. text-transform: uppercase;
  356. font-size: 0.85rem;
  357. letter-spacing: 1px;
  358. }
  359.  
  360. .stat-value {
  361. font-size: 1.8rem;
  362. font-weight: 700;
  363. color: var(--primary-color);
  364. font-family: 'Orbitron', sans-serif;
  365. }
  366.  
  367. input.stat-value {
  368. background-color: transparent;
  369. border: none;
  370. text-align: center;
  371. font-size: 1.8rem;
  372. padding: 0;
  373. width: 100%;
  374. color: var(--primary-color);
  375. font-family: 'Orbitron', sans-serif;
  376. }
  377.  
  378. input.stat-value:focus {
  379. outline: none;
  380. box-shadow: none;
  381. }
  382.  
  383. .skill-container {
  384. display: grid;
  385. grid-template-columns: 1fr auto auto;
  386. gap: 15px;
  387. align-items: center;
  388. padding: 12px;
  389. border-bottom: 1px solid rgba(208, 208, 255, 0.5);
  390. transition: all 0.3s;
  391. border-radius: 8px;
  392. }
  393.  
  394. .skill-container:hover {
  395. background-color: rgba(106, 90, 205, 0.03);
  396. }
  397.  
  398. .skill-name {
  399. font-weight: 600;
  400. color: var(--dark-blue);
  401. display: flex;
  402. flex-direction: column;
  403. }
  404.  
  405. .skill-stat {
  406. color: var(--secondary-color);
  407. font-style: italic;
  408. font-size: 0.85rem;
  409. font-weight: normal;
  410. margin-top: 3px;
  411. }
  412.  
  413. .dice-selector {
  414. display: flex;
  415. flex-wrap: wrap;
  416. gap: 10px;
  417. }
  418.  
  419. .dice-option {
  420. display: inline-flex;
  421. align-items: center;
  422. margin-right: 10px;
  423. cursor: pointer;
  424. }
  425.  
  426. button {
  427. background: linear-gradient(135deg, var(--secondary-color), var(--primary-color));
  428. color: white;
  429. border: none;
  430. padding: 10px 20px;
  431. border-radius: 8px;
  432. cursor: pointer;
  433. font-size: 0.9rem;
  434. font-weight: 600;
  435. transition: all 0.3s;
  436. text-transform: uppercase;
  437. letter-spacing: 0.5px;
  438. box-shadow: 0 3px 10px rgba(0,0,0,0.1);
  439. position: relative;
  440. overflow: hidden;
  441. }
  442.  
  443. button::after {
  444. content: '';
  445. position: absolute;
  446. top: 0;
  447. left: 0;
  448. width: 100%;
  449. height: 100%;
  450. background-image: linear-gradient(rgba(255,255,255,0.2), rgba(255,255,255,0));
  451. opacity: 0;
  452. transition: opacity 0.3s;
  453. }
  454.  
  455. button:hover {
  456. transform: translateY(-2px);
  457. box-shadow: 0 5px 15px rgba(0,0,0,0.15);
  458. }
  459.  
  460. button:hover::after {
  461. opacity: 1;
  462. }
  463.  
  464. button:active {
  465. transform: translateY(0);
  466. box-shadow: 0 2px 5px rgba(0,0,0,0.1);
  467. }
  468.  
  469. button.secondary {
  470. background: linear-gradient(135deg, var(--primary-color), var(--primary-dark));
  471. }
  472.  
  473. button.accent {
  474. background: linear-gradient(135deg, var(--accent-color), var(--secondary-color));
  475. }
  476.  
  477. button.success {
  478. background: linear-gradient(135deg, var(--success-color), #27ae60);
  479. }
  480.  
  481. button.danger {
  482. background: linear-gradient(135deg, var(--danger-color), #c0392b);
  483. }
  484.  
  485. button.sm {
  486. padding: 6px 12px;
  487. font-size: 0.8rem;
  488. }
  489.  
  490. .add-button {
  491. background: linear-gradient(135deg, #4caf50, #2e7d32);
  492. margin-top: 10px;
  493. }
  494.  
  495. .remove-button {
  496. background: linear-gradient(135deg, #f44336, #c62828);
  497. margin-bottom: 10px;
  498. }
  499.  
  500. .notes-container {
  501. display: flex;
  502. flex-direction: column;
  503. height: 300px;
  504. background-color: #f9f9ff;
  505. border-radius: 8px;
  506. overflow: hidden;
  507. box-shadow: 0 3px 10px rgba(0,0,0,0.05);
  508. }
  509.  
  510. .notes-heading {
  511. background-color: var(--primary-color);
  512. color: white;
  513. padding: 10px 15px;
  514. font-weight: 600;
  515. font-size: 0.9rem;
  516. }
  517.  
  518. .notes-content {
  519. flex-grow: 1;
  520. resize: vertical;
  521. border: none;
  522. padding: 15px;
  523. font-size: 0.95rem;
  524. line-height: 1.6;
  525. }
  526.  
  527. .notes-content:focus {
  528. outline: none;
  529. }
  530.  
  531. .image-upload {
  532. display: flex;
  533. flex-direction: column;
  534. align-items: center;
  535. justify-content: center;
  536. width: 200px;
  537. height: 200px;
  538. border: 2px dashed var(--border-color);
  539. margin: 0 auto 25px;
  540. position: relative;
  541. overflow: hidden;
  542. background-color: rgba(106, 90, 205, 0.05);
  543. border-radius: 10px;
  544. transition: all 0.3s;
  545. }
  546.  
  547. .image-upload:hover {
  548. border-color: var(--primary-color);
  549. background-color: rgba(106, 90, 205, 0.1);
  550. }
  551.  
  552. .image-upload img {
  553. max-width: 100%;
  554. max-height: 100%;
  555. object-fit: contain;
  556. }
  557.  
  558. .image-upload-btn {
  559. position: absolute;
  560. bottom: 10px;
  561. opacity: 0.8;
  562. background: rgba(0,0,0,0.6);
  563. padding: 8px 12px;
  564. font-size: 0.8rem;
  565. border-radius: 20px;
  566. }
  567.  
  568. .hide {
  569. display: none;
  570. }
  571.  
  572. .background-info {
  573. margin-top: 15px;
  574. padding: 15px;
  575. background-color: rgba(106, 90, 205, 0.05);
  576. border-radius: 8px;
  577. border-left: 4px solid var(--primary-color);
  578. box-shadow: 0 3px 10px rgba(0,0,0,0.05);
  579. }
  580.  
  581. .background-info h3 {
  582. margin-top: 0;
  583. color: var(--primary-color);
  584. font-size: 1.2rem;
  585. }
  586.  
  587. .background-info ul {
  588. margin-bottom: 0;
  589. }
  590.  
  591. .dice-roller {
  592. padding: 20px;
  593. background: linear-gradient(135deg, rgba(106, 90, 205, 0.1), rgba(135, 206, 250, 0.1));
  594. border-radius: 10px;
  595. margin-top: 25px;
  596. text-align: center;
  597. position: relative;
  598. overflow: hidden;
  599. box-shadow: 0 5px 15px rgba(0,0,0,0.05);
  600. border: 1px solid rgba(208, 208, 255, 0.5);
  601. }
  602.  
  603. .dice-roller::before {
  604. content: '';
  605. position: absolute;
  606. top: 0;
  607. left: 0;
  608. right: 0;
  609. bottom: 0;
  610. background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MCIgaGVpZ2h0PSI2MCIgdmlld0JveD0iMCAwIDYwIDYwIj48cGF0aCBkPSJNMzAgMzBtLTI1IDAgYTI1LDI1IDAgMSwwIDUwLDAgYTI1LDI1IDAgMSwwIC01MCwwIiBmaWxsPSJub25lIiBzdHJva2U9InJnYmEoMTA2LCA5MCwgMjA1LCAwLjEpIiBzdHJva2Utd2lkdGg9IjIiPjwvcGF0aD48L3N2Zz4=');
  611. background-size: 100px 100px;
  612. opacity: 0.5;
  613. }
  614.  
  615. .dice-roller h3 {
  616. margin-top: 0;
  617. color: var(--dark-blue);
  618. position: relative;
  619. }
  620.  
  621. #rollResult {
  622. font-size: 1.8rem;
  623. font-weight: 700;
  624. margin: 15px 0;
  625. min-height: 45px;
  626. color: var(--primary-color);
  627. font-family: 'Orbitron', sans-serif;
  628. position: relative;
  629. text-shadow: 0 2px 5px rgba(0,0,0,0.1);
  630. }
  631.  
  632. .evo-line {
  633. border: 1px solid var(--border-color);
  634. padding: 20px;
  635. margin-bottom: 20px;
  636. border-radius: 10px;
  637. background-color: rgba(106, 90, 205, 0.02);
  638. position: relative;
  639. overflow: hidden;
  640. box-shadow: 0 3px 10px rgba(0,0,0,0.05);
  641. }
  642.  
  643. .evo-line::after {
  644. content: '';
  645. position: absolute;
  646. top: 0;
  647. right: 0;
  648. width: 150px;
  649. height: 150px;
  650. background-image: linear-gradient(135deg, rgba(106, 90, 205, 0.05) 0%, rgba(255, 255, 255, 0) 60%);
  651. border-radius: 0 0 0 100%;
  652. }
  653.  
  654. .evo-stage {
  655. margin-bottom: 15px;
  656. padding: 15px;
  657. border-radius: 8px;
  658. background-color: white;
  659. border-left: 3px solid var(--secondary-color);
  660. box-shadow: 0 3px 10px rgba(0,0,0,0.05);
  661. transition: all 0.3s;
  662. }
  663.  
  664. .evo-stage:hover {
  665. box-shadow: 0 5px 15px rgba(0,0,0,0.1);
  666. }
  667.  
  668. .evo-stage-title {
  669. color: var(--dark-blue);
  670. font-weight: 700;
  671. margin-bottom: 10px;
  672. font-size: 1.1rem;
  673. display: flex;
  674. align-items: center;
  675. }
  676.  
  677. .evo-stage-title::before {
  678. content: '';
  679. display: inline-block;
  680. width: 10px;
  681. height: 10px;
  682. background-color: var(--secondary-color);
  683. border-radius: 50%;
  684. margin-right: 8px;
  685. }
  686.  
  687. .mech-part {
  688. border: 1px solid var(--border-color);
  689. padding: 15px;
  690. margin-bottom: 15px;
  691. border-radius: 8px;
  692. background-color: white;
  693. box-shadow: 0 3px 10px rgba(0,0,0,0.05);
  694. transition: all 0.3s;
  695. position: relative;
  696. overflow: hidden;
  697. }
  698.  
  699. .mech-part:hover {
  700. box-shadow: 0 5px 15px rgba(0,0,0,0.1);
  701. }
  702.  
  703. .mech-part::after {
  704. content: '';
  705. position: absolute;
  706. bottom: 0;
  707. right: 0;
  708. width: 80px;
  709. height: 80px;
  710. background-image: linear-gradient(135deg, rgba(65, 105, 225, 0.05) 0%, rgba(255, 255, 255, 0) 60%);
  711. border-radius: 100% 0 0 0;
  712. }
  713.  
  714. .mech-part h4 {
  715. margin-top: 0;
  716. color: var(--secondary-color);
  717. font-size: 1.1rem;
  718. display: flex;
  719. align-items: center;
  720. }
  721.  
  722. .mech-part h4::before {
  723. content: '⚙';
  724. margin-right: 8px;
  725. font-size: 1rem;
  726. }
  727.  
  728. .item-entry {
  729. border: 1px solid var(--border-color);
  730. padding: 15px;
  731. margin-bottom: 15px;
  732. border-radius: 8px;
  733. background-color: white;
  734. box-shadow: 0 3px 10px rgba(0,0,0,0.05);
  735. transition: all 0.3s;
  736. position: relative;
  737. }
  738.  
  739. .item-entry:hover {
  740. box-shadow: 0 5px 15px rgba(0,0,0,0.1);
  741. }
  742.  
  743. .item-entry::before {
  744. content: '🎒';
  745. position: absolute;
  746. top: 15px;
  747. right: 15px;
  748. font-size: 1.5rem;
  749. opacity: 0.2;
  750. }
  751.  
  752. .import-export {
  753. margin-top: 30px;
  754. padding: 20px;
  755. border: 1px solid var(--border-color);
  756. border-radius: 10px;
  757. background: linear-gradient(135deg, rgba(106, 90, 205, 0.05), rgba(135, 206, 250, 0.05));
  758. box-shadow: 0 5px 15px rgba(0,0,0,0.07);
  759. }
  760.  
  761. .import-export h3 {
  762. margin-top: 0;
  763. color: var(--dark-blue);
  764. }
  765.  
  766. /* Custom notification */
  767. .notification {
  768. position: fixed;
  769. top: 20px;
  770. right: 20px;
  771. padding: 15px 20px;
  772. background-color: var(--success-color);
  773. color: white;
  774. border-radius: 8px;
  775. box-shadow: 0 5px 15px rgba(0,0,0,0.2);
  776. transform: translateY(-100px);
  777. opacity: 0;
  778. transition: all 0.5s;
  779. z-index: 1000;
  780. font-weight: 600;
  781. }
  782.  
  783. .notification.show {
  784. transform: translateY(0);
  785. opacity: 1;
  786. }
  787.  
  788. .notification.error {
  789. background-color: var(--danger-color);
  790. }
  791.  
  792. /* Toggle switch */
  793. .switch {
  794. position: relative;
  795. display: inline-block;
  796. width: 54px;
  797. height: 28px;
  798. }
  799.  
  800. .switch input {
  801. opacity: 0;
  802. width: 0;
  803. height: 0;
  804. }
  805.  
  806. .slider {
  807. position: absolute;
  808. cursor: pointer;
  809. top: 0;
  810. left: 0;
  811. right: 0;
  812. bottom: 0;
  813. background-color: #ccc;
  814. transition: .4s;
  815. border-radius: 34px;
  816. }
  817.  
  818. .slider:before {
  819. position: absolute;
  820. content: "";
  821. height: 20px;
  822. width: 20px;
  823. left: 4px;
  824. bottom: 4px;
  825. background-color: white;
  826. transition: .4s;
  827. border-radius: 50%;
  828. }
  829.  
  830. input:checked + .slider {
  831. background-color: var(--success-color);
  832. }
  833.  
  834. input:focus + .slider {
  835. box-shadow: 0 0 1px var(--success-color);
  836. }
  837.  
  838. input:checked + .slider:before {
  839. transform: translateX(26px);
  840. }
  841.  
  842. /* Responsive */
  843. @media (max-width: 768px) {
  844. .grid-container {
  845. grid-template-columns: 1fr;
  846. }
  847.  
  848. .form-row {
  849. flex-direction: column;
  850. gap: 10px;
  851. }
  852.  
  853. .form-row .form-group {
  854. flex: 1 1 100%;
  855. }
  856.  
  857. .stat-container {
  858. justify-content: center;
  859. }
  860.  
  861. .image-upload {
  862. width: 150px;
  863. height: 150px;
  864. }
  865.  
  866. .tab {
  867. padding: 10px 15px;
  868. font-size: 0.9rem;
  869. }
  870.  
  871. .skill-container {
  872. grid-template-columns: 1fr;
  873. gap: 10px;
  874. }
  875.  
  876. .dice-selector {
  877. justify-content: center;
  878. }
  879.  
  880. .game-title {
  881. font-size: 2.2rem;
  882. }
  883.  
  884. .game-subtitle {
  885. font-size: 1.8rem;
  886. }
  887. }
  888. /* Add at the end of your existing CSS */
  889.  
  890. /* Moves Tab Styling */
  891. #moves-tab .controls {
  892. display: flex;
  893. justify-content: space-between;
  894. margin-bottom: 20px;
  895. align-items: center;
  896. }
  897.  
  898. .move-entry {
  899. background: rgba(255, 255, 255, 0.08);
  900. border-radius: 10px;
  901. padding: 15px;
  902. margin-bottom: 15px;
  903. position: relative;
  904. border: 1px solid var(--border-color);
  905. transition: all 0.3s ease;
  906. }
  907.  
  908. .move-entry:hover {
  909. box-shadow: 0 0 10px rgba(186, 104, 200, 0.3);
  910. }
  911.  
  912. .move-header {
  913. display: flex;
  914. justify-content: space-between;
  915. align-items: center;
  916. margin-bottom: 10px;
  917. }
  918.  
  919. .move-title {
  920. font-size: 1.2em;
  921. font-weight: bold;
  922. color: var(--primary-color);
  923. display: flex;
  924. align-items: center;
  925. }
  926.  
  927. .move-type {
  928. background-color: rgba(186, 104, 200, 0.2);
  929. padding: 4px 8px;
  930. border-radius: 12px;
  931. font-size: 0.8em;
  932. margin-left: 10px;
  933. }
  934.  
  935. .move-sp-cost {
  936. background-color: rgba(86, 144, 255, 0.2);
  937. padding: 4px 8px;
  938. border-radius: 12px;
  939. font-size: 0.8em;
  940. margin-left: 10px;
  941. }
  942.  
  943. .move-actions {
  944. display: flex;
  945. gap: 10px;
  946. }
  947.  
  948. .move-details {
  949. display: grid;
  950. grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  951. gap: 15px;
  952. margin-bottom: 15px;
  953. }
  954.  
  955. .move-description {
  956. grid-column: 1 / -1;
  957. }
  958.  
  959. .move-calculator {
  960. background: rgba(86, 144, 255, 0.1);
  961. border-radius: 10px;
  962. padding: 15px;
  963. margin-top: 30px;
  964. }
  965.  
  966. .calc-result {
  967. background: rgba(0, 0, 0, 0.2);
  968. padding: 10px;
  969. border-radius: 5px;
  970. margin-top: 15px;
  971. min-height: 50px;
  972. display: flex;
  973. align-items: center;
  974. font-family: 'Courier New', monospace;
  975. }
  976.  
  977. /* Move type colors */
  978. .move-type.attack {
  979. background-color: rgba(255, 86, 86, 0.2);
  980. }
  981.  
  982. .move-type.healing {
  983. background-color: rgba(86, 255, 86, 0.2);
  984. }
  985.  
  986. .move-type.buff {
  987. background-color: rgba(255, 217, 86, 0.2);
  988. }
  989.  
  990. .move-type.utility {
  991. background-color: rgba(86, 172, 255, 0.2);
  992. }
  993.  
  994. /* Move animation */
  995. @keyframes moveGlow {
  996. 0% { box-shadow: 0 0 5px rgba(186, 104, 200, 0.3); }
  997. 50% { box-shadow: 0 0 15px rgba(186, 104, 200, 0.5); }
  998. 100% { box-shadow: 0 0 5px rgba(186, 104, 200, 0.3); }
  999. }
  1000.  
  1001. .move-entry.performing {
  1002. animation: moveGlow 1s infinite;
  1003. }
  1004. </style>
  1005. </head>
  1006. <body>
  1007. <div class="main-container">
  1008. <div class="game-header">
  1009. <h1 class="game-title">DIGIMON: <span class="game-subtitle">WORLDS BEYOND THE CODE</span></h1>
  1010. </div>
  1011.  
  1012. <div class="tab-container">
  1013. <div class="tabs">
  1014. <div class="tab active" data-tab="character-tab">Character</div>
  1015. <div class="tab" data-tab="partner-tab">Partner</div>
  1016. <div class="tab" data-tab="skills-tab">Skills</div>
  1017. <div class="tab" data-tab="notes-tab">Notes</div>
  1018. <div class="tab" data-tab="class-skills-tab">Class Skills</div>
  1019. <div class="tab" data-tab="items-tab">Items</div>
  1020. <div class="tab" data-tab="mechs-tab">Mechs</div>
  1021. <div class="tab" data-tab="digimon-lines-tab">Digimon Lines</div>
  1022. <div class="tab" data-tab="rules-tab">Rules</div>
  1023. <div class="tab" data-tab="moves-tab">Moves</div>
  1024. <div class="tab" data-tab="partner-moves-tab">Partner Moves</div>
  1025. </div>
  1026.  
  1027. <div id="character-tab" class="tab-content active">
  1028. <div class="card">
  1029. <h2 class="card-title">Character Type</h2>
  1030. <div class="radio-container">
  1031. <label>
  1032. <input type="radio" name="characterType" value="tamer" checked> Tamer (Human)
  1033. </label>
  1034. <label>
  1035. <input type="radio" name="characterType" value="digimon"> Digimon
  1036. </label>
  1037. </div>
  1038.  
  1039. <div class="form-row">
  1040. <div class="form-group">
  1041. <label for="characterName">Name</label>
  1042. <input type="text" id="characterName" placeholder="Enter name">
  1043. </div>
  1044.  
  1045. <div class="form-group">
  1046. <label for="characterLevel">Level (1-99)</label>
  1047. <input type="number" id="characterLevel" min="1" max="99" value="1">
  1048. </div>
  1049.  
  1050. <div class="form-group">
  1051. <label for="characterExp">Experience Points</label>
  1052. <input type="number" id="characterExp" min="0" value="0">
  1053. </div>
  1054.  
  1055. <div class="form-group">
  1056. <label for="characterNextLevel">Next Level At</label>
  1057. <input type="number" id="characterNextLevel" value="10" disabled>
  1058. </div>
  1059.  
  1060. <div class="form-group tamer-only">
  1061. <label for="characterBackground">Background</label>
  1062. <select id="characterBackground">
  1063. <option value="">-- Select Background --</option>
  1064. <option value="courtesan">Courtesan</option>
  1065. <option value="adventurer">Adventurer</option>
  1066. <option value="diplomat">Diplomat</option>
  1067. <option value="farmer">Farmer</option>
  1068. <option value="janitor">Janitor</option>
  1069. <option value="sleuth">Sleuth</option>
  1070. <option value="slave">Slave</option>
  1071. <option value="wronged_hero">Wronged Hero</option>
  1072. <option value="doctor">Doctor</option>
  1073. <option value="carpenter">Carpenter</option>
  1074. <option value="child">Child</option>
  1075. <option value="explorer">Explorer</option>
  1076. <option value="fallen_noble">Fallen Noble</option>
  1077. <option value="student_of_magic">Student of Magic</option>
  1078. <option value="survivor">Survivor</option>
  1079. <option value="messenger">Messenger</option>
  1080. <option value="from_the_past">From The Past</option>
  1081. <option value="miner">Miner</option>
  1082. <option value="royalty">Royalty</option>
  1083. <option value="mute">Mute</option>
  1084. <option value="artist">Artist</option>
  1085. <option value="negotiator">Negotiator</option>
  1086. <option value="innkeeper">Innkeeper</option>
  1087. <option value="barmaid">Barmaid</option>
  1088. <option value="bartender">Bartender</option>
  1089. <option value="sex_slave">Sex Slave</option>
  1090. <option value="inventor">Inventor</option>
  1091. <option value="beggar">Beggar</option>
  1092. <option value="shepherd">Shepherd</option>
  1093. <option value="pilot">Pilot</option>
  1094. <option value="bodyguard">Bodyguard</option>
  1095. <option value="librarian">Librarian</option>
  1096. <option value="isekai">Isekai'd</option>
  1097. </select>
  1098. </div>
  1099.  
  1100. <div class="form-group digimon-only" style="display: none;">
  1101. <label for="digimonBackground">Background</label>
  1102. <select id="digimonBackground">
  1103. <option value="">-- Select Background --</option>
  1104. <option value="isekai">Isekai'd</option>
  1105. <option value="partnered">Partnered</option>
  1106. </select>
  1107. </div>
  1108.  
  1109. <div class="form-group">
  1110. <label for="characterRank">Rank</label>
  1111. <select id="characterRank">
  1112. <option value="in-training">None / In-Training (Levels 1-5)</option>
  1113. <option value="rookie">Copper / Rookie (Levels 6-20)</option>
  1114. <option value="champion">Silver / Champion (Levels 21-64)</option>
  1115. <option value="ultimate">Gold / Ultimate (Levels 65-99)</option>
  1116. <option value="mega">Platinum / Mega (Narrative)</option>
  1117. </select>
  1118. </div>
  1119. </div>
  1120.  
  1121. <div class="background-info" id="backgroundInfo">
  1122. <p>Select a background to see details</p>
  1123. </div>
  1124.  
  1125. <div class="form-group isekai-only" style="display: none;">
  1126. <h3>Isekai'd Stat Bonuses</h3>
  1127. <p>Select two stats to gain +2 bonus:</p>
  1128. <div class="checkbox-container">
  1129. <label><input type="checkbox" class="isekai-stat-bonus" value="baseHP"> Base HP</label>
  1130. <label><input type="checkbox" class="isekai-stat-bonus" value="baseSP"> Base SP</label>
  1131. <label><input type="checkbox" class="isekai-stat-bonus" value="str"> STR</label>
  1132. <label><input type="checkbox" class="isekai-stat-bonus" value="def"> DEF</label>
  1133. <label><input type="checkbox" class="isekai-stat-bonus" value="int"> INT</label>
  1134. <label><input type="checkbox" class="isekai-stat-bonus" value="agi"> AGI</label>
  1135. <label><input type="checkbox" class="isekai-stat-bonus" value="wil"> WIL</label>
  1136. </div>
  1137. </div>
  1138.  
  1139. <div class="image-upload">
  1140. <img id="characterImage" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzZhNWFjZCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxyZWN0IHg9IjMiIHk9IjMiIHdpZHRoPSIxOCIgaGVpZ2h0PSIxOCIgcng9IjIiIHJ5PSIyIj48L3JlY3Q+PGNpcmNsZSBjeD0iOC41IiBjeT0iOC41IiByPSIxLjUiPjwvY2lyY2xlPjxwb2x5bGluZSBwb2ludHM9IjIxIDE1IDEwIDIxIDMgMTUiPjwvcG9seWxpbmU+PC9zdmc+" alt="Character Image">
  1141. <button type="button" class="image-upload-btn" onclick="document.getElementById('characterImageUpload').click()">Add Image</button>
  1142. <input type="file" id="characterImageUpload" accept="image/*" style="display: none;" onchange="previewImage(this, 'characterImage')">
  1143. </div>
  1144. </div>
  1145.  
  1146. <div class="card">
  1147. <h2 class="card-title">Stats</h2>
  1148. <p>Available Points: <span id="statPointsRemaining">7</span></p>
  1149. <div class="form-row">
  1150. <div class="form-group">
  1151. <label for="baseHP">Base HP</label>
  1152. <input type="number" id="baseHP" min="1" max="20" value="1" class="stat-input">
  1153. </div>
  1154. <div class="form-group">
  1155. <label for="baseSP">Base SP</label>
  1156. <input type="number" id="baseSP" min="1" max="20" value="1" class="stat-input">
  1157. </div>
  1158. <div class="form-group">
  1159. <label for="str">STR</label>
  1160. <input type="number" id="str" min="1" max="20" value="1" class="stat-input">
  1161. </div>
  1162. <div class="form-group">
  1163. <label for="def">DEF</label>
  1164. <input type="number" id="def" min="1" max="20" value="1" class="stat-input">
  1165. </div>
  1166. <div class="form-group">
  1167. <label for="int">INT</label>
  1168. <input type="number" id="int" min="1" max="20" value="1" class="stat-input">
  1169. </div>
  1170. <div class="form-group">
  1171. <label for="agi">AGI</label>
  1172. <input type="number" id="agi" min="1" max="20" value="1" class="stat-input">
  1173. </div>
  1174. <div class="form-group">
  1175. <label for="wil">WIL</label>
  1176. <input type="number" id="wil" min="1" max="20" value="1" class="stat-input">
  1177. </div>
  1178. </div>
  1179.  
  1180. <div class="stat-container">
  1181. <div class="stat-box">
  1182. <div class="stat-name">Current HP</div>
  1183. <input type="number" id="currentHP" class="stat-value">
  1184. </div>
  1185. <div class="stat-box">
  1186. <div class="stat-name">Max HP</div>
  1187. <div class="stat-value" id="hp-value">-</div>
  1188. </div>
  1189. <div class="stat-box">
  1190. <div class="stat-name">Current SP</div>
  1191. <input type="number" id="currentSP" class="stat-value">
  1192. </div>
  1193. <div class="stat-box">
  1194. <div class="stat-name">Max SP</div>
  1195. <div class="stat-value" id="sp-value">-</div>
  1196. </div>
  1197. </div>
  1198. </div>
  1199.  
  1200. <div class="dice-roller">
  1201. <h3>Dice Roller</h3>
  1202. <div class="form-row">
  1203. <div class="form-group">
  1204. <select id="diceType">
  1205. <option value="d4">d4 (In-Training)</option>
  1206. <option value="d6">d6 (Rookie)</option>
  1207. <option value="d8">d8 (Champion)</option>
  1208. <option value="d12">d12 (Ultimate)</option>
  1209. <option value="d20">d20 (Mega)</option>
  1210. </select>
  1211. </div>
  1212. <button type="button" onclick="rollDice()">Roll</button>
  1213. </div>
  1214. <div id="rollResult"></div>
  1215. </div>
  1216. </div>
  1217.  
  1218. <div id="partner-tab" class="tab-content">
  1219. <div class="card">
  1220. <h2 class="card-title">Partner</h2>
  1221. <div class="form-row">
  1222. <div class="form-group">
  1223. <label for="partnerName">Name</label>
  1224. <input type="text" id="partnerName" placeholder="Enter partner name">
  1225. </div>
  1226.  
  1227. <div class="form-group">
  1228. <label for="partnerLevel">Level (1-99)</label>
  1229. <input type="number" id="partnerLevel" min="1" max="99" value="1">
  1230. </div>
  1231.  
  1232. <div class="form-group">
  1233. <label for="partnerExp">Experience Points</label>
  1234. <input type="number" id="partnerExp" min="0" value="0">
  1235. </div>
  1236.  
  1237. <div class="form-group">
  1238. <label for="partnerNextLevel">Next Level At</label>
  1239. <input type="number" id="partnerNextLevel" value="10" disabled>
  1240. </div>
  1241.  
  1242. <div class="form-group">
  1243. <label for="partnerType">Type</label>
  1244. <select id="partnerType">
  1245. <option value="digimon">Digimon</option>
  1246. <option value="tamer">Human</option>
  1247. </select>
  1248. </div>
  1249.  
  1250. <div class="form-group partner-tamer-only" style="display: none;">
  1251. <label for="partnerHumanBackground">Background</label>
  1252. <select id="partnerHumanBackground">
  1253. <option value="">-- Select Background --</option>
  1254. <option value="courtesan">Courtesan</option>
  1255. <option value="adventurer">Adventurer</option>
  1256. <option value="diplomat">Diplomat</option>
  1257. <option value="farmer">Farmer</option>
  1258. <option value="janitor">Janitor</option>
  1259. <option value="sleuth">Sleuth</option>
  1260. <option value="slave">Slave</option>
  1261. <option value="wronged_hero">Wronged Hero</option>
  1262. <option value="doctor">Doctor</option>
  1263. <option value="carpenter">Carpenter</option>
  1264. <option value="child">Child</option>
  1265. <option value="explorer">Explorer</option>
  1266. <option value="fallen_noble">Fallen Noble</option>
  1267. <option value="student_of_magic">Student of Magic</option>
  1268. <option value="survivor">Survivor</option>
  1269. <option value="messenger">Messenger</option>
  1270. <option value="from_the_past">From The Past</option>
  1271. <option value="miner">Miner</option>
  1272. <option value="royalty">Royalty</option>
  1273. <option value="mute">Mute</option>
  1274. <option value="artist">Artist</option>
  1275. <option value="negotiator">Negotiator</option>
  1276. <option value="innkeeper">Innkeeper</option>
  1277. <option value="barmaid">Barmaid</option>
  1278. <option value="bartender">Bartender</option>
  1279. <option value="sex_slave">Sex Slave</option>
  1280. <option value="inventor">Inventor</option>
  1281. <option value="beggar">Beggar</option>
  1282. <option value="shepherd">Shepherd</option>
  1283. <option value="pilot">Pilot</option>
  1284. <option value="bodyguard">Bodyguard</option>
  1285. <option value="librarian">Librarian</option>
  1286. <option value="isekai">Isekai'd</option>
  1287. </select>
  1288. </div>
  1289.  
  1290. <div class="form-group partner-digimon-only">
  1291. <label for="partnerDigimonBackground">Background</label>
  1292. <select id="partnerDigimonBackground">
  1293. <option value="">-- Select Background --</option>
  1294. <option value="isekai">Isekai'd</option>
  1295. <option value="partnered">Partnered</option>
  1296. </select>
  1297. </div>
  1298.  
  1299. <div class="form-group">
  1300. <label for="partnerRank">Rank</label>
  1301. <select id="partnerRank">
  1302. <option value="in-training">None / In-Training (Levels 1-5)</option>
  1303. <option value="rookie">Copper / Rookie (Levels 6-20)</option>
  1304. <option value="champion">Silver / Champion (Levels 21-64)</option>
  1305. <option value="ultimate">Gold / Ultimate (Levels 65-99)</option>
  1306. <option value="mega">Platinum / Mega (Narrative)</option>
  1307. </select>
  1308. </div>
  1309. </div>
  1310.  
  1311. <div class="background-info" id="partnerBackgroundInfo">
  1312. <p>Select a background to see details</p>
  1313. </div>
  1314.  
  1315. <div class="form-group partner-isekai-only" style="display: none;">
  1316. <h3>Partner Isekai'd Stat Bonuses</h3>
  1317. <p>Select two stats to gain +2 bonus:</p>
  1318. <div class="checkbox-container">
  1319. <label><input type="checkbox" class="partner-isekai-stat-bonus" value="partnerBaseHP"> Base HP</label>
  1320. <label><input type="checkbox" class="partner-isekai-stat-bonus" value="partnerBaseSP"> Base SP</label>
  1321. <label><input type="checkbox" class="partner-isekai-stat-bonus" value="partner-str"> STR</label>
  1322. <label><input type="checkbox" class="partner-isekai-stat-bonus" value="partner-def"> DEF</label>
  1323. <label><input type="checkbox" class="partner-isekai-stat-bonus" value="partner-int"> INT</label>
  1324. <label><input type="checkbox" class="partner-isekai-stat-bonus" value="partner-agi"> AGI</label>
  1325. <label><input type="checkbox" class="partner-isekai-stat-bonus" value="partner-wil"> WIL</label>
  1326. </div>
  1327. </div>
  1328.  
  1329. <div class="image-upload">
  1330. <img id="partnerImage" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzZhNWFjZCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxyZWN0IHg9IjMiIHk9IjMiIHdpZHRoPSIxOCIgaGVpZ2h0PSIxOCIgcng9IjIiIHJ5PSIyIj48L3JlY3Q+PGNpcmNsZSBjeD0iOC41IiBjeT0iOC41IiByPSIxLjUiPjwvY2lyY2xlPjxwb2x5bGluZSBwb2ludHM9IjIxIDE1IDEwIDIxIDMgMTUiPjwvcG9seWxpbmU+PC9zdmc+" alt="Partner Image">
  1331. <button type="button" class="image-upload-btn" onclick="document.getElementById('partnerImageUpload').click()">Add Image</button>
  1332. <input type="file" id="partnerImageUpload" accept="image/*" style="display: none;" onchange="previewImage(this, 'partnerImage')">
  1333. </div>
  1334. </div>
  1335.  
  1336. <div class="card">
  1337. <h2 class="card-title">Partner Stats</h2>
  1338. <p>Available Points: <span id="partnerStatPointsRemaining">7</span></p>
  1339. <div class="form-row">
  1340. <div class="form-group">
  1341. <label for="partnerBaseHP">Base HP</label>
  1342. <input type="number" id="partnerBaseHP" min="1" max="20" value="1" class="partner-stat-input">
  1343. </div>
  1344. <div class="form-group">
  1345. <label for="partnerBaseSP">Base SP</label>
  1346. <input type="number" id="partnerBaseSP" min="1" max="20" value="1" class="partner-stat-input">
  1347. </div>
  1348. <div class="form-group">
  1349. <label for="partner-str">STR</label>
  1350. <input type="number" id="partner-str" min="1" max="20" value="1" class="partner-stat-input">
  1351. </div>
  1352. <div class="form-group">
  1353. <label for="partner-def">DEF</label>
  1354. <input type="number" id="partner-def" min="1" max="20" value="1" class="partner-stat-input">
  1355. </div>
  1356. <div class="form-group">
  1357. <label for="partner-int">INT</label>
  1358. <input type="number" id="partner-int" min="1" max="20" value="1" class="partner-stat-input">
  1359. </div>
  1360. <div class="form-group">
  1361. <label for="partner-agi">AGI</label>
  1362. <input type="number" id="partner-agi" min="1" max="20" value="1" class="partner-stat-input">
  1363. </div>
  1364. <div class="form-group">
  1365. <label for="partner-wil">WIL</label>
  1366. <input type="number" id="partner-wil" min="1" max="20" value="1" class="partner-stat-input">
  1367. </div>
  1368. </div>
  1369.  
  1370. <div class="stat-container">
  1371. <div class="stat-box">
  1372. <div class="stat-name">Current HP</div>
  1373. <input type="number" id="partnerCurrentHP" class="stat-value">
  1374. </div>
  1375. <div class="stat-box">
  1376. <div class="stat-name">Max HP</div>
  1377. <div class="stat-value" id="partner-hp-value">-</div>
  1378. </div>
  1379. <div class="stat-box">
  1380. <div class="stat-name">Current SP</div>
  1381. <input type="number" id="partnerCurrentSP" class="stat-value">
  1382. </div>
  1383. <div class="stat-box">
  1384. <div class="stat-name">Max SP</div>
  1385. <div class="stat-value" id="partner-sp-value">-</div>
  1386. </div>
  1387. </div>
  1388. </div>
  1389. </div>
  1390.  
  1391. <div id="skills-tab" class="tab-content">
  1392. <div class="card">
  1393. <h2 class="card-title">Skills</h2>
  1394. <p>Click on the appropriate dice to set your proficiency level.</p>
  1395.  
  1396. <h3>Character Skills</h3>
  1397. <div class="skill-container">
  1398. <div class="skill-name">
  1399. Dodge <span class="skill-stat">(AGI)</span>
  1400. </div>
  1401. <div class="dice-selector" data-skill="dodge">
  1402. <label class="dice-option">
  1403. <input type="radio" name="dodge" value="none" checked> None
  1404. </label>
  1405. <label class="dice-option">
  1406. <input type="radio" name="dodge" value="d6"> d6
  1407. </label>
  1408. <label class="dice-option">
  1409. <input type="radio" name="dodge" value="d8"> d8
  1410. </label>
  1411. <label class="dice-option">
  1412. <input type="radio" name="dodge" value="d12"> d12
  1413. </label>
  1414. <label class="dice-option">
  1415. <input type="radio" name="dodge" value="d20"> d20
  1416. </label>
  1417. </div>
  1418. <button type="button" onclick="rollSkill('dodge')">Roll</button>
  1419. </div>
  1420.  
  1421. <div class="skill-container">
  1422. <div class="skill-name">
  1423. Fight <span class="skill-stat">(STR)</span>
  1424. </div>
  1425. <div class="dice-selector" data-skill="fight">
  1426. <label class="dice-option">
  1427. <input type="radio" name="fight" value="none" checked> None
  1428. </label>
  1429. <label class="dice-option">
  1430. <input type="radio" name="fight" value="d6"> d6
  1431. </label>
  1432. <label class="dice-option">
  1433. <input type="radio" name="fight" value="d8"> d8
  1434. </label>
  1435. <label class="dice-option">
  1436. <input type="radio" name="fight" value="d12"> d12
  1437. </label>
  1438. <label class="dice-option">
  1439. <input type="radio" name="fight" value="d20"> d20
  1440. </label>
  1441. </div>
  1442. <button type="button" onclick="rollSkill('fight')">Roll</button>
  1443. </div>
  1444.  
  1445. <div class="skill-container">
  1446. <div class="skill-name">
  1447. Stealth <span class="skill-stat">(AGI)</span>
  1448. </div>
  1449. <div class="dice-selector" data-skill="stealth">
  1450. <label class="dice-option">
  1451. <input type="radio" name="stealth" value="none" checked> None
  1452. </label>
  1453. <label class="dice-option">
  1454. <input type="radio" name="stealth" value="d6"> d6
  1455. </label>
  1456. <label class="dice-option">
  1457. <input type="radio" name="stealth" value="d8"> d8
  1458. </label>
  1459. <label class="dice-option">
  1460. <input type="radio" name="stealth" value="d12"> d12
  1461. </label>
  1462. <label class="dice-option">
  1463. <input type="radio" name="stealth" value="d20"> d20
  1464. </label>
  1465. </div>
  1466. <button type="button" onclick="rollSkill('stealth')">Roll</button>
  1467. </div>
  1468.  
  1469. <div class="skill-container">
  1470. <div class="skill-name">
  1471. Manipulate <span class="skill-stat">(WIL)</span>
  1472. </div>
  1473. <div class="dice-selector" data-skill="manipulate">
  1474. <label class="dice-option">
  1475. <input type="radio" name="manipulate" value="none" checked> None
  1476. </label>
  1477. <label class="dice-option">
  1478. <input type="radio" name="manipulate" value="d6"> d6
  1479. </label>
  1480. <label class="dice-option">
  1481. <input type="radio" name="manipulate" value="d8"> d8
  1482. </label>
  1483. <label class="dice-option">
  1484. <input type="radio" name="manipulate" value="d12"> d12
  1485. </label>
  1486. <label class="dice-option">
  1487. <input type="radio" name="manipulate" value="d20"> d20
  1488. </label>
  1489. </div>
  1490. <button type="button" onclick="rollSkill('manipulate')">Roll</button>
  1491. </div>
  1492.  
  1493. <div class="skill-container">
  1494. <div class="skill-name">
  1495. Perform <span class="skill-stat">(WIL)</span>
  1496. </div>
  1497. <div class="dice-selector" data-skill="perform">
  1498. <label class="dice-option">
  1499. <input type="radio" name="perform" value="none" checked> None
  1500. </label>
  1501. <label class="dice-option">
  1502. <input type="radio" name="perform" value="d6"> d6
  1503. </label>
  1504. <label class="dice-option">
  1505. <input type="radio" name="perform" value="d8"> d8
  1506. </label>
  1507. <label class="dice-option">
  1508. <input type="radio" name="perform" value="d12"> d12
  1509. </label>
  1510. <label class="dice-option">
  1511. <input type="radio" name="perform" value="d20"> d20
  1512. </label>
  1513. </div>
  1514. <button type="button" onclick="rollSkill('perform')">Roll</button>
  1515. </div>
  1516.  
  1517. <div class="skill-container">
  1518. <div class="skill-name">
  1519. Persuade <span class="skill-stat">(WIL)</span>
  1520. </div>
  1521. <div class="dice-selector" data-skill="persuade">
  1522. <label class="dice-option">
  1523. <input type="radio" name="persuade" value="none" checked> None
  1524. </label>
  1525. <label class="dice-option">
  1526. <input type="radio" name="persuade" value="d6"> d6
  1527. </label>
  1528. <label class="dice-option">
  1529. <input type="radio" name="persuade" value="d8"> d8
  1530. </label>
  1531. <label class="dice-option">
  1532. <input type="radio" name="persuade" value="d12"> d12
  1533. </label>
  1534. <label class="dice-option">
  1535. <input type="radio" name="persuade" value="d20"> d20
  1536. </label>
  1537. </div>
  1538. <button type="button" onclick="rollSkill('persuade')">Roll</button>
  1539. </div>
  1540.  
  1541. <div class="skill-container">
  1542. <div class="skill-name">
  1543. Survival <span class="skill-stat">(AGI)</span>
  1544. </div>
  1545. <div class="dice-selector" data-skill="survival">
  1546. <label class="dice-option">
  1547. <input type="radio" name="survival" value="none" checked> None
  1548. </label>
  1549. <label class="dice-option">
  1550. <input type="radio" name="survival" value="d6"> d6
  1551. </label>
  1552. <label class="dice-option">
  1553. <input type="radio" name="survival" value="d8"> d8
  1554. </label>
  1555. <label class="dice-option">
  1556. <input type="radio" name="survival" value="d12"> d12
  1557. </label>
  1558. <label class="dice-option">
  1559. <input type="radio" name="survival" value="d20"> d20
  1560. </label>
  1561. </div>
  1562. <button type="button" onclick="rollSkill('survival')">Roll</button>
  1563. </div>
  1564.  
  1565. <div class="skill-container">
  1566. <div class="skill-name">
  1567. Perception <span class="skill-stat">(AGI)</span>
  1568. </div>
  1569. <div class="dice-selector" data-skill="perception">
  1570. <label class="dice-option">
  1571. <input type="radio" name="perception" value="none" checked> None
  1572. </label>
  1573. <label class="dice-option">
  1574. <input type="radio" name="perception" value="d6"> d6
  1575. </label>
  1576. <label class="dice-option">
  1577. <input type="radio" name="perception" value="d8"> d8
  1578. </label>
  1579. <label class="dice-option">
  1580. <input type="radio" name="perception" value="d12"> d12
  1581. </label>
  1582. <label class="dice-option">
  1583. <input type="radio" name="perception" value="d20"> d20
  1584. </label>
  1585. </div>
  1586. <button type="button" onclick="rollSkill('perception')">Roll</button>
  1587. </div>
  1588.  
  1589. <h3>Knowledge Skills</h3>
  1590.  
  1591. <div class="skill-container">
  1592. <div class="skill-name">
  1593. Knowledge: Digimon <span class="skill-stat">(INT)</span>
  1594. </div>
  1595. <div class="dice-selector" data-skill="knowledge_digimon">
  1596. <label class="dice-option">
  1597. <input type="radio" name="knowledge_digimon" value="none" checked> None
  1598. </label>
  1599. <label class="dice-option">
  1600. <input type="radio" name="knowledge_digimon" value="d6"> d6
  1601. </label>
  1602. <label class="dice-option">
  1603. <input type="radio" name="knowledge_digimon" value="d8"> d8
  1604. </label>
  1605. <label class="dice-option">
  1606. <input type="radio" name="knowledge_digimon" value="d12"> d12
  1607. </label>
  1608. <label class="dice-option">
  1609. <input type="radio" name="knowledge_digimon" value="d20"> d20
  1610. </label>
  1611. </div>
  1612. <button type="button" onclick="rollSkill('knowledge_digimon')">Roll</button>
  1613. </div>
  1614.  
  1615. <div class="skill-container">
  1616. <div class="skill-name">
  1617. Knowledge: Human <span class="skill-stat">(WIL)</span>
  1618. </div>
  1619. <div class="dice-selector" data-skill="knowledge_human">
  1620. <label class="dice-option">
  1621. <input type="radio" name="knowledge_human" value="none" checked> None
  1622. </label>
  1623. <label class="dice-option">
  1624. <input type="radio" name="knowledge_human" value="d6"> d6
  1625. </label>
  1626. <label class="dice-option">
  1627. <input type="radio" name="knowledge_human" value="d8"> d8
  1628. </label>
  1629. <label class="dice-option">
  1630. <input type="radio" name="knowledge_human" value="d12"> d12
  1631. </label>
  1632. <label class="dice-option">
  1633. <input type="radio" name="knowledge_human" value="d20"> d20
  1634. </label>
  1635. </div>
  1636. <button type="button" onclick="rollSkill('knowledge_human')">Roll</button>
  1637. </div>
  1638.  
  1639. <div class="skill-container">
  1640. <div class="skill-name">
  1641. Knowledge: Local <span class="skill-stat">(INT)</span>
  1642. </div>
  1643. <div class="dice-selector" data-skill="knowledge_local">
  1644. <label class="dice-option">
  1645. <input type="radio" name="knowledge_local" value="none" checked> None
  1646. </label>
  1647. <label class="dice-option">
  1648. <input type="radio" name="knowledge_local" value="d6"> d6
  1649. </label>
  1650. <label class="dice-option">
  1651. <input type="radio" name="knowledge_local" value="d8"> d8
  1652. </label>
  1653. <label class="dice-option">
  1654. <input type="radio" name="knowledge_local" value="d12"> d12
  1655. </label>
  1656. <label class="dice-option">
  1657. <input type="radio" name="knowledge_local" value="d20"> d20
  1658. </label>
  1659. </div>
  1660. <button type="button" onclick="rollSkill('knowledge_local')">Roll</button>
  1661. </div>
  1662.  
  1663. <div class="skill-container">
  1664. <div class="skill-name">
  1665. Knowledge: Region <span class="skill-stat">(INT)</span>
  1666. </div>
  1667. <div class="dice-selector" data-skill="knowledge_region">
  1668. <label class="dice-option">
  1669. <input type="radio" name="knowledge_region" value="none" checked> None
  1670. </label>
  1671. <label class="dice-option">
  1672. <input type="radio" name="knowledge_region" value="d6"> d6
  1673. </label>
  1674. <label class="dice-option">
  1675. <input type="radio" name="knowledge_region" value="d8"> d8
  1676. </label>
  1677. <label class="dice-option">
  1678. <input type="radio" name="knowledge_region" value="d12"> d12
  1679. </label>
  1680. <label class="dice-option">
  1681. <input type="radio" name="knowledge_region" value="d20"> d20
  1682. </label>
  1683. </div>
  1684. <button type="button" onclick="rollSkill('knowledge_region')">Roll</button>
  1685. </div>
  1686.  
  1687. <div class="skill-container">
  1688. <div class="skill-name">
  1689. Knowledge: Trapper <span class="skill-stat">(AGI)</span>
  1690. </div>
  1691. <div class="dice-selector" data-skill="knowledge_trapper">
  1692. <label class="dice-option">
  1693. <input type="radio" name="knowledge_trapper" value="none" checked> None
  1694. </label>
  1695. <label class="dice-option">
  1696. <input type="radio" name="knowledge_trapper" value="d6"> d6
  1697. </label>
  1698. <label class="dice-option">
  1699. <input type="radio" name="knowledge_trapper" value="d8"> d8
  1700. </label>
  1701. <label class="dice-option">
  1702. <input type="radio" name="knowledge_trapper" value="d12"> d12
  1703. </label>
  1704. <label class="dice-option">
  1705. <input type="radio" name="knowledge_trapper" value="d20"> d20
  1706. </label>
  1707. </div>
  1708. <button type="button" onclick="rollSkill('knowledge_trapper')">Roll</button>
  1709. </div>
  1710.  
  1711. <div class="skill-container">
  1712. <div class="skill-name">
  1713. Knowledge: Smith <span class="skill-stat">(WIL)</span>
  1714. </div>
  1715. <div class="dice-selector" data-skill="knowledge_smith">
  1716. <label class="dice-option">
  1717. <input type="radio" name="knowledge_smith" value="none" checked> None
  1718. </label>
  1719. <label class="dice-option">
  1720. <input type="radio" name="knowledge_smith" value="d6"> d6
  1721. </label>
  1722. <label class="dice-option">
  1723. <input type="radio" name="knowledge_smith" value="d8"> d8
  1724. </label>
  1725. <label class="dice-option">
  1726. <input type="radio" name="knowledge_smith" value="d12"> d12
  1727. </label>
  1728. <label class="dice-option">
  1729. <input type="radio" name="knowledge_smith" value="d20"> d20
  1730. </label>
  1731. </div>
  1732. <button type="button" onclick="rollSkill('knowledge_smith')">Roll</button>
  1733. </div>
  1734.  
  1735. <div class="skill-container">
  1736. <div class="skill-name">
  1737. Knowledge: Carpenter <span class="skill-stat">(WIL)</span>
  1738. </div>
  1739. <div class="dice-selector" data-skill="knowledge_carpenter">
  1740. <label class="dice-option">
  1741. <input type="radio" name="knowledge_carpenter" value="none" checked> None
  1742. </label>
  1743. <label class="dice-option">
  1744. <input type="radio" name="knowledge_carpenter" value="d6"> d6
  1745. </label>
  1746. <label class="dice-option">
  1747. <input type="radio" name="knowledge_carpenter" value="d8"> d8
  1748. </label>
  1749. <label class="dice-option">
  1750. <input type="radio" name="knowledge_carpenter" value="d12"> d12
  1751. </label>
  1752. <label class="dice-option">
  1753. <input type="radio" name="knowledge_carpenter" value="d20"> d20
  1754. </label>
  1755. </div>
  1756. <button type="button" onclick="rollSkill('knowledge_carpenter')">Roll</button>
  1757. </div>
  1758.  
  1759. <div class="skill-container">
  1760. <div class="skill-name">
  1761. Knowledge: Handyman <span class="skill-stat">(INT)</span>
  1762. </div>
  1763. <div class="dice-selector" data-skill="knowledge_handyman">
  1764. <label class="dice-option">
  1765. <input type="radio" name="knowledge_handyman" value="none" checked> None
  1766. </label>
  1767. <label class="dice-option">
  1768. <input type="radio" name="knowledge_handyman" value="d6"> d6
  1769. </label>
  1770. <label class="dice-option">
  1771. <input type="radio" name="knowledge_handyman" value="d8"> d8
  1772. </label>
  1773. <label class="dice-option">
  1774. <input type="radio" name="knowledge_handyman" value="d12"> d12
  1775. </label>
  1776. <label class="dice-option">
  1777. <input type="radio" name="knowledge_handyman" value="d20"> d20
  1778. </label>
  1779. </div>
  1780. <button type="button" onclick="rollSkill('knowledge_handyman')">Roll</button>
  1781. </div>
  1782.  
  1783. <div class="skill-container">
  1784. <div class="skill-name">
  1785. Knowledge: Cook <span class="skill-stat">(WIL)</span>
  1786. </div>
  1787. <div class="dice-selector" data-skill="knowledge_cook">
  1788. <label class="dice-option">
  1789. <input type="radio" name="knowledge_cook" value="none" checked> None
  1790. </label>
  1791. <label class="dice-option">
  1792. <input type="radio" name="knowledge_cook" value="d6"> d6
  1793. </label>
  1794. <label class="dice-option">
  1795. <input type="radio" name="knowledge_cook" value="d8"> d8
  1796. </label>
  1797. <label class="dice-option">
  1798. <input type="radio" name="knowledge_cook" value="d12"> d12
  1799. </label>
  1800. <label class="dice-option">
  1801. <input type="radio" name="knowledge_cook" value="d20"> d20
  1802. </label>
  1803. </div>
  1804. <button type="button" onclick="rollSkill('knowledge_cook')">Roll</button>
  1805. </div>
  1806.  
  1807. <div class="skill-container">
  1808. <div class="skill-name">
  1809. Knowledge: Hacking <span class="skill-stat">(INT)</span>
  1810. </div>
  1811. <div class="dice-selector" data-skill="knowledge_hacking">
  1812. <label class="dice-option">
  1813. <input type="radio" name="knowledge_hacking" value="none" checked> None
  1814. </label>
  1815. <label class="dice-option">
  1816. <input type="radio" name="knowledge_hacking" value="d6"> d6
  1817. </label>
  1818. <label class="dice-option">
  1819. <input type="radio" name="knowledge_hacking" value="d8"> d8
  1820. </label>
  1821. <label class="dice-option">
  1822. <input type="radio" name="knowledge_hacking" value="d12"> d12
  1823. </label>
  1824. <label class="dice-option">
  1825. <input type="radio" name="knowledge_hacking" value="d20"> d20
  1826. </label>
  1827. </div>
  1828. <button type="button" onclick="rollSkill('knowledge_hacking')">Roll</button>
  1829. </div>
  1830.  
  1831. <div class="skill-container">
  1832. <div class="skill-name">
  1833. Knowledge: Engineering <span class="skill-stat">(INT)</span>
  1834. </div>
  1835. <div class="dice-selector" data-skill="knowledge_engineering">
  1836. <label class="dice-option">
  1837. <input type="radio" name="knowledge_engineering" value="none" checked> None
  1838. </label>
  1839. <label class="dice-option">
  1840. <input type="radio" name="knowledge_engineering" value="d6"> d6
  1841. </label>
  1842. <label class="dice-option">
  1843. <input type="radio" name="knowledge_engineering" value="d8"> d8
  1844. </label>
  1845. <label class="dice-option">
  1846. <input type="radio" name="knowledge_engineering" value="d12"> d12
  1847. </label>
  1848. <label class="dice-option">
  1849. <input type="radio" name="knowledge_engineering" value="d20"> d20
  1850. </label>
  1851. </div>
  1852. <button type="button" onclick="rollSkill('knowledge_engineering')">Roll</button>
  1853. </div>
  1854. </div>
  1855.  
  1856. <div class="card">
  1857. <h2 class="card-title">Partner Skills</h2>
  1858. <div id="partnerSkillsContainer">
  1859. <!-- Partner skills set up -->
  1860. <div class="skill-container">
  1861. <div class="skill-name">
  1862. Partner Dodge <span class="skill-stat">(AGI)</span>
  1863. </div>
  1864. <div class="dice-selector" data-skill="partner_dodge">
  1865. <label class="dice-option">
  1866. <input type="radio" name="partner_dodge" value="none" checked> None
  1867. </label>
  1868. <label class="dice-option">
  1869. <input type="radio" name="partner_dodge" value="d6"> d6
  1870. </label>
  1871. <label class="dice-option">
  1872. <input type="radio" name="partner_dodge" value="d8"> d8
  1873. </label>
  1874. <label class="dice-option">
  1875. <input type="radio" name="partner_dodge" value="d12"> d12
  1876. </label>
  1877. <label class="dice-option">
  1878. <input type="radio" name="partner_dodge" value="d20"> d20
  1879. </label>
  1880. </div>
  1881. <button type="button" onclick="rollPartnerSkill('partner_dodge', 'agi')">Roll</button>
  1882. </div>
  1883.  
  1884. <div class="skill-container">
  1885. <div class="skill-name">
  1886. Partner Fight <span class="skill-stat">(STR)</span>
  1887. </div>
  1888. <div class="dice-selector" data-skill="partner_fight">
  1889. <label class="dice-option">
  1890. <input type="radio" name="partner_fight" value="none" checked> None
  1891. </label>
  1892. <label class="dice-option">
  1893. <input type="radio" name="partner_fight" value="d6"> d6
  1894. </label>
  1895. <label class="dice-option">
  1896. <input type="radio" name="partner_fight" value="d8"> d8
  1897. </label>
  1898. <label class="dice-option">
  1899. <input type="radio" name="partner_fight" value="d12"> d12
  1900. </label>
  1901. <label class="dice-option">
  1902. <input type="radio" name="partner_fight" value="d20"> d20
  1903. </label>
  1904. </div>
  1905. <button type="button" onclick="rollPartnerSkill('partner_fight', 'str')">Roll</button>
  1906. </div>
  1907.  
  1908. <div class="skill-container">
  1909. <div class="skill-name">
  1910. Partner Stealth <span class="skill-stat">(AGI)</span>
  1911. </div>
  1912. <div class="dice-selector" data-skill="partner_stealth">
  1913. <label class="dice-option">
  1914. <input type="radio" name="partner_stealth" value="none" checked> None
  1915. </label>
  1916. <label class="dice-option">
  1917. <input type="radio" name="partner_stealth" value="d6"> d6
  1918. </label>
  1919. <label class="dice-option">
  1920. <input type="radio" name="partner_stealth" value="d8"> d8
  1921. </label>
  1922. <label class="dice-option">
  1923. <input type="radio" name="partner_stealth" value="d12"> d12
  1924. </label>
  1925. <label class="dice-option">
  1926. <input type="radio" name="partner_stealth" value="d20"> d20
  1927. </label>
  1928. </div>
  1929. <button type="button" onclick="rollPartnerSkill('partner_stealth', 'agi')">Roll</button>
  1930. </div>
  1931.  
  1932. <div class="skill-container">
  1933. <div class="skill-name">
  1934. Partner Manipulate <span class="skill-stat">(WIL)</span>
  1935. </div>
  1936. <div class="dice-selector" data-skill="partner_manipulate">
  1937. <label class="dice-option">
  1938. <input type="radio" name="partner_manipulate" value="none" checked> None
  1939. </label>
  1940. <label class="dice-option">
  1941. <input type="radio" name="partner_manipulate" value="d6"> d6
  1942. </label>
  1943. <label class="dice-option">
  1944. <input type="radio" name="partner_manipulate" value="d8"> d8
  1945. </label>
  1946. <label class="dice-option">
  1947. <input type="radio" name="partner_manipulate" value="d12"> d12
  1948. </label>
  1949. <label class="dice-option">
  1950. <input type="radio" name="partner_manipulate" value="d20"> d20
  1951. </label>
  1952. </div>
  1953. <button type="button" onclick="rollPartnerSkill('partner_manipulate', 'wil')">Roll</button>
  1954. </div>
  1955.  
  1956. <div class="skill-container">
  1957. <div class="skill-name">
  1958. Partner Perform <span class="skill-stat">(WIL)</span>
  1959. </div>
  1960. <div class="dice-selector" data-skill="partner_perform">
  1961. <label class="dice-option">
  1962. <input type="radio" name="partner_perform" value="none" checked> None
  1963. </label>
  1964. <label class="dice-option">
  1965. <input type="radio" name="partner_perform" value="d6"> d6
  1966. </label>
  1967. <label class="dice-option">
  1968. <input type="radio" name="partner_perform" value="d8"> d8
  1969. </label>
  1970. <label class="dice-option">
  1971. <input type="radio" name="partner_perform" value="d12"> d12
  1972. </label>
  1973. <label class="dice-option">
  1974. <input type="radio" name="partner_perform" value="d20"> d20
  1975. </label>
  1976. </div>
  1977. <button type="button" onclick="rollPartnerSkill('partner_perform', 'wil')">Roll</button>
  1978. </div>
  1979.  
  1980. <div class="skill-container">
  1981. <div class="skill-name">
  1982. Partner Persuade <span class="skill-stat">(WIL)</span>
  1983. </div>
  1984. <div class="dice-selector" data-skill="partner_persuade">
  1985. <label class="dice-option">
  1986. <input type="radio" name="partner_persuade" value="none" checked> None
  1987. </label>
  1988. <label class="dice-option">
  1989. <input type="radio" name="partner_persuade" value="d6"> d6
  1990. </label>
  1991. <label class="dice-option">
  1992. <input type="radio" name="partner_persuade" value="d8"> d8
  1993. </label>
  1994. <label class="dice-option">
  1995. <input type="radio" name="partner_persuade" value="d12"> d12
  1996. </label>
  1997. <label class="dice-option">
  1998. <input type="radio" name="partner_persuade" value="d20"> d20
  1999. </label>
  2000. </div>
  2001. <button type="button" onclick="rollPartnerSkill('partner_persuade', 'wil')">Roll</button>
  2002. </div>
  2003.  
  2004. <div class="skill-container">
  2005. <div class="skill-name">
  2006. Partner Survival <span class="skill-stat">(AGI)</span>
  2007. </div>
  2008. <div class="dice-selector" data-skill="partner_survival">
  2009. <label class="dice-option">
  2010. <input type="radio" name="partner_survival" value="none" checked> None
  2011. </label>
  2012. <label class="dice-option">
  2013. <input type="radio" name="partner_survival" value="d6"> d6
  2014. </label>
  2015. <label class="dice-option">
  2016. <input type="radio" name="partner_survival" value="d8"> d8
  2017. </label>
  2018. <label class="dice-option">
  2019. <input type="radio" name="partner_survival" value="d12"> d12
  2020. </label>
  2021. <label class="dice-option">
  2022. <input type="radio" name="partner_survival" value="d20"> d20
  2023. </label>
  2024. </div>
  2025. <button type="button" onclick="rollPartnerSkill('partner_survival', 'agi')">Roll</button>
  2026. </div>
  2027.  
  2028. <div class="skill-container">
  2029. <div class="skill-name">
  2030. Partner Perception <span class="skill-stat">(AGI)</span>
  2031. </div>
  2032. <div class="dice-selector" data-skill="partner_perception">
  2033. <label class="dice-option">
  2034. <input type="radio" name="partner_perception" value="none" checked> None
  2035. </label>
  2036. <label class="dice-option">
  2037. <input type="radio" name="partner_perception" value="d6"> d6
  2038. </label>
  2039. <label class="dice-option">
  2040. <input type="radio" name="partner_perception" value="d8"> d8
  2041. </label>
  2042. <label class="dice-option">
  2043. <input type="radio" name="partner_perception" value="d12"> d12
  2044. </label>
  2045. <label class="dice-option">
  2046. <input type="radio" name="partner_perception" value="d20"> d20
  2047. </label>
  2048. </div>
  2049. <button type="button" onclick="rollPartnerSkill('partner_perception', 'agi')">Roll</button>
  2050. </div>
  2051.  
  2052. <h3>Partner Knowledge Skills</h3>
  2053.  
  2054. <div class="skill-container">
  2055. <div class="skill-name">
  2056. Partner Knowledge: Digimon <span class="skill-stat">(INT)</span>
  2057. </div>
  2058. <div class="dice-selector" data-skill="partner_knowledge_digimon">
  2059. <label class="dice-option">
  2060. <input type="radio" name="partner_knowledge_digimon" value="none" checked> None
  2061. </label>
  2062. <label class="dice-option">
  2063. <input type="radio" name="partner_knowledge_digimon" value="d6"> d6
  2064. </label>
  2065. <label class="dice-option">
  2066. <input type="radio" name="partner_knowledge_digimon" value="d8"> d8
  2067. </label>
  2068. <label class="dice-option">
  2069. <input type="radio" name="partner_knowledge_digimon" value="d12"> d12
  2070. </label>
  2071. <label class="dice-option">
  2072. <input type="radio" name="partner_knowledge_digimon" value="d20"> d20
  2073. </label>
  2074. </div>
  2075. <button type="button" onclick="rollPartnerSkill('partner_knowledge_digimon', 'int')">Roll</button>
  2076. </div>
  2077.  
  2078. <div class="skill-container">
  2079. <div class="skill-name">
  2080. Partner Knowledge: Human <span class="skill-stat">(WIL)</span>
  2081. </div>
  2082. <div class="dice-selector" data-skill="partner_knowledge_human">
  2083. <label class="dice-option">
  2084. <input type="radio" name="partner_knowledge_human" value="none" checked> None
  2085. </label>
  2086. <label class="dice-option">
  2087. <input type="radio" name="partner_knowledge_human" value="d6"> d6
  2088. </label>
  2089. <label class="dice-option">
  2090. <input type="radio" name="partner_knowledge_human" value="d8"> d8
  2091. </label>
  2092. <label class="dice-option">
  2093. <input type="radio" name="partner_knowledge_human" value="d12"> d12
  2094. </label>
  2095. <label class="dice-option">
  2096. <input type="radio" name="partner_knowledge_human" value="d20"> d20
  2097. </label>
  2098. </div>
  2099. <button type="button" onclick="rollPartnerSkill('partner_knowledge_human', 'wil')">Roll</button>
  2100. </div>
  2101.  
  2102. <div class="skill-container">
  2103. <div class="skill-name">
  2104. Partner Knowledge: Local <span class="skill-stat">(INT)</span>
  2105. </div>
  2106. <div class="dice-selector" data-skill="partner_knowledge_local">
  2107. <label class="dice-option">
  2108. <input type="radio" name="partner_knowledge_local" value="none" checked> None
  2109. </label>
  2110. <label class="dice-option">
  2111. <input type="radio" name="partner_knowledge_local" value="d6"> d6
  2112. </label>
  2113. <label class="dice-option">
  2114. <input type="radio" name="partner_knowledge_local" value="d8"> d8
  2115. </label>
  2116. <label class="dice-option">
  2117. <input type="radio" name="partner_knowledge_local" value="d12"> d12
  2118. </label>
  2119. <label class="dice-option">
  2120. <input type="radio" name="partner_knowledge_local" value="d20"> d20
  2121. </label>
  2122. </div>
  2123. <button type="button" onclick="rollPartnerSkill('partner_knowledge_local', 'int')">Roll</button>
  2124. </div>
  2125.  
  2126. <div class="skill-container">
  2127. <div class="skill-name">
  2128. Partner Knowledge: Region <span class="skill-stat">(INT)</span>
  2129. </div>
  2130. <div class="dice-selector" data-skill="partner_knowledge_region">
  2131. <label class="dice-option">
  2132. <input type="radio" name="partner_knowledge_region" value="none" checked> None
  2133. </label>
  2134. <label class="dice-option">
  2135. <input type="radio" name="partner_knowledge_region" value="d6"> d6
  2136. </label>
  2137. <label class="dice-option">
  2138. <input type="radio" name="partner_knowledge_region" value="d8"> d8
  2139. </label>
  2140. <label class="dice-option">
  2141. <input type="radio" name="partner_knowledge_region" value="d12"> d12
  2142. </label>
  2143. <label class="dice-option">
  2144. <input type="radio" name="partner_knowledge_region" value="d20"> d20
  2145. </label>
  2146. </div>
  2147. <button type="button" onclick="rollPartnerSkill('partner_knowledge_region', 'int')">Roll</button>
  2148. </div>
  2149.  
  2150. <div class="skill-container">
  2151. <div class="skill-name">
  2152. Partner Knowledge: Trapper <span class="skill-stat">(AGI)</span>
  2153. </div>
  2154. <div class="dice-selector" data-skill="partner_knowledge_trapper">
  2155. <label class="dice-option">
  2156. <input type="radio" name="partner_knowledge_trapper" value="none" checked> None
  2157. </label>
  2158. <label class="dice-option">
  2159. <input type="radio" name="partner_knowledge_trapper" value="d6"> d6
  2160. </label>
  2161. <label class="dice-option">
  2162. <input type="radio" name="partner_knowledge_trapper" value="d8"> d8
  2163. </label>
  2164. <label class="dice-option">
  2165. <input type="radio" name="partner_knowledge_trapper" value="d12"> d12
  2166. </label>
  2167. <label class="dice-option">
  2168. <input type="radio" name="partner_knowledge_trapper" value="d20"> d20
  2169. </label>
  2170. </div>
  2171. <button type="button" onclick="rollPartnerSkill('partner_knowledge_trapper', 'agi')">Roll</button>
  2172. </div>
  2173.  
  2174. <div class="skill-container">
  2175. <div class="skill-name">
  2176. Partner Knowledge: Smith <span class="skill-stat">(WIL)</span>
  2177. </div>
  2178. <div class="dice-selector" data-skill="partner_knowledge_smith">
  2179. <label class="dice-option">
  2180. <input type="radio" name="partner_knowledge_smith" value="none" checked> None
  2181. </label>
  2182. <label class="dice-option">
  2183. <input type="radio" name="partner_knowledge_smith" value="d6"> d6
  2184. </label>
  2185. <label class="dice-option">
  2186. <input type="radio" name="partner_knowledge_smith" value="d8"> d8
  2187. </label>
  2188. <label class="dice-option">
  2189. <input type="radio" name="partner_knowledge_smith" value="d12"> d12
  2190. </label>
  2191. <label class="dice-option">
  2192. <input type="radio" name="partner_knowledge_smith" value="d20"> d20
  2193. </label>
  2194. </div>
  2195. <button type="button" onclick="rollPartnerSkill('partner_knowledge_smith', 'wil')">Roll</button>
  2196. </div>
  2197.  
  2198. <div class="skill-container">
  2199. <div class="skill-name">
  2200. Partner Knowledge: Carpenter <span class="skill-stat">(WIL)</span>
  2201. </div>
  2202. <div class="dice-selector" data-skill="partner_knowledge_carpenter">
  2203. <label class="dice-option">
  2204. <input type="radio" name="partner_knowledge_carpenter" value="none" checked> None
  2205. </label>
  2206. <label class="dice-option">
  2207. <input type="radio" name="partner_knowledge_carpenter" value="d6"> d6
  2208. </label>
  2209. <label class="dice-option">
  2210. <input type="radio" name="partner_knowledge_carpenter" value="d8"> d8
  2211. </label>
  2212. <label class="dice-option">
  2213. <input type="radio" name="partner_knowledge_carpenter" value="d12"> d12
  2214. </label>
  2215. <label class="dice-option">
  2216. <input type="radio" name="partner_knowledge_carpenter" value="d20"> d20
  2217. </label>
  2218. </div>
  2219. <button type="button" onclick="rollPartnerSkill('partner_knowledge_carpenter', 'wil')">Roll</button>
  2220. </div>
  2221.  
  2222. <div class="skill-container">
  2223. <div class="skill-name">
  2224. Partner Knowledge: Handyman <span class="skill-stat">(INT)</span>
  2225. </div>
  2226. <div class="dice-selector" data-skill="partner_knowledge_handyman">
  2227. <label class="dice-option">
  2228. <input type="radio" name="partner_knowledge_handyman" value="none" checked> None
  2229. </label>
  2230. <label class="dice-option">
  2231. <input type="radio" name="partner_knowledge_handyman" value="d6"> d6
  2232. </label>
  2233. <label class="dice-option">
  2234. <input type="radio" name="partner_knowledge_handyman" value="d8"> d8
  2235. </label>
  2236. <label class="dice-option">
  2237. <input type="radio" name="partner_knowledge_handyman" value="d12"> d12
  2238. </label>
  2239. <label class="dice-option">
  2240. <input type="radio" name="partner_knowledge_handyman" value="d20"> d20
  2241. </label>
  2242. </div>
  2243. <button type="button" onclick="rollPartnerSkill('partner_knowledge_handyman', 'int')">Roll</button>
  2244. </div>
  2245.  
  2246. <div class="skill-container">
  2247. <div class="skill-name">
  2248. Partner Knowledge: Cook <span class="skill-stat">(WIL)</span>
  2249. </div>
  2250. <div class="dice-selector" data-skill="partner_knowledge_cook">
  2251. <label class="dice-option">
  2252. <input type="radio" name="partner_knowledge_cook" value="none" checked> None
  2253. </label>
  2254. <label class="dice-option">
  2255. <input type="radio" name="partner_knowledge_cook" value="d6"> d6
  2256. </label>
  2257. <label class="dice-option">
  2258. <input type="radio" name="partner_knowledge_cook" value="d8"> d8
  2259. </label>
  2260. <label class="dice-option">
  2261. <input type="radio" name="partner_knowledge_cook" value="d12"> d12
  2262. </label>
  2263. <label class="dice-option">
  2264. <input type="radio" name="partner_knowledge_cook" value="d20"> d20
  2265. </label>
  2266. </div>
  2267. <button type="button" onclick="rollPartnerSkill('partner_knowledge_cook', 'wil')">Roll</button>
  2268. </div>
  2269.  
  2270. <div class="skill-container">
  2271. <div class="skill-name">
  2272. Partner Knowledge: Hacking <span class="skill-stat">(INT)</span>
  2273. </div>
  2274. <div class="dice-selector" data-skill="partner_knowledge_hacking">
  2275. <label class="dice-option">
  2276. <input type="radio" name="partner_knowledge_hacking" value="none" checked> None
  2277. </label>
  2278. <label class="dice-option">
  2279. <input type="radio" name="partner_knowledge_hacking" value="d6"> d6
  2280. </label>
  2281. <label class="dice-option">
  2282. <input type="radio" name="partner_knowledge_hacking" value="d8"> d8
  2283. </label>
  2284. <label class="dice-option">
  2285. <input type="radio" name="partner_knowledge_hacking" value="d12"> d12
  2286. </label>
  2287. <label class="dice-option">
  2288. <input type="radio" name="partner_knowledge_hacking" value="d20"> d20
  2289. </label>
  2290. </div>
  2291. <button type="button" onclick="rollPartnerSkill('partner_knowledge_hacking', 'int')">Roll</button>
  2292. </div>
  2293.  
  2294. <div class="skill-container">
  2295. <div class="skill-name">
  2296. Partner Knowledge: Engineering <span class="skill-stat">(INT)</span>
  2297. </div>
  2298. <div class="dice-selector" data-skill="partner_knowledge_engineering">
  2299. <label class="dice-option">
  2300. <input type="radio" name="partner_knowledge_engineering" value="none" checked> None
  2301. </label>
  2302. <label class="dice-option">
  2303. <input type="radio" name="partner_knowledge_engineering" value="d6"> d6
  2304. </label>
  2305. <label class="dice-option">
  2306. <input type="radio" name="partner_knowledge_engineering" value="d8"> d8
  2307. </label>
  2308. <label class="dice-option">
  2309. <input type="radio" name="partner_knowledge_engineering" value="d12"> d12
  2310. </label>
  2311. <label class="dice-option">
  2312. <input type="radio" name="partner_knowledge_engineering" value="d20"> d20
  2313. </label>
  2314. </div>
  2315. <button type="button" onclick="rollPartnerSkill('partner_knowledge_engineering', 'int')">Roll</button>
  2316. </div>
  2317. </div>
  2318. </div>
  2319. </div>
  2320. </div>
  2321. <!-- Add more partner skills as needed -->
  2322. </div>
  2323. </div>
  2324. </div>
  2325.  
  2326. <div id="notes-tab" class="tab-content">
  2327. <div class="grid-container">
  2328. <div class="card">
  2329. <h2 class="card-title">Items</h2>
  2330. <div class="notes-container">
  2331. <div class="notes-heading">Items Inventory</div>
  2332. <textarea id="itemsNotes" class="notes-content" placeholder="Record your items here..."></textarea>
  2333. </div>
  2334. </div>
  2335.  
  2336. <div class="card">
  2337. <h2 class="card-title">Character Aspects</h2>
  2338. <div class="notes-container">
  2339. <div class="notes-heading">Major & Minor Aspects</div>
  2340. <textarea id="aspectsNotes" class="notes-content" placeholder="Record your major and minor aspects here..."></textarea>
  2341. </div>
  2342. </div>
  2343.  
  2344. <div class="card">
  2345. <h2 class="card-title">Campaign Notes</h2>
  2346. <div class="notes-container">
  2347. <div class="notes-heading">Campaign Journal</div>
  2348. <textarea id="campaignNotes" class="notes-content" placeholder="Record your campaign notes here..."></textarea>
  2349. </div>
  2350. </div>
  2351. </div>
  2352. </div>
  2353.  
  2354. <div id="class-skills-tab" class="tab-content">
  2355. <div class="card">
  2356. <h2 class="card-title">Class Skills</h2>
  2357. <div class="notes-container">
  2358. <div class="notes-heading">Special Abilities</div>
  2359. <textarea id="classSkillsNotes" class="notes-content" placeholder="Record your class skills here..."></textarea>
  2360. </div>
  2361. </div>
  2362. </div>
  2363.  
  2364. <div id="items-tab" class="tab-content">
  2365. <div class="card">
  2366. <h2 class="card-title">Items</h2>
  2367. <div id="itemsContainer">
  2368. <!-- Item entries will go here -->
  2369. </div>
  2370. <button type="button" onclick="addItem()" class="add-button">Add New Item</button>
  2371. </div>
  2372. </div>
  2373.  
  2374. <div id="mechs-tab" class="tab-content">
  2375. <div class="card">
  2376. <h2 class="card-title">Mech Parts Library</h2>
  2377. <p>Add mech parts to your library that can be used to build mechs.</p>
  2378.  
  2379. <div class="form-row">
  2380. <div class="form-group">
  2381. <label for="mechPartType">Part Type</label>
  2382. <select id="mechPartType">
  2383. <option value="core">Core</option>
  2384. <option value="frame">Frame</option>
  2385. <option value="weapon">Weapon</option>
  2386. <option value="arm">Arm</option>
  2387. <option value="leg">Leg</option>
  2388. <option value="head">Head</option>
  2389. </select>
  2390. </div>
  2391. <button type="button" onclick="addMechPart()" class="add-button">Add New Part</button>
  2392. </div>
  2393.  
  2394. <h3>Cores</h3>
  2395. <div id="mechCoresContainer" class="mech-parts-container">
  2396. <!-- Core parts will go here -->
  2397. </div>
  2398.  
  2399. <h3>Frames</h3>
  2400. <div id="mechFramesContainer" class="mech-parts-container">
  2401. <!-- Frame parts will go here -->
  2402. </div>
  2403.  
  2404. <h3>Weapons</h3>
  2405. <div id="mechWeaponsContainer" class="mech-parts-container">
  2406. <!-- Weapon parts will go here -->
  2407. </div>
  2408.  
  2409. <h3>Arms</h3>
  2410. <div id="mechArmsContainer" class="mech-parts-container">
  2411. <!-- Arm parts will go here -->
  2412. </div>
  2413.  
  2414. <h3>Legs</h3>
  2415. <div id="mechLegsContainer" class="mech-parts-container">
  2416. <!-- Leg parts will go here -->
  2417. </div>
  2418.  
  2419. <h3>Heads</h3>
  2420. <div id="mechHeadsContainer" class="mech-parts-container">
  2421. <!-- Head parts will go here -->
  2422. </div>
  2423. </div>
  2424.  
  2425. <div class="card">
  2426. <h2 class="card-title">Character Mech Configuration</h2>
  2427. <div id="characterMechContainer">
  2428. <!-- Character mech configuration will go here -->
  2429. <div class="form-group">
  2430. <label for="mechName">Mech Name</label>
  2431. <input type="text" id="mechName">
  2432. </div>
  2433.  
  2434. <div class="form-group">
  2435. <label for="mechDescription">Description</label>
  2436. <textarea id="mechDescription"></textarea>
  2437. </div>
  2438.  
  2439. <div class="form-group">
  2440. <label for="selectedCore">Core</label>
  2441. <select id="selectedCore">
  2442. <option value="">-- Select Core --</option>
  2443. </select>
  2444. </div>
  2445.  
  2446. <div class="form-group">
  2447. <label for="selectedFrame">Frame</label>
  2448. <select id="selectedFrame">
  2449. <option value="">-- Select Frame --</option>
  2450. </select>
  2451. </div>
  2452.  
  2453. <div class="form-group">
  2454. <label for="selectedWeapon">Weapon</label>
  2455. <select id="selectedWeapon">
  2456. <option value="">-- Select Weapon --</option>
  2457. </select>
  2458. </div>
  2459.  
  2460. <div class="form-group">
  2461. <label for="selectedArm">Arms</label>
  2462. <select id="selectedArm">
  2463. <option value="">-- Select Arms --</option>
  2464. </select>
  2465. </div>
  2466.  
  2467. <div class="form-group">
  2468. <label for="selectedLeg">Legs</label>
  2469. <select id="selectedLeg">
  2470. <option value="">-- Select Legs --</option>
  2471. </select>
  2472. </div>
  2473.  
  2474. <div class="form-group">
  2475. <label for="selectedHead">Head</label>
  2476. <select id="selectedHead">
  2477. <option value="">-- Select Head --</option>
  2478. </select>
  2479. </div>
  2480. </div>
  2481. </div>
  2482. </div>
  2483.  
  2484. <div id="digimon-lines-tab" class="tab-content">
  2485. <div class="card">
  2486. <h2 class="card-title">Digimon Evolution Lines</h2>
  2487. <div id="digimonLinesContainer">
  2488. <!-- Digimon lines will go here -->
  2489. </div>
  2490. <button type="button" onclick="addDigimonLine()" class="add-button">Add New Evolution Line</button>
  2491. </div>
  2492. </div>
  2493.  
  2494. <div id="rules-tab" class="tab-content">
  2495. <div class="card">
  2496. <h2 class="card-title">Game Rules</h2>
  2497. <div class="notes-container">
  2498. <div class="notes-heading">Rules Reference</div>
  2499. <textarea id="rulesNotes" class="notes-content" placeholder="Record important game rules here..."></textarea>
  2500. </div>
  2501. </div>
  2502. </div>
  2503. </div>
  2504. <!-- After your other tab content divs -->
  2505. <div id="moves-tab" class="tab-content">
  2506. <div class="card">
  2507. <h2 class="card-title">Move List</h2>
  2508. <p class="card-subtitle">Create and manage your character's attacks, abilities, and techniques.</p>
  2509.  
  2510. <div class="controls">
  2511. <button type="button" onclick="addMove()" class="add-button">Add New Move</button>
  2512. <select id="moveFilter" onchange="filterMoves()">
  2513. <option value="all">All Moves</option>
  2514. <option value="attack">Attacks</option>
  2515. <option value="healing">Healing</option>
  2516. <option value="buff">Buffs/Debuffs</option>
  2517. <option value="utility">Utility</option>
  2518. </select>
  2519. </div>
  2520.  
  2521. <div id="movesContainer">
  2522. <!-- Moves will be added here -->
  2523. </div>
  2524.  
  2525. <div class="move-calculator">
  2526. <h3>Move Calculator</h3>
  2527. <div class="form-row">
  2528. <div class="form-group">
  2529. <label for="calcMoveName">Move:</label>
  2530. <select id="calcMoveName">
  2531. <option value="">-- Select Move --</option>
  2532. </select>
  2533. </div>
  2534. <div class="form-group">
  2535. <label for="calcTarget">Target Defense:</label>
  2536. <input type="number" id="calcTarget" min="0" value="0">
  2537. </div>
  2538. <div class="form-group">
  2539. <button type="button" onclick="calculateMoveEffect()">Calculate</button>
  2540. </div>
  2541. </div>
  2542. <div id="moveCalcResult" class="calc-result">
  2543. Result will appear here...
  2544. </div>
  2545. </div>
  2546. </div>
  2547. </div>
  2548.  
  2549. <div id="partner-moves-tab" class="tab-content">
  2550. <div class="card">
  2551. <h2 class="card-title">Partner Move List</h2>
  2552. <p class="card-subtitle">Create and manage your partner's attacks, abilities, and techniques.</p>
  2553.  
  2554. <div class="controls">
  2555. <button type="button" onclick="addPartnerMove()" class="add-button">Add New Partner Move</button>
  2556. <select id="partnerMoveFilter" onchange="filterPartnerMoves()">
  2557. <option value="all">All Moves</option>
  2558. <option value="attack">Attacks</option>
  2559. <option value="healing">Healing</option>
  2560. <option value="buff">Buffs/Debuffs</option>
  2561. <option value="utility">Utility</option>
  2562. </select>
  2563. </div>
  2564.  
  2565. <div id="partnerMovesContainer">
  2566. <!-- Partner moves will be added here -->
  2567. </div>
  2568.  
  2569. <div class="move-calculator">
  2570. <h3>Partner Move Calculator</h3>
  2571. <div class="form-row">
  2572. <div class="form-group">
  2573. <label for="calcPartnerMoveName">Move:</label>
  2574. <select id="calcPartnerMoveName">
  2575. <option value="">-- Select Move --</option>
  2576. </select>
  2577. </div>
  2578. <div class="form-group">
  2579. <label for="calcPartnerTarget">Target Defense:</label>
  2580. <input type="number" id="calcPartnerTarget" min="0" value="0">
  2581. </div>
  2582. <div class="form-group">
  2583. <button type="button" onclick="calculatePartnerMoveEffect()">Calculate</button>
  2584. </div>
  2585. </div>
  2586. <div id="partnerMoveCalcResult" class="calc-result">
  2587. Result will appear here...
  2588. </div>
  2589. </div>
  2590. </div>
  2591. </div>
  2592.  
  2593. <div class="import-export">
  2594. <h3>Save & Import Options</h3>
  2595. <div class="form-row">
  2596. <button type="button" onclick="saveCharacterSheet()" class="accent">Save Character Sheet</button>
  2597. <button type="button" onclick="loadCharacterSheet()" class="secondary">Load Character Sheet</button>
  2598. <button type="button" onclick="exportToJSON()" class="accent">Export to JSON</button>
  2599. <button type="button" onclick="document.getElementById('importFile').click()">Import from JSON</button>
  2600. <input type="file" id="importFile" accept=".json" style="display: none;" onchange="importFromJSON(this)">
  2601. </div>
  2602.  
  2603. <div class="form-row">
  2604. <button type="button" onclick="importBackgrounds()" class="secondary">Import Backgrounds</button>
  2605. <div class="form-group" style="display: flex; align-items: center; gap: 10px;">
  2606. <label for="autoSaveSwitch" style="margin: 0;">Auto-Save:</label>
  2607. <label class="switch">
  2608. <input type="checkbox" id="autoSaveSwitch" onchange="autoSaveToggle()">
  2609. <span class="slider"></span>
  2610. </label>
  2611. </div>
  2612. </div>
  2613. </div>
  2614. </div>
  2615.  
  2616. <!-- Notification element -->
  2617. <div id="notification" class="notification">Save successful!</div>
  2618.  
  2619. <script>
  2620. // Global variables
  2621. let autoSaveEnabled = false;
  2622. let autoSaveInterval;
  2623. const AUTOSAVE_INTERVAL = 60000; // 1 minute
  2624.  
  2625. // Show notification
  2626. function showNotification(message, isError = false) {
  2627. const notification = document.getElementById('notification');
  2628. notification.textContent = message;
  2629. notification.classList.toggle('error', isError);
  2630. notification.classList.add('show');
  2631.  
  2632. setTimeout(() => {
  2633. notification.classList.remove('show');
  2634. }, 3000);
  2635. }
  2636.  
  2637. // Auto-save functionality
  2638. function autoSaveToggle() {
  2639. autoSaveEnabled = document.getElementById('autoSaveSwitch').checked;
  2640.  
  2641. if (autoSaveEnabled) {
  2642. showNotification('Auto-save enabled');
  2643. autoSaveInterval = setInterval(saveCharacterSheet, AUTOSAVE_INTERVAL);
  2644. saveCharacterSheet(); // Initial save
  2645. } else {
  2646. showNotification('Auto-save disabled');
  2647. clearInterval(autoSaveInterval);
  2648. }
  2649. }
  2650.  
  2651. // Handle page unload
  2652. window.addEventListener('beforeunload', function(e) {
  2653. saveCharacterSheet(); // Save before leaving page
  2654. });
  2655.  
  2656. // Tabs functionality
  2657. document.querySelectorAll('.tab').forEach(tab => {
  2658. tab.addEventListener('click', () => {
  2659. const tabId = tab.getAttribute('data-tab');
  2660.  
  2661. // Remove active class from all tabs and tab contents
  2662. document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
  2663. document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active'));
  2664.  
  2665. // Add active class to clicked tab and corresponding content
  2666. tab.classList.add('active');
  2667. document.getElementById(tabId).classList.add('active');
  2668.  
  2669. // Save on tab change
  2670. saveCharacterSheet();
  2671. });
  2672. });
  2673.  
  2674. // Character type toggle
  2675. document.querySelectorAll('input[name="characterType"]').forEach(input => {
  2676. input.addEventListener('change', () => {
  2677. const isTamer = document.querySelector('input[name="characterType"]:checked').value === 'tamer';
  2678. document.querySelectorAll('.tamer-only').forEach(el => {
  2679. el.style.display = isTamer ? 'block' : 'none';
  2680. });
  2681. document.querySelectorAll('.digimon-only').forEach(el => {
  2682. el.style.display = isTamer ? 'none' : 'block';
  2683. });
  2684. updateBackgroundInfo();
  2685. });
  2686. });
  2687.  
  2688. // Partner type toggle
  2689. document.getElementById('partnerType').addEventListener('change', () => {
  2690. const isHuman = document.getElementById('partnerType').value === 'tamer';
  2691. document.querySelectorAll('.partner-tamer-only').forEach(el => {
  2692. el.style.display = isHuman ? 'block' : 'none';
  2693. });
  2694. document.querySelectorAll('.partner-digimon-only').forEach(el => {
  2695. el.style.display = isHuman ? 'none' : 'block';
  2696. });
  2697. updatePartnerBackgroundInfo();
  2698. });
  2699.  
  2700. // Background info display
  2701. document.getElementById('characterBackground').addEventListener('change', () => {
  2702. updateBackgroundInfo();
  2703. applyBackgroundBonuses();
  2704. });
  2705.  
  2706. document.getElementById('digimonBackground').addEventListener('change', () => {
  2707. updateBackgroundInfo();
  2708. applyBackgroundBonuses();
  2709. });
  2710.  
  2711. document.getElementById('partnerHumanBackground').addEventListener('change', () => {
  2712. updatePartnerBackgroundInfo();
  2713. applyPartnerBackgroundBonuses();
  2714. });
  2715.  
  2716. document.getElementById('partnerDigimonBackground').addEventListener('change', () => {
  2717. updatePartnerBackgroundInfo();
  2718. applyPartnerBackgroundBonuses();
  2719. });
  2720.  
  2721. // Show/hide Isekai'd options
  2722. function updateIsekaiOptions() {
  2723. const characterType = document.querySelector('input[name="characterType"]:checked').value;
  2724. const background = characterType === 'tamer'
  2725. ? document.getElementById('characterBackground').value
  2726. : document.getElementById('digimonBackground').value;
  2727.  
  2728. document.querySelector('.isekai-only').style.display = background === 'isekai' ? 'block' : 'none';
  2729.  
  2730. if (background === 'isekai') {
  2731. // Limit to only 2 checkboxes
  2732. const checkboxes = document.querySelectorAll('.isekai-stat-bonus');
  2733. checkboxes.forEach(cb => {
  2734. cb.addEventListener('change', function() {
  2735. const checked = document.querySelectorAll('.isekai-stat-bonus:checked');
  2736. if (checked.length > 2) {
  2737. this.checked = false;
  2738. showNotification('You can only select 2 stats for Isekai\'d bonus.', true);
  2739. }
  2740. applyIsekaiBonus();
  2741. });
  2742. });
  2743. }
  2744. }
  2745.  
  2746. function updatePartnerIsekaiOptions() {
  2747. const partnerType = document.getElementById('partnerType').value;
  2748. const background = partnerType === 'tamer'
  2749. ? document.getElementById('partnerHumanBackground').value
  2750. : document.getElementById('partnerDigimonBackground').value;
  2751.  
  2752. document.querySelector('.partner-isekai-only').style.display = background === 'isekai' ? 'block' : 'none';
  2753.  
  2754. if (background === 'isekai') {
  2755. // Limit to only 2 checkboxes
  2756. const checkboxes = document.querySelectorAll('.partner-isekai-stat-bonus');
  2757. checkboxes.forEach(cb => {
  2758. cb.addEventListener('change', function() {
  2759. const checked = document.querySelectorAll('.partner-isekai-stat-bonus:checked');
  2760. if (checked.length > 2) {
  2761. this.checked = false;
  2762. showNotification('You can only select 2 stats for Isekai\'d bonus.', true);
  2763. }
  2764. applyPartnerIsekaiBonus();
  2765. });
  2766. });
  2767. }
  2768. }
  2769.  
  2770. function applyIsekaiBonus() {
  2771. // First reset all isekai bonuses
  2772. resetIsekaiBonus();
  2773.  
  2774. // Then apply new bonuses
  2775. const checkedBoxes = document.querySelectorAll('.isekai-stat-bonus:checked');
  2776. checkedBoxes.forEach(box => {
  2777. const statId = box.value;
  2778. const statElement = document.getElementById(statId);
  2779. const currentValue = parseInt(statElement.value) || 1;
  2780.  
  2781. // Store original value in data attribute if not already stored
  2782. if (!statElement.dataset.originalValue) {
  2783. statElement.dataset.originalValue = currentValue;
  2784. }
  2785.  
  2786. // Apply +2 bonus
  2787. statElement.value = parseInt(statElement.dataset.originalValue) + 2;
  2788. });
  2789.  
  2790. // Recalculate after applying bonuses
  2791. calculateStats();
  2792. }
  2793.  
  2794. function resetIsekaiBonus() {
  2795. const statInputs = ['baseHP', 'baseSP', 'str', 'def', 'int', 'agi', 'wil'];
  2796. statInputs.forEach(statId => {
  2797. const statElement = document.getElementById(statId);
  2798. if (statElement.dataset.originalValue) {
  2799. statElement.value = statElement.dataset.originalValue;
  2800. delete statElement.dataset.originalValue;
  2801. }
  2802. });
  2803. }
  2804.  
  2805. function applyPartnerIsekaiBonus() {
  2806. // First reset all partner isekai bonuses
  2807. resetPartnerIsekaiBonus();
  2808.  
  2809. // Then apply new bonuses
  2810. const checkedBoxes = document.querySelectorAll('.partner-isekai-stat-bonus:checked');
  2811. checkedBoxes.forEach(box => {
  2812. const statId = box.value;
  2813. const statElement = document.getElementById(statId);
  2814. const currentValue = parseInt(statElement.value) || 1;
  2815.  
  2816. // Store original value in data attribute if not already stored
  2817. if (!statElement.dataset.originalValue) {
  2818. statElement.dataset.originalValue = currentValue;
  2819. }
  2820.  
  2821. // Apply +2 bonus
  2822. statElement.value = parseInt(statElement.dataset.originalValue) + 2;
  2823. });
  2824.  
  2825. // Recalculate after applying bonuses
  2826. calculatePartnerStats();
  2827. }
  2828.  
  2829. function resetPartnerIsekaiBonus() {
  2830. const statInputs = ['partnerBaseHP', 'partnerBaseSP', 'partner-str', 'partner-def', 'partner-int', 'partner-agi', 'partner-wil'];
  2831. statInputs.forEach(statId => {
  2832. const statElement = document.getElementById(statId);
  2833. if (statElement.dataset.originalValue) {
  2834. statElement.value = statElement.dataset.originalValue;
  2835. delete statElement.dataset.originalValue;
  2836. }
  2837. });
  2838. }
  2839.  
  2840. function updateBackgroundInfo() {
  2841. const characterType = document.querySelector('input[name="characterType"]:checked').value;
  2842. const background = characterType === 'tamer'
  2843. ? document.getElementById('characterBackground').value
  2844. : document.getElementById('digimonBackground').value;
  2845.  
  2846. const backgroundInfoElement = document.getElementById('backgroundInfo');
  2847.  
  2848. if (!background) {
  2849. backgroundInfoElement.innerHTML = '<p>Select a background to see details</p>';
  2850. return;
  2851. }
  2852.  
  2853. const backgroundInfo = getBackgroundInfo(background, characterType);
  2854. backgroundInfoElement.innerHTML = backgroundInfo;
  2855.  
  2856. // Update Isekai options visibility
  2857. updateIsekaiOptions();
  2858. }
  2859.  
  2860. function updatePartnerBackgroundInfo() {
  2861. const partnerType = document.getElementById('partnerType').value;
  2862. const background = partnerType === 'tamer'
  2863. ? document.getElementById('partnerHumanBackground').value
  2864. : document.getElementById('partnerDigimonBackground').value;
  2865.  
  2866. const backgroundInfoElement = document.getElementById('partnerBackgroundInfo');
  2867.  
  2868. if (!background) {
  2869. backgroundInfoElement.innerHTML = '<p>Select a background to see details</p>';
  2870. return;
  2871. }
  2872.  
  2873. const backgroundInfo = getBackgroundInfo(background, partnerType);
  2874. backgroundInfoElement.innerHTML = backgroundInfo;
  2875.  
  2876. // Update Isekai options visibility for partner
  2877. updatePartnerIsekaiOptions();
  2878. }
  2879.  
  2880. function applyBackgroundBonuses() {
  2881. // Reset skills first
  2882. resetSkillBonuses();
  2883.  
  2884. const characterType = document.querySelector('input[name="characterType"]:checked').value;
  2885. const background = characterType === 'tamer'
  2886. ? document.getElementById('characterBackground').value
  2887. : document.getElementById('digimonBackground').value;
  2888.  
  2889. if (!background || background === 'isekai') return;
  2890.  
  2891. const backgroundBonuses = getBackgroundBonuses(background);
  2892.  
  2893. // Apply skill proficiencies
  2894. if (backgroundBonuses.skills) {
  2895. for (const skill in backgroundBonuses.skills) {
  2896. const dice = backgroundBonuses.skills[skill];
  2897. const radio = document.querySelector(`input[name="${skill}"][value="${dice}"]`);
  2898. if (radio) radio.checked = true;
  2899. }
  2900. }
  2901.  
  2902. // Apply stat bonuses
  2903. if (backgroundBonuses.stats) {
  2904. for (const stat in backgroundBonuses.stats) {
  2905. const bonus = backgroundBonuses.stats[stat];
  2906. const statElement = document.getElementById(stat);
  2907.  
  2908. if (statElement) {
  2909. // Store original value if not already stored
  2910. if (!statElement.dataset.originalValue) {
  2911. statElement.dataset.originalValue = statElement.value;
  2912. }
  2913.  
  2914. statElement.value = parseInt(statElement.dataset.originalValue) + bonus;
  2915. }
  2916. }
  2917. }
  2918.  
  2919. calculateStats();
  2920. }
  2921.  
  2922. function applyPartnerBackgroundBonuses() {
  2923. // Reset partner skills first
  2924. resetPartnerSkillBonuses();
  2925.  
  2926. const partnerType = document.getElementById('partnerType').value;
  2927. const background = partnerType === 'tamer'
  2928. ? document.getElementById('partnerHumanBackground').value
  2929. : document.getElementById('partnerDigimonBackground').value;
  2930.  
  2931. if (!background || background === 'isekai') return;
  2932.  
  2933. const backgroundBonuses = getBackgroundBonuses(background);
  2934.  
  2935. // Apply skill proficiencies for partner
  2936. if (backgroundBonuses.skills) {
  2937. for (const skill in backgroundBonuses.skills) {
  2938. const dice = backgroundBonuses.skills[skill];
  2939. const partnerSkill = 'partner_' + skill;
  2940. const radio = document.querySelector(`input[name="${partnerSkill}"][value="${dice}"]`);
  2941. if (radio) radio.checked = true;
  2942. }
  2943. }
  2944.  
  2945. // Apply stat bonuses for partner
  2946. if (backgroundBonuses.stats) {
  2947. for (const stat in backgroundBonuses.stats) {
  2948. const bonus = backgroundBonuses.stats[stat];
  2949. // Map to partner stats (prefix with 'partner-')
  2950. const partnerStat = stat.startsWith('partner') ? stat : (stat === 'baseHP' ? 'partnerBaseHP' :
  2951. (stat === 'baseSP' ? 'partnerBaseSP' : 'partner-' + stat));
  2952. const statElement = document.getElementById(partnerStat);
  2953.  
  2954. if (statElement) {
  2955. // Store original value if not already stored
  2956. if (!statElement.dataset.originalValue) {
  2957. statElement.dataset.originalValue = statElement.value;
  2958. }
  2959.  
  2960. statElement.value = parseInt(statElement.dataset.originalValue) + bonus;
  2961. }
  2962. }
  2963. }
  2964.  
  2965. calculatePartnerStats();
  2966. }
  2967.  
  2968. function resetSkillBonuses() {
  2969. const skills = document.querySelectorAll('input[type="radio"][name^="knowledge_"], input[type="radio"][name="dodge"], input[type="radio"][name="fight"], input[type="radio"][name="stealth"], input[type="radio"][name="manipulate"], input[type="radio"][name="perform"], input[type="radio"][name="persuade"], input[type="radio"][name="survival"], input[type="radio"][name="perception"]');
  2970.  
  2971. skills.forEach(skill => {
  2972. if (skill.value === 'none') {
  2973. skill.checked = true;
  2974. }
  2975. });
  2976.  
  2977. // Reset stat bonuses too
  2978. const statInputs = ['baseHP', 'baseSP', 'str', 'def', 'int', 'agi', 'wil'];
  2979. statInputs.forEach(statId => {
  2980. const statElement = document.getElementById(statId);
  2981. if (statElement.dataset.originalValue) {
  2982. statElement.value = statElement.dataset.originalValue;
  2983. delete statElement.dataset.originalValue;
  2984. }
  2985. });
  2986. }
  2987.  
  2988. function resetPartnerSkillBonuses() {
  2989. const skills = document.querySelectorAll('input[type="radio"][name^="partner_"]');
  2990.  
  2991. skills.forEach(skill => {
  2992. if (skill.value === 'none') {
  2993. skill.checked = true;
  2994. }
  2995. });
  2996.  
  2997. // Reset partner stat bonuses
  2998. const statInputs = ['partnerBaseHP', 'partnerBaseSP', 'partner-str', 'partner-def', 'partner-int', 'partner-agi', 'partner-wil'];
  2999. statInputs.forEach(statId => {
  3000. const statElement = document.getElementById(statId);
  3001. if (statElement.dataset.originalValue) {
  3002. statElement.value = statElement.dataset.originalValue;
  3003. delete statElement.dataset.originalValue;
  3004. }
  3005. });
  3006. }
  3007.  
  3008. function getBackgroundBonuses(background) {
  3009. const backgroundBonuses = {
  3010. 'courtesan': {
  3011. stats: { wil: 2 },
  3012. skills: {
  3013. manipulate: 'd8',
  3014. perform: 'd6',
  3015. persuade: 'd6',
  3016. knowledge_human: 'd6'
  3017. }
  3018. },
  3019. 'adventurer': {
  3020. stats: { str: 2 },
  3021. skills: {
  3022. survival: 'd8',
  3023. fight: 'd6',
  3024. perception: 'd6',
  3025. knowledge_region: 'd6'
  3026. }
  3027. },
  3028. 'diplomat': {
  3029. stats: { wil: 2 },
  3030. skills: {
  3031. persuade: 'd8',
  3032. manipulate: 'd6',
  3033. knowledge_human: 'd6',
  3034. knowledge_local: 'd6'
  3035. }
  3036. },
  3037. 'farmer': {
  3038. stats: { agi: 2 },
  3039. skills: {
  3040. knowledge_cook: 'd8',
  3041. survival: 'd6',
  3042. perception: 'd6',
  3043. knowledge_region: 'd6'
  3044. }
  3045. },
  3046. 'janitor': {
  3047. stats: { int: 2 },
  3048. skills: {
  3049. knowledge_handyman: 'd8',
  3050. stealth: 'd6',
  3051. perception: 'd6'
  3052. }
  3053. },
  3054. 'sleuth': {
  3055. stats: { agi: 2 },
  3056. skills: {
  3057. perception: 'd8',
  3058. knowledge_local: 'd6',
  3059. survival: 'd6'
  3060. }
  3061. },
  3062. 'slave': {
  3063. stats: { agi: 2 },
  3064. skills: {
  3065. stealth: 'd8',
  3066. dodge: 'd6',
  3067. survival: 'd6'
  3068. }
  3069. },
  3070. 'wronged_hero': {
  3071. stats: { str: 2 },
  3072. skills: {
  3073. fight: 'd8',
  3074. knowledge_region: 'd6',
  3075. persuade: 'd6'
  3076. }
  3077. },
  3078. 'doctor': {
  3079. stats: { int: 2 },
  3080. skills: {
  3081. knowledge_human: 'd8',
  3082. perception: 'd6',
  3083. knowledge_cook: 'd6'
  3084. }
  3085. },
  3086. 'carpenter': {
  3087. stats: { wil: 2 },
  3088. skills: {
  3089. knowledge_carpenter: 'd8',
  3090. knowledge_handyman: 'd6',
  3091. survival: 'd6'
  3092. }
  3093. },
  3094. 'child': {
  3095. stats: { agi: 2 },
  3096. skills: {
  3097. dodge: 'd8',
  3098. stealth: 'd6',
  3099. manipulate: 'd6'
  3100. }
  3101. },
  3102. 'explorer': {
  3103. stats: { int: 2 },
  3104. skills: {
  3105. knowledge_region: 'd8',
  3106. survival: 'd6',
  3107. perception: 'd6'
  3108. }
  3109. },
  3110. 'fallen_noble': {
  3111. stats: { wil: 2 },
  3112. skills: {
  3113. persuade: 'd8',
  3114. knowledge_human: 'd6',
  3115. knowledge_local: 'd6'
  3116. }
  3117. },
  3118. 'student_of_magic': {
  3119. stats: { int: 2 },
  3120. skills: {
  3121. knowledge_digimon: 'd8',
  3122. knowledge_engineering: 'd6',
  3123. perception: 'd6'
  3124. }
  3125. },
  3126. 'survivor': {
  3127. stats: { agi: 2 },
  3128. skills: {
  3129. survival: 'd8',
  3130. perception: 'd6',
  3131. dodge: 'd6'
  3132. }
  3133. },
  3134. 'messenger': {
  3135. stats: { agi: 2 },
  3136. skills: {
  3137. knowledge_local: 'd8',
  3138. dodge: 'd6',
  3139. perception: 'd6'
  3140. }
  3141. },
  3142. 'from_the_past': {
  3143. stats: { int: 2 },
  3144. skills: {
  3145. knowledge_region: 'd8',
  3146. knowledge_human: 'd6',
  3147. manipulate: 'd6'
  3148. }
  3149. },
  3150. 'miner': {
  3151. stats: { int: 2 },
  3152. skills: {
  3153. knowledge_handyman: 'd8',
  3154. survival: 'd6',
  3155. perception: 'd6'
  3156. }
  3157. },
  3158. 'royalty': {
  3159. stats: { wil: 2 },
  3160. skills: {
  3161. persuade: 'd8',
  3162. knowledge_human: 'd6',
  3163. knowledge_local: 'd6'
  3164. }
  3165. },
  3166. 'mute': {
  3167. stats: { agi: 2 },
  3168. skills: {
  3169. stealth: 'd8',
  3170. perception: 'd6',
  3171. manipulate: 'd6'
  3172. }
  3173. },
  3174. 'artist': {
  3175. stats: { wil: 2 },
  3176. skills: {
  3177. perform: 'd8',
  3178. knowledge_human: 'd6',
  3179. persuade: 'd6'
  3180. }
  3181. },
  3182. 'negotiator': {
  3183. stats: { wil: 2 },
  3184. skills: {
  3185. persuade: 'd8',
  3186. knowledge_human: 'd6',
  3187. perception: 'd6'
  3188. }
  3189. },
  3190. 'innkeeper': {
  3191. stats: { wil: 2 },
  3192. skills: {
  3193. knowledge_cook: 'd8',
  3194. persuade: 'd6',
  3195. knowledge_local: 'd6'
  3196. }
  3197. },
  3198. 'barmaid': {
  3199. stats: { wil: 2 },
  3200. skills: {
  3201. manipulate: 'd8',
  3202. persuade: 'd6',
  3203. knowledge_local: 'd6'
  3204. }
  3205. },
  3206. 'bartender': {
  3207. stats: { wil: 2 },
  3208. skills: {
  3209. persuade: 'd8',
  3210. knowledge_cook: 'd6',
  3211. knowledge_local: 'd6'
  3212. }
  3213. },
  3214. 'sex_slave': {
  3215. stats: { wil: 2 },
  3216. skills: {
  3217. manipulate: 'd8',
  3218. persuade: 'd6',
  3219. stealth: 'd6'
  3220. }
  3221. },
  3222. 'inventor': {
  3223. stats: { int: 2 },
  3224. skills: {
  3225. knowledge_engineering: 'd8',
  3226. knowledge_hacking: 'd6',
  3227. perception: 'd6'
  3228. }
  3229. },
  3230. 'beggar': {
  3231. stats: { agi: 2 },
  3232. skills: {
  3233. stealth: 'd8',
  3234. dodge: 'd6',
  3235. perception: 'd6'
  3236. }
  3237. },
  3238. 'shepherd': {
  3239. stats: { agi: 2 },
  3240. skills: {
  3241. survival: 'd8',
  3242. knowledge_region: 'd6',
  3243. perception: 'd6'
  3244. }
  3245. },
  3246. 'pilot': {
  3247. stats: { int: 2 },
  3248. skills: {
  3249. knowledge_engineering: 'd8',
  3250. knowledge_hacking: 'd6',
  3251. dodge: 'd6'
  3252. }
  3253. },
  3254. 'bodyguard': {
  3255. stats: { str: 2 },
  3256. skills: {
  3257. fight: 'd8',
  3258. dodge: 'd6',
  3259. perception: 'd6'
  3260. }
  3261. },
  3262. 'librarian': {
  3263. stats: { int: 2 },
  3264. skills: {
  3265. knowledge_human: 'd8',
  3266. knowledge_local: 'd6',
  3267. perception: 'd6'
  3268. }
  3269. },
  3270. 'partnered': {
  3271. skills: {
  3272. // The player can choose 2 skills to receive d8
  3273. }
  3274. }
  3275. };
  3276.  
  3277. return backgroundBonuses[background] || { stats: {}, skills: {} };
  3278. }
  3279.  
  3280. function getBackgroundInfo(background, characterType) {
  3281. const backgrounds = {
  3282. // Human Backgrounds
  3283. 'courtesan': `
  3284. <h3>Courtesan</h3>
  3285. <p><strong>Stat Bonuses:</strong> +2 to Manipulate, Perform, and Knowledge: Human</p>
  3286. <p><strong>Skill Proficiencies:</strong></p>
  3287. <ul>
  3288. <li>d8: Manipulate</li>
  3289. <li>d6: Perform, Persuade</li>
  3290. </ul>
  3291. `,
  3292. 'adventurer': `
  3293. <h3>Adventurer</h3>
  3294. <p><strong>Stat Bonuses:</strong> +2 to Fight, Survival, and Knowledge: Region</p>
  3295. <p><strong>Skill Proficiencies:</strong></p>
  3296. <ul>
  3297. <li>d8: Survival</li>
  3298. <li>d6: Fight, Perception</li>
  3299. </ul>
  3300. `,
  3301. 'diplomat': `
  3302. <h3>Diplomat</h3>
  3303. <p><strong>Stat Bonuses:</strong> +2 to Persuade, Knowledge: Human, and Knowledge: Local</p>
  3304. <p><strong>Skill Proficiencies:</strong></p>
  3305. <ul>
  3306. <li>d8: Persuade</li>
  3307. <li>d6: Manipulate, Knowledge: Local</li>
  3308. </ul>
  3309. `,
  3310. 'farmer': `
  3311. <h3>Farmer</h3>
  3312. <p><strong>Stat Bonuses:</strong> +2 to Survival, Knowledge: Cook, and Knowledge: Region</p>
  3313. <p><strong>Skill Proficiencies:</strong></p>
  3314. <ul>
  3315. <li>d8: Knowledge: Cook</li>
  3316. <li>d6: Survival, Perception</li>
  3317. </ul>
  3318. `,
  3319. 'janitor': `
  3320. <h3>Janitor</h3>
  3321. <p><strong>Stat Bonuses:</strong> +2 to Knowledge: Handyman, Stealth, and Perception</p>
  3322. <p><strong>Skill Proficiencies:</strong></p>
  3323. <ul>
  3324. <li>d8: Knowledge: Handyman</li>
  3325. <li>d6: Stealth, Perception</li>
  3326. </ul>
  3327. `,
  3328. 'sleuth': `
  3329. <h3>Sleuth</h3>
  3330. <p><strong>Stat Bonuses:</strong> +2 to Perception, Knowledge: Local, and Survival</p>
  3331. <p><strong>Skill Proficiencies:</strong></p>
  3332. <ul>
  3333. <li>d8: Perception</li>
  3334. <li>d6: Knowledge: Local, Survival</li>
  3335. </ul>
  3336. `,
  3337. 'slave': `
  3338. <h3>Slave</h3>
  3339. <p><strong>Stat Bonuses:</strong> +2 to Dodge, Stealth, and Survival</p>
  3340. <p><strong>Skill Proficiencies:</strong></p>
  3341. <ul>
  3342. <li>d8: Stealth</li>
  3343. <li>d6: Dodge, Survival</li>
  3344. </ul>
  3345. `,
  3346. 'wronged_hero': `
  3347. <h3>Wronged Hero</h3>
  3348. <p><strong>Stat Bonuses:</strong> +2 to Fight, Persuade, and Knowledge: Region</p>
  3349. <p><strong>Skill Proficiencies:</strong></p>
  3350. <ul>
  3351. <li>d8: Fight</li>
  3352. <li>d6: Knowledge: Region, Persuade</li>
  3353. </ul>
  3354. `,
  3355. 'doctor': `
  3356. <h3>Doctor</h3>
  3357. <p><strong>Stat Bonuses:</strong> +2 to Perception, Knowledge: Human, and Knowledge: Cook</p>
  3358. <p><strong>Skill Proficiencies:</strong></p>
  3359. <ul>
  3360. <li>d8: Knowledge: Human</li>
  3361. <li>d6: Perception, Knowledge: Cook</li>
  3362. </ul>
  3363. `,
  3364. 'carpenter': `
  3365. <h3>Carpenter</h3>
  3366. <p><strong>Stat Bonuses:</strong> +2 to Knowledge: Carpenter, Survival, and Knowledge: Handyman</p>
  3367. <p><strong>Skill Proficiencies:</strong></p>
  3368. <ul>
  3369. <li>d8: Knowledge: Carpenter</li>
  3370. <li>d6: Knowledge: Handyman, Survival</li>
  3371. </ul>
  3372. `,
  3373. 'child': `
  3374. <h3>Child</h3>
  3375. <p><strong>Stat Bonuses:</strong> +2 to Dodge, Stealth, and Manipulate</p>
  3376. <p><strong>Skill Proficiencies:</strong></p>
  3377. <ul>
  3378. <li>d8: Dodge</li>
  3379. <li>d6: Stealth, Manipulate</li>
  3380. </ul>
  3381. `,
  3382. 'explorer': `
  3383. <h3>Explorer</h3>
  3384. <p><strong>Stat Bonuses:</strong> +2 to Knowledge: Region, Survival, and Perception</p>
  3385. <p><strong>Skill Proficiencies:</strong></p>
  3386. <ul>
  3387. <li>d8: Knowledge: Region</li>
  3388. <li>d6: Survival, Perception</li>
  3389. </ul>
  3390. `,
  3391. 'fallen_noble': `
  3392. <h3>Fallen Noble</h3>
  3393. <p><strong>Stat Bonuses:</strong> +2 to Persuade, Knowledge: Human, and Knowledge: Local</p>
  3394. <p><strong>Skill Proficiencies:</strong></p>
  3395. <ul>
  3396. <li>d8: Persuade</li>
  3397. <li>d6: Knowledge: Human, Knowledge: Local</li>
  3398. </ul>
  3399. `,
  3400. 'student_of_magic': `
  3401. <h3>Student of Magic</h3>
  3402. <p><strong>Stat Bonuses:</strong> +2 to Knowledge: Digimon, Knowledge: Engineering, and Perception</p>
  3403. <p><strong>Skill Proficiencies:</strong></p>
  3404. <ul>
  3405. <li>d8: Knowledge: Digimon</li>
  3406. <li>d6: Knowledge: Engineering, Perception</li>
  3407. </ul>
  3408. `,
  3409. 'survivor': `
  3410. <h3>Survivor</h3>
  3411. <p><strong>Stat Bonuses:</strong> +2 to Survival, Perception, and Dodge</p>
  3412. <p><strong>Skill Proficiencies:</strong></p>
  3413. <ul>
  3414. <li>d8: Survival</li>
  3415. <li>d6: Perception, Dodge</li>
  3416. </ul>
  3417. `,
  3418. 'messenger': `
  3419. <h3>Messenger</h3>
  3420. <p><strong>Stat Bonuses:</strong> +2 to Dodge, Knowledge: Local, and Perception</p>
  3421. <p><strong>Skill Proficiencies:</strong></p>
  3422. <ul>
  3423. <li>d8: Knowledge: Local</li>
  3424. <li>d6: Dodge, Perception</li>
  3425. </ul>
  3426. `,
  3427. 'from_the_past': `
  3428. <h3>From The Past</h3>
  3429. <p><strong>Stat Bonuses:</strong> +2 to Knowledge: Human, Knowledge: Region, and Manipulate</p>
  3430. <p><strong>Skill Proficiencies:</strong></p>
  3431. <ul>
  3432. <li>d8: Knowledge: Region</li>
  3433. <li>d6: Knowledge: Human, Manipulate</li>
  3434. </ul>
  3435. `,
  3436. 'miner': `
  3437. <h3>Miner</h3>
  3438. <p><strong>Stat Bonuses:</strong> +2 to Knowledge: Handyman, Survival, and Perception</p>
  3439. <p><strong>Skill Proficiencies:</strong></p>
  3440. <ul>
  3441. <li>d8: Knowledge: Handyman</li>
  3442. <li>d6: Survival, Perception</li>
  3443. </ul>
  3444. `,
  3445. 'royalty': `
  3446. <h3>Royalty</h3>
  3447. <p><strong>Stat Bonuses:</strong> +2 to Persuade, Knowledge: Human, and Knowledge: Local</p>
  3448. <p><strong>Skill Proficiencies:</strong></p>
  3449. <ul>
  3450. <li>d8: Persuade</li>
  3451. <li>d6: Knowledge: Human, Knowledge: Local</li>
  3452. </ul>
  3453. `,
  3454. 'mute': `
  3455. <h3>Mute</h3>
  3456. <p><strong>Stat Bonuses:</strong> +2 to Stealth, Perception, and Manipulate</p>
  3457. <p><strong>Skill Proficiencies:</strong></p>
  3458. <ul>
  3459. <li>d8: Stealth</li>
  3460. <li>d6: Perception, Manipulate</li>
  3461. </ul>
  3462. `,
  3463. 'artist': `
  3464. <h3>Artist</h3>
  3465. <p><strong>Stat Bonuses:</strong> +2 to Perform, Knowledge: Human, and Persuade</p>
  3466. <p><strong>Skill Proficiencies:</strong></p>
  3467. <ul>
  3468. <li>d8: Perform</li>
  3469. <li>d6: Knowledge: Human, Persuade</li>
  3470. </ul>
  3471. `,
  3472. 'negotiator': `
  3473. <h3>Negotiator</h3>
  3474. <p><strong>Stat Bonuses:</strong> +2 to Persuade, Knowledge: Human, and Perception</p>
  3475. <p><strong>Skill Proficiencies:</strong></p>
  3476. <ul>
  3477. <li>d8: Persuade</li>
  3478. <li>d6: Knowledge: Human, Perception</li>
  3479. </ul>
  3480. `,
  3481. 'innkeeper': `
  3482. <h3>Innkeeper</h3>
  3483. <p><strong>Stat Bonuses:</strong> +2 to Knowledge: Cook, Persuade, and Knowledge: Local</p>
  3484. <p><strong>Skill Proficiencies:</strong></p>
  3485. <ul>
  3486. <li>d8: Knowledge: Cook</li>
  3487. <li>d6: Persuade, Knowledge: Local</li>
  3488. </ul>
  3489. `,
  3490. 'barmaid': `
  3491. <h3>Barmaid</h3>
  3492. <p><strong>Stat Bonuses:</strong> +2 to Manipulate, Persuade, and Knowledge: Local</p>
  3493. <p><strong>Skill Proficiencies:</strong></p>
  3494. <ul>
  3495. <li>d8: Manipulate</li>
  3496. <li>d6: Persuade, Knowledge: Local</li>
  3497. </ul>
  3498. `,
  3499. 'bartender': `
  3500. <h3>Bartender</h3>
  3501. <p><strong>Stat Bonuses:</strong> +2 to Persuade, Knowledge: Cook, and Knowledge: Local</p>
  3502. <p><strong>Skill Proficiencies:</strong></p>
  3503. <ul>
  3504. <li>d8: Persuade</li>
  3505. <li>d6: Knowledge: Cook, Knowledge: Local</li>
  3506. </ul>
  3507. `,
  3508. 'sex_slave': `
  3509. <h3>Sex Slave</h3>
  3510. <p><strong>Stat Bonuses:</strong> +2 to Manipulate, Persuade, and Stealth</p>
  3511. <p><strong>Skill Proficiencies:</strong></p>
  3512. <ul>
  3513. <li>d8: Manipulate</li>
  3514. <li>d6: Persuade, Stealth</li>
  3515. </ul>
  3516. `,
  3517. 'inventor': `
  3518. <h3>Inventor</h3>
  3519. <p><strong>Stat Bonuses:</strong> +2 to Knowledge: Engineering, Knowledge: Hacking, and Perception</p>
  3520. <p><strong>Skill Proficiencies:</strong></p>
  3521. <ul>
  3522. <li>d8: Knowledge: Engineering</li>
  3523. <li>d6: Knowledge: Hacking, Perception</li>
  3524. </ul>
  3525. `,
  3526. 'beggar': `
  3527. <h3>Beggar</h3>
  3528. <p><strong>Stat Bonuses:</strong> +2 to Stealth, Dodge, and Perception</p>
  3529. <p><strong>Skill Proficiencies:</strong></p>
  3530. <ul>
  3531. <li>d8: Stealth</li>
  3532. <li>d6: Dodge, Perception</li>
  3533. </ul>
  3534. `,
  3535. 'shepherd': `
  3536. <h3>Shepherd</h3>
  3537. <p><strong>Stat Bonuses:</strong> +2 to Knowledge: Region, Survival, and Perception</p>
  3538. <p><strong>Skill Proficiencies:</strong></p>
  3539. <ul>
  3540. <li>d8: Survival</li>
  3541. <li>d6: Knowledge: Region, Perception</li>
  3542. </ul>
  3543. `,
  3544. 'pilot': `
  3545. <h3>Pilot</h3>
  3546. <p><strong>Stat Bonuses:</strong> +2 to Knowledge: Engineering, Knowledge: Hacking, and Dodge</p>
  3547. <p><strong>Skill Proficiencies:</strong></p>
  3548. <ul>
  3549. <li>d8: Knowledge: Engineering</li>
  3550. <li>d6: Knowledge: Hacking, Dodge</li>
  3551. </ul>
  3552. `,
  3553. 'bodyguard': `
  3554. <h3>Bodyguard</h3>
  3555. <p><strong>Stat Bonuses:</strong> +2 to Fight, Dodge, and Perception</p>
  3556. <p><strong>Skill Proficiencies:</strong></p>
  3557. <ul>
  3558. <li>d8: Fight</li>
  3559. <li>d6: Dodge, Perception</li>
  3560. </ul>
  3561. `,
  3562. 'librarian': `
  3563. <h3>Librarian</h3>
  3564. <p><strong>Stat Bonuses:</strong> +2 to Knowledge: Human, Knowledge: Local, and Perception</p>
  3565. <p><strong>Skill Proficiencies:</strong></p>
  3566. <ul>
  3567. <li>d8: Knowledge: Human</li>
  3568. <li>d6: Knowledge: Local, Perception</li>
  3569. </ul>
  3570. `,
  3571. 'isekai': `
  3572. <h3>Isekai'd</h3>
  3573. <p><strong>General Features:</strong> Gain +2 to any two stats of your choice.</p>
  3574. <p>Select which stats to enhance in the options below.</p>
  3575. `,
  3576. // Digimon Backgrounds
  3577. 'partnered': `
  3578. <h3>Partnered</h3>
  3579. <p><strong>General Features:</strong> Gain d8 to any two skills of your choice.</p>
  3580. <p>Select which skills to enhance when rolling.</p>
  3581. `
  3582. };
  3583.  
  3584. return backgrounds[background] || '<p>No information available for this background.</p>';
  3585. }
  3586.  
  3587. // Image preview functionality
  3588. function previewImage(input, imageId) {
  3589. const file = input.files[0];
  3590. if (file) {
  3591. const reader = new FileReader();
  3592. reader.onload = function(e) {
  3593. document.getElementById(imageId).src = e.target.result;
  3594. }
  3595. reader.readAsDataURL(file);
  3596. }
  3597. }
  3598.  
  3599. // Experience & Level Calculation
  3600. document.getElementById('characterExp').addEventListener('change', () => {
  3601. calculateNextLevel('characterExp', 'characterLevel', 'characterNextLevel');
  3602. });
  3603.  
  3604. document.getElementById('partnerExp').addEventListener('change', () => {
  3605. calculateNextLevel('partnerExp', 'partnerLevel', 'partnerNextLevel');
  3606. });
  3607.  
  3608. function calculateNextLevel(expId, levelId, nextLevelId) {
  3609. const exp = parseInt(document.getElementById(expId).value) || 0;
  3610. let level = 1;
  3611. let nextLevelExp = 10;
  3612.  
  3613. // Calculate current level based on exp
  3614. while (exp >= nextLevelExp && level < 99) {
  3615. level++;
  3616. nextLevelExp = Math.ceil(nextLevelExp * 1.3);
  3617. }
  3618.  
  3619. document.getElementById(levelId).value = level;
  3620. document.getElementById(nextLevelId).value = nextLevelExp;
  3621.  
  3622. // Update rank based on level
  3623. if (expId === 'characterExp') {
  3624. updateRankFromLevel('characterLevel', 'characterRank');
  3625. updateStatCaps();
  3626. calculateStats();
  3627. } else {
  3628. updateRankFromLevel('partnerLevel', 'partnerRank');
  3629. updatePartnerStatCaps();
  3630. calculatePartnerStats();
  3631. }
  3632. }
  3633.  
  3634. // Stats management
  3635. const statInputs = document.querySelectorAll('.stat-input');
  3636. const partnerStatInputs = document.querySelectorAll('.partner-stat-input');
  3637.  
  3638. // Initial stats calculation
  3639. calculateStats();
  3640. calculatePartnerStats();
  3641.  
  3642. statInputs.forEach(input => {
  3643. input.addEventListener('change', () => {
  3644. validateStats(statInputs);
  3645. calculateStats();
  3646. });
  3647. });
  3648.  
  3649. partnerStatInputs.forEach(input => {
  3650. input.addEventListener('change', () => {
  3651. validateStats(partnerStatInputs);
  3652. calculatePartnerStats();
  3653. });
  3654. });
  3655.  
  3656. document.getElementById('characterRank').addEventListener('change', () => {
  3657. updateStatCaps();
  3658. calculateStats();
  3659. });
  3660.  
  3661. document.getElementById('partnerRank').addEventListener('change', () => {
  3662. updatePartnerStatCaps();
  3663. calculatePartnerStats();
  3664. });
  3665.  
  3666. document.getElementById('characterLevel').addEventListener('change', () => {
  3667. updateRankFromLevel('characterLevel', 'characterRank');
  3668. updateStatCaps();
  3669. calculateStats();
  3670. });
  3671.  
  3672. document.getElementById('partnerLevel').addEventListener('change', () => {
  3673. updateRankFromLevel('partnerLevel', 'partnerRank');
  3674. updatePartnerStatCaps();
  3675. calculatePartnerStats();
  3676. });
  3677.  
  3678. function updateRankFromLevel(levelId, rankId) {
  3679. const level = parseInt(document.getElementById(levelId).value);
  3680. const rankElement = document.getElementById(rankId);
  3681.  
  3682. if (level >= 1 && level <= 5) {
  3683. rankElement.value = 'in-training';
  3684. } else if (level >= 6 && level <= 20) {
  3685. rankElement.value = 'rookie';
  3686. } else if (level >= 21 && level <= 64) {
  3687. rankElement.value = 'champion';
  3688. } else if (level >= 65 && level <= 99) {
  3689. rankElement.value = 'ultimate';
  3690. }
  3691. }
  3692.  
  3693. function updateStatCaps() {
  3694. const rank = document.getElementById('characterRank').value;
  3695. let cap = 6;
  3696. let bonusPoints = 0;
  3697.  
  3698. switch(rank) {
  3699. case 'rookie':
  3700. cap = 10;
  3701. bonusPoints = 5;
  3702. break;
  3703. case 'champion':
  3704. cap = 15;
  3705. bonusPoints = 10;
  3706. break;
  3707. case 'ultimate':
  3708. cap = 20;
  3709. bonusPoints = 15;
  3710. break;
  3711. case 'mega':
  3712. cap = 50;
  3713. bonusPoints = 50;
  3714. break;
  3715. default:
  3716. cap = 6;
  3717. bonusPoints = 0;
  3718. }
  3719.  
  3720. statInputs.forEach(input => {
  3721. input.setAttribute('max', cap);
  3722. });
  3723.  
  3724. document.getElementById('statPointsRemaining').textContent = 7 + bonusPoints;
  3725. }
  3726.  
  3727. function updatePartnerStatCaps() {
  3728. const rank = document.getElementById('partnerRank').value;
  3729. let cap = 6;
  3730. let bonusPoints = 0;
  3731.  
  3732. switch(rank) {
  3733. case 'rookie':
  3734. cap = 10;
  3735. bonusPoints = 5;
  3736. break;
  3737. case 'champion':
  3738. cap = 15;
  3739. bonusPoints = 10;
  3740. break;
  3741. case 'ultimate':
  3742. cap = 20;
  3743. bonusPoints = 15;
  3744. break;
  3745. case 'mega':
  3746. cap = 50;
  3747. bonusPoints = 50;
  3748. break;
  3749. default:
  3750. cap = 6;
  3751. bonusPoints = 0;
  3752. }
  3753.  
  3754. partnerStatInputs.forEach(input => {
  3755. input.setAttribute('max', cap);
  3756. });
  3757.  
  3758. document.getElementById('partnerStatPointsRemaining').textContent = 7 + bonusPoints;
  3759. }
  3760.  
  3761. function validateStats(inputs) {
  3762. let total = 0;
  3763. inputs.forEach(input => {
  3764. total += parseInt(input.value || 0);
  3765. });
  3766.  
  3767. const isCharacter = inputs[0].id === 'baseHP';
  3768. const rank = isCharacter ? document.getElementById('characterRank').value : document.getElementById('partnerRank').value;
  3769.  
  3770. let maxPoints = 12; // 7 points + 5 starting at 1
  3771.  
  3772. switch(rank) {
  3773. case 'rookie':
  3774. maxPoints = 17; // 12 + 5 bonus
  3775. break;
  3776. case 'champion':
  3777. maxPoints = 22; // 12 + 10 bonus
  3778. break;
  3779. case 'ultimate':
  3780. maxPoints = 27; // 12 + 15 bonus
  3781. break;
  3782. case 'mega':
  3783. maxPoints = 62; // 12 + 50 bonus
  3784. break;
  3785. }
  3786.  
  3787. if (total > maxPoints) {
  3788. showNotification(`You've used ${total - maxPoints} too many stat points. Maximum is ${maxPoints}.`, true);
  3789.  
  3790. // Reset to valid values
  3791. let excess = total - maxPoints;
  3792. for (let i = inputs.length - 1; i >= 0; i--) {
  3793. let currentValue = parseInt(inputs[i].value);
  3794. if (currentValue > 1 && excess > 0) {
  3795. let reduction = Math.min(currentValue - 1, excess);
  3796. inputs[i].value = currentValue - reduction;
  3797. excess -= reduction;
  3798. }
  3799. }
  3800. }
  3801.  
  3802. // Update points remaining
  3803. if (isCharacter) {
  3804. document.getElementById('statPointsRemaining').textContent = maxPoints - total + 7;
  3805. } else {
  3806. document.getElementById('partnerStatPointsRemaining').textContent = maxPoints - total + 7;
  3807. }
  3808. }
  3809.  
  3810. function calculateStats() {
  3811. const baseHP = parseInt(document.getElementById('baseHP').value) || 1;
  3812. const def = parseInt(document.getElementById('def').value) || 1;
  3813. const baseSP = parseInt(document.getElementById('baseSP').value) || 1;
  3814. const int = parseInt(document.getElementById('int').value) || 1;
  3815.  
  3816. const rank = document.getElementById('characterRank').value;
  3817. let modifier = 1.5;
  3818.  
  3819. switch(rank) {
  3820. case 'rookie':
  3821. modifier = 2;
  3822. break;
  3823. case 'champion':
  3824. modifier = 2.5;
  3825. break;
  3826. case 'ultimate':
  3827. modifier = 3;
  3828. break;
  3829. case 'mega':
  3830. modifier = 3.5;
  3831. break;
  3832. default:
  3833. modifier = 1.5;
  3834. }
  3835.  
  3836. const maxHP = Math.floor((baseHP + def) * modifier);
  3837. const maxSP = Math.floor((baseSP + int) * modifier);
  3838.  
  3839. document.getElementById('hp-value').textContent = maxHP;
  3840. document.getElementById('sp-value').textContent = maxSP;
  3841.  
  3842. // Set initial current values if they're empty
  3843. if (!document.getElementById('currentHP').value) {
  3844. document.getElementById('currentHP').value = maxHP;
  3845. }
  3846. if (!document.getElementById('currentSP').value) {
  3847. document.getElementById('currentSP').value = maxSP;
  3848. }
  3849. }
  3850.  
  3851. function calculatePartnerStats() {
  3852. const baseHP = parseInt(document.getElementById('partnerBaseHP').value) || 1;
  3853. const def = parseInt(document.getElementById('partner-def').value) || 1;
  3854. const baseSP = parseInt(document.getElementById('partnerBaseSP').value) || 1;
  3855. const int = parseInt(document.getElementById('partner-int').value) || 1;
  3856.  
  3857. const rank = document.getElementById('partnerRank').value;
  3858. let modifier = 1.5;
  3859.  
  3860. switch(rank) {
  3861. case 'rookie':
  3862. modifier = 2;
  3863. break;
  3864. case 'champion':
  3865. modifier = 2.5;
  3866. break;
  3867. case 'ultimate':
  3868. modifier = 3;
  3869. break;
  3870. case 'mega':
  3871. modifier = 3.5;
  3872. break;
  3873. default:
  3874. modifier = 1.5;
  3875. }
  3876.  
  3877. const maxHP = Math.floor((baseHP + def) * modifier);
  3878. const maxSP = Math.floor((baseSP + int) * modifier);
  3879.  
  3880. document.getElementById('partner-hp-value').textContent = maxHP;
  3881. document.getElementById('partner-sp-value').textContent = maxSP;
  3882.  
  3883. // Set initial current values if they're empty
  3884. if (!document.getElementById('partnerCurrentHP').value) {
  3885. document.getElementById('partnerCurrentHP').value = maxHP;
  3886. }
  3887. if (!document.getElementById('partnerCurrentSP').value) {
  3888. document.getElementById('partnerCurrentSP').value = maxSP;
  3889. }
  3890. }
  3891.  
  3892. // Digimon Lines
  3893. function addDigimonLine() {
  3894. const container = document.getElementById('digimonLinesContainer');
  3895. const lineIndex = container.children.length;
  3896.  
  3897. const line = document.createElement('div');
  3898. line.className = 'evo-line';
  3899. line.innerHTML = `
  3900. <h3>Evolution Line ${lineIndex + 1}</h3>
  3901. <button type="button" class="remove-button" onclick="removeDigimonLine(this.parentNode)">Remove Line</button>
  3902.  
  3903. <div class="evo-stage">
  3904. <div class="evo-stage-title">In-Training</div>
  3905. <div class="form-group">
  3906. <label>Name</label>
  3907. <input type="text" name="inTrainingName_${lineIndex}">
  3908. </div>
  3909. <div class="form-group">
  3910. <label>Description</label>
  3911. <textarea name="inTrainingDesc_${lineIndex}"></textarea>
  3912. </div>
  3913. </div>
  3914.  
  3915. <div id="rookieContainer_${lineIndex}">
  3916. <!-- Rookie evolutions will go here -->
  3917. </div>
  3918. <button type="button" class="add-button" onclick="addEvolution('rookie', ${lineIndex})">Add Rookie Evolution</button>
  3919. `;
  3920.  
  3921. container.appendChild(line);
  3922.  
  3923. // Auto-save when adding a new line
  3924. if (autoSaveEnabled) saveCharacterSheet();
  3925. }
  3926.  
  3927. function removeDigimonLine(lineElement) {
  3928. lineElement.remove();
  3929. if (autoSaveEnabled) saveCharacterSheet();
  3930. }
  3931.  
  3932. function addEvolution(level, lineIndex) {
  3933. const container = document.getElementById(`${level}Container_${lineIndex}`);
  3934. const evoIndex = container.children.length;
  3935.  
  3936. const evo = document.createElement('div');
  3937. evo.className = 'evo-stage';
  3938.  
  3939. let nextLevel = '';
  3940. let levelTitle = '';
  3941.  
  3942. switch(level) {
  3943. case 'rookie':
  3944. nextLevel = 'champion';
  3945. levelTitle = 'Rookie';
  3946. break;
  3947. case 'champion':
  3948. nextLevel = 'ultimate';
  3949. levelTitle = 'Champion';
  3950. break;
  3951. case 'ultimate':
  3952. nextLevel = 'mega';
  3953. levelTitle = 'Ultimate';
  3954. break;
  3955. case 'mega':
  3956. nextLevel = '';
  3957. levelTitle = 'Mega';
  3958. break;
  3959. }
  3960.  
  3961. evo.innerHTML = `
  3962. <div class="evo-stage-title">${levelTitle}</div>
  3963. <button type="button" class="remove-button" onclick="removeEvolution(this.parentNode)">Remove</button>
  3964. <div class="form-group">
  3965. <label>Name</label>
  3966. <input type="text" name="${level}Name_${lineIndex}_${evoIndex}">
  3967. </div>
  3968. <div class="form-group">
  3969. <label>Description</label>
  3970. <textarea name="${level}Desc_${lineIndex}_${evoIndex}"></textarea>
  3971. </div>
  3972. `;
  3973.  
  3974. container.appendChild(evo);
  3975.  
  3976. // Add next level container if not mega
  3977. if (nextLevel) {
  3978. if (!document.getElementById(`${nextLevel}Container_${lineIndex}_${evoIndex}`)) {
  3979. const nextContainer = document.createElement('div');
  3980. nextContainer.id = `${nextLevel}Container_${lineIndex}_${evoIndex}`;
  3981. evo.appendChild(nextContainer);
  3982.  
  3983. const addButton = document.createElement('button');
  3984. addButton.className = 'add-button';
  3985. addButton.textContent = `Add ${nextLevel.charAt(0).toUpperCase() + nextLevel.slice(1)} Evolution`;
  3986. addButton.onclick = function() {
  3987. addEvolution(nextLevel, `${lineIndex}_${evoIndex}`);
  3988. };
  3989. evo.appendChild(addButton);
  3990. }
  3991. }
  3992.  
  3993. // Auto-save when adding a new evolution
  3994. if (autoSaveEnabled) saveCharacterSheet();
  3995. }
  3996.  
  3997. function removeEvolution(evoElement) {
  3998. evoElement.remove();
  3999. if (autoSaveEnabled) saveCharacterSheet();
  4000. }
  4001.  
  4002. // Mech Parts
  4003. function addMechPart() {
  4004. const partType = document.getElementById('mechPartType').value;
  4005. const container = document.getElementById(`mech${partType.charAt(0).toUpperCase() + partType.slice(1)}sContainer`);
  4006. const partIndex = container.children.length;
  4007.  
  4008. const part = document.createElement('div');
  4009. part.className = 'mech-part';
  4010. part.innerHTML = `
  4011. <h4>${partType.charAt(0).toUpperCase() + partType.slice(1)} ${partIndex + 1}</h4>
  4012. <button type="button" class="remove-button" onclick="removeMechPart(this.parentNode)">Remove</button>
  4013. <div class="form-group">
  4014. <label>Name</label>
  4015. <input type="text" name="mech${partType}Name_${partIndex}">
  4016. </div>
  4017. <div class="form-group">
  4018. <label>Description</label>
  4019. <textarea name="mech${partType}Desc_${partIndex}"></textarea>
  4020. </div>
  4021. <div class="form-group">
  4022. <label>Stats</label>
  4023. <textarea name="mech${partType}Stats_${partIndex}"></textarea>
  4024. </div>
  4025. `;
  4026.  
  4027. container.appendChild(part);
  4028.  
  4029. // Update the dropdown options for this part type
  4030. updateMechPartDropdowns(partType);
  4031.  
  4032. // Auto-save when adding a new part
  4033. if (autoSaveEnabled) saveCharacterSheet();
  4034. }
  4035.  
  4036. function removeMechPart(partElement) {
  4037. // Get the part type from the container ID
  4038. const container = partElement.parentNode;
  4039. const partType = container.id.replace('mech', '').replace('Container', '').toLowerCase();
  4040.  
  4041. partElement.remove();
  4042.  
  4043. // Update the dropdown options after removing
  4044. updateMechPartDropdowns(partType);
  4045.  
  4046. if (autoSaveEnabled) saveCharacterSheet();
  4047. }
  4048.  
  4049. function updateMechPartDropdowns(partType) {
  4050. const container = document.getElementById(`mech${partType.charAt(0).toUpperCase() + partType.slice(1)}sContainer`);
  4051. const dropdown = document.getElementById(`selected${partType.charAt(0).toUpperCase() + partType.slice(1)}`);
  4052.  
  4053. // Clear current options except the first one
  4054. while (dropdown.options.length > 1) {
  4055. dropdown.remove(1);
  4056. }
  4057.  
  4058. // Add an option for each part in the container
  4059. const parts = container.querySelectorAll('.mech-part');
  4060. parts.forEach((part, index) => {
  4061. const nameInput = part.querySelector(`input[name^="mech${partType}Name_"]`);
  4062. const name = nameInput.value || `${partType.charAt(0).toUpperCase() + partType.slice(1)} ${index + 1}`;
  4063.  
  4064. const option = document.createElement('option');
  4065. option.value = index;
  4066. option.textContent = name;
  4067. dropdown.appendChild(option);
  4068. });
  4069. }
  4070.  
  4071. // Items
  4072. function addItem() {
  4073. const container = document.getElementById('itemsContainer');
  4074. const itemIndex = container.children.length;
  4075.  
  4076. const item = document.createElement('div');
  4077. item.className = 'item-entry';
  4078. item.innerHTML = `
  4079. <button type="button" class="remove-button" onclick="removeItem(this.parentNode)">Remove</button>
  4080. <div class="form-group">
  4081. <label>Name</label>
  4082. <input type="text" name="itemName_${itemIndex}">
  4083. </div>
  4084. <div class="form-group">
  4085. <label>Description</label>
  4086. <textarea name="itemDesc_${itemIndex}"></textarea>
  4087. </div>
  4088. <div class="form-group">
  4089. <label>Effects</label>
  4090. <textarea name="itemEffects_${itemIndex}"></textarea>
  4091. </div>
  4092. `;
  4093.  
  4094. container.appendChild(item);
  4095.  
  4096. // Auto-save when adding a new item
  4097. if (autoSaveEnabled) saveCharacterSheet();
  4098. }
  4099.  
  4100. function removeItem(itemElement) {
  4101. itemElement.remove();
  4102. if (autoSaveEnabled) saveCharacterSheet();
  4103. }
  4104.  
  4105. // Dice rolling
  4106. function rollDice() {
  4107. const diceType = document.getElementById('diceType').value;
  4108. let max;
  4109.  
  4110. switch(diceType) {
  4111. case 'd4':
  4112. max = 4;
  4113. break;
  4114. case 'd6':
  4115. max = 6;
  4116. break;
  4117. case 'd8':
  4118. max = 8;
  4119. break;
  4120. case 'd12':
  4121. max = 12;
  4122. break;
  4123. case 'd20':
  4124. max = 20;
  4125. break;
  4126. default:
  4127. max = 6;
  4128. }
  4129.  
  4130. const result = Math.floor(Math.random() * max) + 1;
  4131. document.getElementById('rollResult').textContent = `${result} (${diceType})`;
  4132.  
  4133. // Animation effect
  4134. const rollResult = document.getElementById('rollResult');
  4135. rollResult.style.transform = 'scale(1.2)';
  4136. rollResult.style.transition = 'transform 0.2s';
  4137. setTimeout(() => {
  4138. rollResult.style.transform = 'scale(1)';
  4139. }, 200);
  4140. }
  4141.  
  4142. function rollSkill(skill) {
  4143. const selectedDice = document.querySelector(`input[name="${skill}"]:checked`).value;
  4144. if (selectedDice === 'none') {
  4145. showNotification('Please select a proficiency level for this skill first.', true);
  4146. return;
  4147. }
  4148.  
  4149. let max;
  4150. switch(selectedDice) {
  4151. case 'd4':
  4152. max = 4;
  4153. break;
  4154. case 'd6':
  4155. max = 6;
  4156. break;
  4157. case 'd8':
  4158. max = 8;
  4159. break;
  4160. case 'd12':
  4161. max = 12;
  4162. break;
  4163. case 'd20':
  4164. max = 20;
  4165. break;
  4166. default:
  4167. max = 6;
  4168. }
  4169.  
  4170. // Get the associated stat
  4171. let statType;
  4172. if (skill.includes('knowledge_')) {
  4173. const knowledgeType = skill.replace('knowledge_', '');
  4174. if (['digimon', 'local', 'region', 'handyman', 'hacking', 'engineering'].includes(knowledgeType)) {
  4175. statType = 'int';
  4176. } else if (['human', 'smith', 'carpenter', 'cook'].includes(knowledgeType)) {
  4177. statType = 'wil';
  4178. } else if (knowledgeType === 'trapper') {
  4179. statType = 'agi';
  4180. }
  4181. } else if (['dodge', 'stealth', 'survival', 'perception'].includes(skill)) {
  4182. statType = 'agi';
  4183. } else if (skill === 'fight') {
  4184. statType = 'str';
  4185. } else if (['manipulate', 'perform', 'persuade'].includes(skill)) {
  4186. statType = 'wil';
  4187. }
  4188.  
  4189. // Get stat bonus
  4190. const statValue = parseInt(document.getElementById(statType).value) || 0;
  4191.  
  4192. // Apply background bonuses if applicable
  4193. const characterType = document.querySelector('input[name="characterType"]:checked').value;
  4194. const background = characterType === 'tamer'
  4195. ? document.getElementById('characterBackground').value
  4196. : document.getElementById('digimonBackground').value;
  4197.  
  4198. let backgroundBonus = 0;
  4199.  
  4200. if (background && background !== 'isekai') {
  4201. const backgroundBonuses = getBackgroundBonuses(background);
  4202. if (backgroundBonuses.stats && backgroundBonuses.stats[statType]) {
  4203. backgroundBonus = backgroundBonuses.stats[statType];
  4204. }
  4205. }
  4206.  
  4207. const diceRoll = Math.floor(Math.random() * max) + 1;
  4208. const totalResult = diceRoll + statValue + backgroundBonus;
  4209.  
  4210. document.getElementById('rollResult').textContent = `${diceRoll} (${selectedDice}) + ${statValue} (${statType.toUpperCase()}) ${backgroundBonus > 0 ? '+ ' + backgroundBonus + ' (background)' : ''} = ${totalResult} - ${skill.replace('_', ' ')}`;
  4211.  
  4212. // Animation effect
  4213. const rollResult = document.getElementById('rollResult');
  4214. rollResult.style.transform = 'scale(1.2)';
  4215. rollResult.style.transition = 'transform 0.2s';
  4216. setTimeout(() => {
  4217. rollResult.style.transform = 'scale(1)';
  4218. }, 200);
  4219.  
  4220. // Switch to character tab to see the result
  4221. document.querySelector('.tab[data-tab="character-tab"]').click();
  4222. }
  4223.  
  4224. function rollPartnerSkill(skill, statType) {
  4225. const selectedDice = document.querySelector(`input[name="${skill}"]:checked`).value;
  4226. if (selectedDice === 'none') {
  4227. showNotification('Please select a proficiency level for this skill first.', true);
  4228. return;
  4229. }
  4230.  
  4231. let max;
  4232. switch(selectedDice) {
  4233. case 'd4':
  4234. max = 4;
  4235. break;
  4236. case 'd6':
  4237. max = 6;
  4238. break;
  4239. case 'd8':
  4240. max = 8;
  4241. break;
  4242. case 'd12':
  4243. max = 12;
  4244. break;
  4245. case 'd20':
  4246. max = 20;
  4247. break;
  4248. default:
  4249. max = 6;
  4250. }
  4251.  
  4252. // Get stat bonus
  4253. const actualStatId = statType === 'str' ? 'partner-str' :
  4254. statType === 'def' ? 'partner-def' :
  4255. statType === 'int' ? 'partner-int' :
  4256. statType === 'agi' ? 'partner-agi' : 'partner-wil';
  4257.  
  4258. const statValue = parseInt(document.getElementById(actualStatId).value) || 0;
  4259.  
  4260. // Apply background bonuses if applicable
  4261. const partnerType = document.getElementById('partnerType').value;
  4262. const background = partnerType === 'tamer'
  4263. ? document.getElementById('partnerHumanBackground').value
  4264. : document.getElementById('partnerDigimonBackground').value;
  4265.  
  4266. let backgroundBonus = 0;
  4267.  
  4268. if (background && background !== 'isekai') {
  4269. const backgroundBonuses = getBackgroundBonuses(background);
  4270. if (backgroundBonuses.stats) {
  4271. const statMapped = statType === 'str' ? 'str' :
  4272. statType === 'def' ? 'def' :
  4273. statType === 'int' ? 'int' :
  4274. statType === 'agi' ? 'agi' : 'wil';
  4275.  
  4276. if (backgroundBonuses.stats[statMapped]) {
  4277. backgroundBonus = backgroundBonuses.stats[statMapped];
  4278. }
  4279. }
  4280. }
  4281.  
  4282. const diceRoll = Math.floor(Math.random() * max) + 1;
  4283. const totalResult = diceRoll + statValue + backgroundBonus;
  4284.  
  4285. document.getElementById('rollResult').textContent = `${diceRoll} (${selectedDice}) + ${statValue} (${statType.toUpperCase()}) ${backgroundBonus > 0 ? '+ ' + backgroundBonus + ' (background)' : ''} = ${totalResult} - Partner ${skill.replace('partner_', '').replace('_', ' ')}`;
  4286.  
  4287. // Animation effect
  4288. const rollResult = document.getElementById('rollResult');
  4289. rollResult.style.transform = 'scale(1.2)';
  4290. rollResult.style.transition = 'transform 0.2s';
  4291. setTimeout(() => {
  4292. rollResult.style.transform = 'scale(1)';
  4293. }, 200);
  4294.  
  4295. // Switch to character tab to see the result
  4296. document.querySelector('.tab[data-tab="character-tab"]').click();
  4297. }
  4298.  
  4299. // Save/Load functionality
  4300. function saveCharacterSheet() {
  4301. const data = collectAllData();
  4302.  
  4303. // Save to localStorage
  4304. localStorage.setItem('digimonCharacter', JSON.stringify(data));
  4305.  
  4306. // Visual indicator that save was successful
  4307. showNotification('Character data saved!');
  4308. }
  4309.  
  4310. function loadCharacterSheet() {
  4311. const savedData = localStorage.getItem('digimonCharacter');
  4312. if (!savedData) {
  4313. showNotification('No saved character data found.', true);
  4314. return;
  4315. }
  4316.  
  4317. loadAllData(JSON.parse(savedData));
  4318. showNotification('Character data loaded successfully!');
  4319. }
  4320.  
  4321. function exportToJSON() {
  4322. const data = collectAllData();
  4323. const dataStr = JSON.stringify(data, null, 2);
  4324. const dataUri = 'data:application/json;charset=utf-8,'+ encodeURIComponent(dataStr);
  4325.  
  4326. const exportFileName = `${data.characterName || 'digimon'}_character.json`;
  4327.  
  4328. const linkElement = document.createElement('a');
  4329. linkElement.setAttribute('href', dataUri);
  4330. linkElement.setAttribute('download', exportFileName);
  4331. linkElement.click();
  4332.  
  4333. showNotification('Exported to JSON file!');
  4334. }
  4335.  
  4336. function importFromJSON(input) {
  4337. const file = input.files[0];
  4338. if (file) {
  4339. const reader = new FileReader();
  4340. reader.onload = function(e) {
  4341. try {
  4342. const data = JSON.parse(e.target.result);
  4343. loadAllData(data);
  4344. showNotification('Character data imported successfully!');
  4345. } catch (error) {
  4346. showNotification('Error parsing JSON file: ' + error.message, true);
  4347. }
  4348. };
  4349. reader.readAsText(file);
  4350. }
  4351. }
  4352.  
  4353. function importBackgrounds() {
  4354. const input = document.createElement('input');
  4355. input.type = 'file';
  4356. input.accept = '.json';
  4357. input.onchange = function() {
  4358. const file = input.files[0];
  4359. if (file) {
  4360. const reader = new FileReader();
  4361. reader.onload = function(e) {
  4362. try {
  4363. const data = JSON.parse(e.target.result);
  4364. if (data.backgrounds) {
  4365. // Process imported backgrounds
  4366. importedBackgrounds = data.backgrounds;
  4367.  
  4368. // Update background dropdowns
  4369. updateBackgroundOptions();
  4370.  
  4371. showNotification('Backgrounds imported successfully!');
  4372. } else {
  4373. showNotification('Invalid background file format.', true);
  4374. }
  4375. } catch (error) {
  4376. showNotification('Error parsing JSON file: ' + error.message, true);
  4377. }
  4378. };
  4379. reader.readAsText(file);
  4380. }
  4381. };
  4382. input.click();
  4383. }
  4384.  
  4385. function updateBackgroundOptions() {
  4386. // Update character background dropdown
  4387. const characterBackground = document.getElementById('characterBackground');
  4388. const digimonBackground = document.getElementById('digimonBackground');
  4389. const partnerHumanBackground = document.getElementById('partnerHumanBackground');
  4390. const partnerDigimonBackground = document.getElementById('partnerDigimonBackground');
  4391.  
  4392. // Save current selections
  4393. const characterSelected = characterBackground.value;
  4394. const digimonSelected = digimonBackground.value;
  4395. const partnerHumanSelected = partnerHumanBackground.value;
  4396. const partnerDigimonSelected = partnerDigimonBackground.value;
  4397.  
  4398. // First option is empty
  4399. while (characterBackground.options.length > 1) {
  4400. characterBackground.remove(1);
  4401. }
  4402. while (digimonBackground.options.length > 1) {
  4403. digimonBackground.remove(1);
  4404. }
  4405. while (partnerHumanBackground.options.length > 1) {
  4406. partnerHumanBackground.remove(1);
  4407. }
  4408. while (partnerDigimonBackground.options.length > 1) {
  4409. partnerDigimonBackground.remove(1);
  4410. }
  4411.  
  4412. // Add standard backgrounds
  4413. const humanBackgrounds = [
  4414. 'courtesan', 'adventurer', 'diplomat', 'farmer', 'janitor', 'sleuth', 'slave',
  4415. 'wronged_hero', 'doctor', 'carpenter', 'child', 'explorer', 'fallen_noble',
  4416. 'student_of_magic', 'survivor', 'messenger', 'from_the_past', 'miner', 'royalty',
  4417. 'mute', 'artist', 'negotiator', 'innkeeper', 'barmaid', 'bartender', 'sex_slave',
  4418. 'inventor', 'beggar', 'shepherd', 'pilot', 'bodyguard', 'librarian', 'isekai'
  4419. ];
  4420.  
  4421. const digimonBackgrounds = ['isekai', 'partnered'];
  4422.  
  4423. // Add human backgrounds to character dropdown
  4424. humanBackgrounds.forEach(bg => {
  4425. const displayName = bg.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase());
  4426.  
  4427. const option1 = document.createElement('option');
  4428. option1.value = bg;
  4429. option1.textContent = displayName;
  4430. characterBackground.appendChild(option1);
  4431.  
  4432. const option2 = document.createElement('option');
  4433. option2.value = bg;
  4434. option2.textContent = displayName;
  4435. partnerHumanBackground.appendChild(option2);
  4436. });
  4437.  
  4438. // Add digimon backgrounds to digimon dropdown
  4439. digimonBackgrounds.forEach(bg => {
  4440. const displayName = bg.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase());
  4441.  
  4442. const option1 = document.createElement('option');
  4443. option1.value = bg;
  4444. option1.textContent = displayName;
  4445. digimonBackground.appendChild(option1);
  4446.  
  4447. const option2 = document.createElement('option');
  4448. option2.value = bg;
  4449. option2.textContent = displayName;
  4450. partnerDigimonBackground.appendChild(option2);
  4451. });
  4452.  
  4453. // Add custom backgrounds if any
  4454. if (importedBackgrounds) {
  4455. Object.keys(importedBackgrounds).forEach(bg => {
  4456. const bgData = importedBackgrounds[bg];
  4457. const displayName = bg.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase());
  4458.  
  4459. if (bgData.type === 'human' || bgData.type === 'both') {
  4460. const option1 = document.createElement('option');
  4461. option1.value = bg;
  4462. option1.textContent = displayName;
  4463. characterBackground.appendChild(option1);
  4464.  
  4465. const option2 = document.createElement('option');
  4466. option2.value = bg;
  4467. option2.textContent = displayName;
  4468. partnerHumanBackground.appendChild(option2);
  4469. }
  4470.  
  4471. if (bgData.type === 'digimon' || bgData.type === 'both') {
  4472. const option1 = document.createElement('option');
  4473. option1.value = bg;
  4474. option1.textContent = displayName;
  4475. digimonBackground.appendChild(option1);
  4476.  
  4477. const option2 = document.createElement('option');
  4478. option2.value = bg;
  4479. option2.textContent = displayName;
  4480. partnerDigimonBackground.appendChild(option2);
  4481. }
  4482. });
  4483. }
  4484.  
  4485. // Restore selections
  4486. characterBackground.value = characterSelected;
  4487. digimonBackground.value = digimonSelected;
  4488. partnerHumanBackground.value = partnerHumanSelected;
  4489. partnerDigimonBackground.value = partnerDigimonSelected;
  4490. }
  4491.  
  4492. function collectAllData() {
  4493. // Collect all form data
  4494. const data = {
  4495. // Character data
  4496. characterType: document.querySelector('input[name="characterType"]:checked').value,
  4497. characterName: document.getElementById('characterName').value,
  4498. characterLevel: document.getElementById('characterLevel').value,
  4499. characterExp: document.getElementById('characterExp').value,
  4500. characterBackground: document.getElementById('characterBackground').value,
  4501. digimonBackground: document.getElementById('digimonBackground').value,
  4502. characterRank: document.getElementById('characterRank').value,
  4503. characterImage: document.getElementById('characterImage').src,
  4504.  
  4505. // Isekai bonuses
  4506. isekaiStats: Array.from(document.querySelectorAll('.isekai-stat-bonus:checked')).map(cb => cb.value),
  4507.  
  4508. // Stats
  4509. baseHP: document.getElementById('baseHP').value,
  4510. currentHP: document.getElementById('currentHP').value,
  4511. baseSP: document.getElementById('baseSP').value,
  4512. currentSP: document.getElementById('currentSP').value,
  4513. str: document.getElementById('str').value,
  4514. def: document.getElementById('def').value,
  4515. int: document.getElementById('int').value,
  4516. agi: document.getElementById('agi').value,
  4517. wil: document.getElementById('wil').value,
  4518.  
  4519. // Partner data
  4520. partnerName: document.getElementById('partnerName').value,
  4521. partnerLevel: document.getElementById('partnerLevel').value,
  4522. partnerExp: document.getElementById('partnerExp').value,
  4523. partnerType: document.getElementById('partnerType').value,
  4524. partnerHumanBackground: document.getElementById('partnerHumanBackground').value,
  4525. partnerDigimonBackground: document.getElementById('partnerDigimonBackground').value,
  4526. partnerRank: document.getElementById('partnerRank').value,
  4527. partnerImage: document.getElementById('partnerImage').src,
  4528.  
  4529. // Partner Isekai bonuses
  4530. partnerIsekaiStats: Array.from(document.querySelectorAll('.partner-isekai-stat-bonus:checked')).map(cb => cb.value),
  4531.  
  4532. // Partner stats
  4533. partnerBaseHP: document.getElementById('partnerBaseHP').value,
  4534. partnerCurrentHP: document.getElementById('partnerCurrentHP').value,
  4535. partnerBaseSP: document.getElementById('partnerBaseSP').value,
  4536. partnerCurrentSP: document.getElementById('partnerCurrentSP').value,
  4537. partnerStr: document.getElementById('partner-str').value,
  4538. partnerDef: document.getElementById('partner-def').value,
  4539. partnerInt: document.getElementById('partner-int').value,
  4540. partnerAgi: document.getElementById('partner-agi').value,
  4541. partnerWil: document.getElementById('partner-wil').value,
  4542.  
  4543. // Notes
  4544. itemsNotes: document.getElementById('itemsNotes').value,
  4545. aspectsNotes: document.getElementById('aspectsNotes').value,
  4546. campaignNotes: document.getElementById('campaignNotes').value,
  4547. classSkillsNotes: document.getElementById('classSkillsNotes').value,
  4548. rulesNotes: document.getElementById('rulesNotes').value,
  4549.  
  4550. // Skills
  4551. skills: collectSkills(),
  4552. partnerSkills: collectPartnerSkills(),
  4553.  
  4554. // Items, Digimon Lines, and Mech parts
  4555. items: collectItems(),
  4556. digimonLines: collectDigimonLines(),
  4557. mechParts: collectMechParts(),
  4558. mechConfig: collectMechConfig()
  4559. };
  4560.  
  4561. return data;
  4562. }
  4563.  
  4564. function collectSkills() {
  4565. const skills = {};
  4566. const skillNames = [
  4567. 'dodge', 'fight', 'stealth', 'manipulate', 'perform',
  4568. 'persuade', 'survival', 'perception', 'knowledge_digimon',
  4569. 'knowledge_human', 'knowledge_local', 'knowledge_region',
  4570. 'knowledge_trapper', 'knowledge_smith', 'knowledge_carpenter',
  4571. 'knowledge_handyman', 'knowledge_cook', 'knowledge_hacking',
  4572. 'knowledge_engineering'
  4573. ];
  4574.  
  4575. skillNames.forEach(skill => {
  4576. const selectedRadio = document.querySelector(`input[name="${skill}"]:checked`);
  4577. if (selectedRadio) {
  4578. skills[skill] = selectedRadio.value;
  4579. }
  4580. });
  4581.  
  4582. return skills;
  4583. }
  4584.  
  4585. function collectPartnerSkills() {
  4586. const skills = {};
  4587. const skillNames = [
  4588. 'partner_dodge', 'partner_fight', 'partner_stealth',
  4589. 'partner_manipulate', 'partner_perform', 'partner_persuade',
  4590. 'partner_survival', 'partner_perception', 'partner_knowledge_digimon',
  4591. 'partner_knowledge_human', 'partner_knowledge_local', 'partner_knowledge_region',
  4592. 'partner_knowledge_trapper', 'partner_knowledge_smith', 'partner_knowledge_carpenter',
  4593. 'partner_knowledge_handyman', 'partner_knowledge_cook', 'partner_knowledge_hacking',
  4594. 'partner_knowledge_engineering'
  4595. ];
  4596.  
  4597. skillNames.forEach(skill => {
  4598. const selectedRadio = document.querySelector(`input[name="${skill}"]:checked`);
  4599. if (selectedRadio) {
  4600. skills[skill] = selectedRadio.value;
  4601. }
  4602. });
  4603.  
  4604. return skills;
  4605. }
  4606. function collectItems() {
  4607. const items = [];
  4608. const itemElements = document.querySelectorAll('#itemsContainer .item-entry');
  4609.  
  4610. itemElements.forEach((el, index) => {
  4611. const nameInput = el.querySelector(`input[name="itemName_${index}"]`);
  4612. const descInput = el.querySelector(`textarea[name="itemDesc_${index}"]`);
  4613. const effectsInput = el.querySelector(`textarea[name="itemEffects_${index}"]`);
  4614.  
  4615. if (nameInput) {
  4616. items.push({
  4617. name: nameInput.value,
  4618. description: descInput ? descInput.value : '',
  4619. effects: effectsInput ? effectsInput.value : ''
  4620. });
  4621. }
  4622. });
  4623.  
  4624. return items;
  4625. }
  4626.  
  4627. function collectDigimonLines() {
  4628. const lines = [];
  4629. const lineElements = document.querySelectorAll('#digimonLinesContainer .evo-line');
  4630.  
  4631. lineElements.forEach((lineEl, lineIndex) => {
  4632. const line = {
  4633. inTraining: {
  4634. name: lineEl.querySelector(`input[name="inTrainingName_${lineIndex}"]`)?.value || '',
  4635. description: lineEl.querySelector(`textarea[name="inTrainingDesc_${lineIndex}"]`)?.value || ''
  4636. },
  4637. rookies: []
  4638. };
  4639.  
  4640. // Collect rookies (simplified implementation)
  4641. const rookieContainer = lineEl.querySelector(`#rookieContainer_${lineIndex}`);
  4642. if (rookieContainer) {
  4643. const rookieElements = rookieContainer.querySelectorAll('.evo-stage');
  4644. rookieElements.forEach((rookieEl, rookieIndex) => {
  4645. const rookie = {
  4646. name: rookieEl.querySelector(`input[name="rookieName_${lineIndex}_${rookieIndex}"]`)?.value || '',
  4647. description: rookieEl.querySelector(`textarea[name="rookieDesc_${lineIndex}_${rookieIndex}"]`)?.value || '',
  4648. champions: []
  4649. };
  4650.  
  4651. line.rookies.push(rookie);
  4652.  
  4653. // We could continue collecting champions, ultimates, and megas here
  4654. // But for simplicity we'll just store the rookies
  4655. });
  4656. }
  4657.  
  4658. lines.push(line);
  4659. });
  4660.  
  4661. return lines;
  4662. }
  4663.  
  4664. function collectMechParts() {
  4665. const mechParts = {
  4666. cores: collectMechPartsOfType('core'),
  4667. frames: collectMechPartsOfType('frame'),
  4668. weapons: collectMechPartsOfType('weapon'),
  4669. arms: collectMechPartsOfType('arm'),
  4670. legs: collectMechPartsOfType('leg'),
  4671. heads: collectMechPartsOfType('head')
  4672. };
  4673.  
  4674. return mechParts;
  4675. }
  4676.  
  4677. function collectMechPartsOfType(type) {
  4678. const parts = [];
  4679. const container = document.getElementById(`mech${type.charAt(0).toUpperCase() + type.slice(1)}sContainer`);
  4680. if (!container) return parts;
  4681.  
  4682. const partElements = container.querySelectorAll('.mech-part');
  4683. partElements.forEach((partEl, index) => {
  4684. const part = {
  4685. name: partEl.querySelector(`input[name="mech${type}Name_${index}"]`)?.value || '',
  4686. description: partEl.querySelector(`textarea[name="mech${type}Desc_${index}"]`)?.value || '',
  4687. stats: partEl.querySelector(`textarea[name="mech${type}Stats_${index}"]`)?.value || ''
  4688. };
  4689.  
  4690. parts.push(part);
  4691. });
  4692.  
  4693. return parts;
  4694. }
  4695.  
  4696. function collectMechConfig() {
  4697. return {
  4698. name: document.getElementById('mechName')?.value || '',
  4699. description: document.getElementById('mechDescription')?.value || '',
  4700. core: document.getElementById('selectedCore')?.value || '',
  4701. frame: document.getElementById('selectedFrame')?.value || '',
  4702. weapon: document.getElementById('selectedWeapon')?.value || '',
  4703. arm: document.getElementById('selectedArm')?.value || '',
  4704. leg: document.getElementById('selectedLeg')?.value || '',
  4705. head: document.getElementById('selectedHead')?.value || ''
  4706. };
  4707. }
  4708.  
  4709. function loadAllData(data) {
  4710. // Character data
  4711. if (data.characterType) {
  4712. document.querySelector(`input[name="characterType"][value="${data.characterType}"]`).checked = true;
  4713. }
  4714. if (data.characterName) document.getElementById('characterName').value = data.characterName;
  4715. if (data.characterLevel) document.getElementById('characterLevel').value = data.characterLevel;
  4716. if (data.characterExp) document.getElementById('characterExp').value = data.characterExp;
  4717. if (data.characterBackground) document.getElementById('characterBackground').value = data.characterBackground;
  4718. if (data.digimonBackground) document.getElementById('digimonBackground').value = data.digimonBackground;
  4719. if (data.characterRank) document.getElementById('characterRank').value = data.characterRank;
  4720. if (data.characterImage) document.getElementById('characterImage').src = data.characterImage;
  4721.  
  4722. // Handle character type toggle
  4723. const isTamer = data.characterType === 'tamer';
  4724. document.querySelectorAll('.tamer-only').forEach(el => {
  4725. el.style.display = isTamer ? 'block' : 'none';
  4726. });
  4727. document.querySelectorAll('.digimon-only').forEach(el => {
  4728. el.style.display = isTamer ? 'none' : 'block';
  4729. });
  4730.  
  4731. // Update background info
  4732. updateBackgroundInfo();
  4733.  
  4734. // Isekai bonuses
  4735. if (data.isekaiStats) {
  4736. document.querySelectorAll('.isekai-stat-bonus').forEach(checkbox => {
  4737. checkbox.checked = data.isekaiStats.includes(checkbox.value);
  4738. });
  4739. if (data.characterBackground === 'isekai' || data.digimonBackground === 'isekai') {
  4740. applyIsekaiBonus();
  4741. }
  4742. }
  4743.  
  4744. // Stats
  4745. if (data.baseHP) document.getElementById('baseHP').value = data.baseHP;
  4746. if (data.currentHP) document.getElementById('currentHP').value = data.currentHP;
  4747. if (data.baseSP) document.getElementById('baseSP').value = data.baseSP;
  4748. if (data.currentSP) document.getElementById('currentSP').value = data.currentSP;
  4749. if (data.str) document.getElementById('str').value = data.str;
  4750. if (data.def) document.getElementById('def').value = data.def;
  4751. if (data.int) document.getElementById('int').value = data.int;
  4752. if (data.agi) document.getElementById('agi').value = data.agi;
  4753. if (data.wil) document.getElementById('wil').value = data.wil;
  4754.  
  4755. // Partner data
  4756. if (data.partnerName) document.getElementById('partnerName').value = data.partnerName;
  4757. if (data.partnerLevel) document.getElementById('partnerLevel').value = data.partnerLevel;
  4758. if (data.partnerExp) document.getElementById('partnerExp').value = data.partnerExp;
  4759. if (data.partnerType) document.getElementById('partnerType').value = data.partnerType;
  4760. if (data.partnerHumanBackground) document.getElementById('partnerHumanBackground').value = data.partnerHumanBackground;
  4761. if (data.partnerDigimonBackground) document.getElementById('partnerDigimonBackground').value = data.partnerDigimonBackground;
  4762. if (data.partnerRank) document.getElementById('partnerRank').value = data.partnerRank;
  4763. if (data.partnerImage) document.getElementById('partnerImage').src = data.partnerImage;
  4764.  
  4765. // Handle partner type toggle
  4766. const isHuman = data.partnerType === 'tamer';
  4767. document.querySelectorAll('.partner-tamer-only').forEach(el => {
  4768. el.style.display = isHuman ? 'block' : 'none';
  4769. });
  4770. document.querySelectorAll('.partner-digimon-only').forEach(el => {
  4771. el.style.display = isHuman ? 'none' : 'block';
  4772. });
  4773.  
  4774. // Update partner background info
  4775. updatePartnerBackgroundInfo();
  4776.  
  4777. // Partner Isekai bonuses
  4778. if (data.partnerIsekaiStats) {
  4779. document.querySelectorAll('.partner-isekai-stat-bonus').forEach(checkbox => {
  4780. checkbox.checked = data.partnerIsekaiStats.includes(checkbox.value);
  4781. });
  4782. if (data.partnerHumanBackground === 'isekai' || data.partnerDigimonBackground === 'isekai') {
  4783. applyPartnerIsekaiBonus();
  4784. }
  4785. }
  4786.  
  4787. // Partner stats
  4788. if (data.partnerBaseHP) document.getElementById('partnerBaseHP').value = data.partnerBaseHP;
  4789. if (data.partnerCurrentHP) document.getElementById('partnerCurrentHP').value = data.partnerCurrentHP;
  4790. if (data.partnerBaseSP) document.getElementById('partnerBaseSP').value = data.partnerBaseSP;
  4791. if (data.partnerCurrentSP) document.getElementById('partnerCurrentSP').value = data.partnerCurrentSP;
  4792. if (data.partnerStr) document.getElementById('partner-str').value = data.partnerStr;
  4793. if (data.partnerDef) document.getElementById('partner-def').value = data.partnerDef;
  4794. if (data.partnerInt) document.getElementById('partner-int').value = data.partnerInt;
  4795. if (data.partnerAgi) document.getElementById('partner-agi').value = data.partnerAgi;
  4796. if (data.partnerWil) document.getElementById('partner-wil').value = data.partnerWil;
  4797.  
  4798. // Notes
  4799. if (data.itemsNotes) document.getElementById('itemsNotes').value = data.itemsNotes;
  4800. if (data.aspectsNotes) document.getElementById('aspectsNotes').value = data.aspectsNotes;
  4801. if (data.campaignNotes) document.getElementById('campaignNotes').value = data.campaignNotes;
  4802. if (data.classSkillsNotes) document.getElementById('classSkillsNotes').value = data.classSkillsNotes;
  4803. if (data.rulesNotes) document.getElementById('rulesNotes').value = data.rulesNotes;
  4804.  
  4805. // Skills
  4806. if (data.skills) {
  4807. for (const skill in data.skills) {
  4808. const value = data.skills[skill];
  4809. const radio = document.querySelector(`input[name="${skill}"][value="${value}"]`);
  4810. if (radio) radio.checked = true;
  4811. }
  4812. }
  4813.  
  4814. // Partner Skills
  4815. if (data.partnerSkills) {
  4816. for (const skill in data.partnerSkills) {
  4817. const value = data.partnerSkills[skill];
  4818. const radio = document.querySelector(`input[name="${skill}"][value="${value}"]`);
  4819. if (radio) radio.checked = true;
  4820. }
  4821. }
  4822.  
  4823. // Load items
  4824. if (data.items && data.items.length > 0) {
  4825. // Clear existing items
  4826. document.getElementById('itemsContainer').innerHTML = '';
  4827.  
  4828. // Add each item
  4829. data.items.forEach((item, index) => {
  4830. const container = document.getElementById('itemsContainer');
  4831. const itemElement = document.createElement('div');
  4832. itemElement.className = 'item-entry';
  4833. itemElement.innerHTML = `
  4834. <button type="button" class="remove-button" onclick="removeItem(this.parentNode)">Remove</button>
  4835. <div class="form-group">
  4836. <label>Name</label>
  4837. <input type="text" name="itemName_${index}" value="${item.name || ''}">
  4838. </div>
  4839. <div class="form-group">
  4840. <label>Description</label>
  4841. <textarea name="itemDesc_${index}">${item.description || ''}</textarea>
  4842. </div>
  4843. <div class="form-group">
  4844. <label>Effects</label>
  4845. <textarea name="itemEffects_${index}">${item.effects || ''}</textarea>
  4846. </div>
  4847. `;
  4848. container.appendChild(itemElement);
  4849. });
  4850. }
  4851.  
  4852. // Load Digimon Lines
  4853. if (data.digimonLines && data.digimonLines.length > 0) {
  4854. // Clear existing lines
  4855. document.getElementById('digimonLinesContainer').innerHTML = '';
  4856.  
  4857. // Add each evolution line (simplified)
  4858. data.digimonLines.forEach((line, lineIndex) => {
  4859. const container = document.getElementById('digimonLinesContainer');
  4860. const lineElement = document.createElement('div');
  4861. lineElement.className = 'evo-line';
  4862. lineElement.innerHTML = `
  4863. <h3>Evolution Line ${lineIndex + 1}</h3>
  4864. <button type="button" class="remove-button" onclick="removeDigimonLine(this.parentNode)">Remove</button>
  4865.  
  4866. <div class="evo-stage">
  4867. <div class="evo-stage-title">In-Training</div>
  4868. <div class="form-group">
  4869. <label>Name</label>
  4870. <input type="text" name="inTrainingName_${lineIndex}" value="${line.inTraining?.name || ''}">
  4871. </div>
  4872. <div class="form-group">
  4873. <label>Description</label>
  4874. <textarea name="inTrainingDesc_${lineIndex}">${line.inTraining?.description || ''}</textarea>
  4875. </div>
  4876. </div>
  4877.  
  4878. <div id="rookieContainer_${lineIndex}">
  4879. <!-- Rookie evolutions will go here -->
  4880. </div>
  4881. <button type="button" class="add-button" onclick="addEvolution('rookie', ${lineIndex})">Add Rookie Evolution</button>
  4882. `;
  4883. container.appendChild(lineElement);
  4884.  
  4885. // Add rookies if they exist
  4886. if (line.rookies && line.rookies.length > 0) {
  4887. const rookieContainer = document.getElementById(`rookieContainer_${lineIndex}`);
  4888. line.rookies.forEach((rookie, rookieIndex) => {
  4889. const rookieElement = document.createElement('div');
  4890. rookieElement.className = 'evo-stage';
  4891. rookieElement.innerHTML = `
  4892. <div class="evo-stage-title">Rookie</div>
  4893. <button type="button" class="remove-button" onclick="removeEvolution(this.parentNode)">Remove</button>
  4894. <div class="form-group">
  4895. <label>Name</label>
  4896. <input type="text" name="rookieName_${lineIndex}_${rookieIndex}" value="${rookie.name || ''}">
  4897. </div>
  4898. <div class="form-group">
  4899. <label>Description</label>
  4900. <textarea name="rookieDesc_${lineIndex}_${rookieIndex}">${rookie.description || ''}</textarea>
  4901. </div>
  4902.  
  4903. <div id="championContainer_${lineIndex}_${rookieIndex}">
  4904. <!-- Champion evolutions would go here -->
  4905. </div>
  4906. <button type="button" class="add-button" onclick="addEvolution('champion', '${lineIndex}_${rookieIndex}')">Add Champion Evolution</button>
  4907. `;
  4908. rookieContainer.appendChild(rookieElement);
  4909. });
  4910. }
  4911. });
  4912. }
  4913.  
  4914. // Load Mech Parts
  4915. if (data.mechParts) {
  4916. // Load each type of mech part
  4917. loadMechPartsOfType('core', data.mechParts.cores);
  4918. loadMechPartsOfType('frame', data.mechParts.frames);
  4919. loadMechPartsOfType('weapon', data.mechParts.weapons);
  4920. loadMechPartsOfType('arm', data.mechParts.arms);
  4921. loadMechPartsOfType('leg', data.mechParts.legs);
  4922. loadMechPartsOfType('head', data.mechParts.heads);
  4923.  
  4924. // Update dropdowns
  4925. updateMechPartDropdowns('core');
  4926. updateMechPartDropdowns('frame');
  4927. updateMechPartDropdowns('weapon');
  4928. updateMechPartDropdowns('arm');
  4929. updateMechPartDropdowns('leg');
  4930. updateMechPartDropdowns('head');
  4931. }
  4932.  
  4933. // Load Mech Configuration
  4934. if (data.mechConfig) {
  4935. if (data.mechConfig.name) document.getElementById('mechName').value = data.mechConfig.name;
  4936. if (data.mechConfig.description) document.getElementById('mechDescription').value = data.mechConfig.description;
  4937. if (data.mechConfig.core) document.getElementById('selectedCore').value = data.mechConfig.core;
  4938. if (data.mechConfig.frame) document.getElementById('selectedFrame').value = data.mechConfig.frame;
  4939. if (data.mechConfig.weapon) document.getElementById('selectedWeapon').value = data.mechConfig.weapon;
  4940. if (data.mechConfig.arm) document.getElementById('selectedArm').value = data.mechConfig.arm;
  4941. if (data.mechConfig.leg) document.getElementById('selectedLeg').value = data.mechConfig.leg;
  4942. if (data.mechConfig.head) document.getElementById('selectedHead').value = data.mechConfig.head;
  4943. }
  4944.  
  4945. // Apply background bonuses
  4946. applyBackgroundBonuses();
  4947. applyPartnerBackgroundBonuses();
  4948.  
  4949. // Recalculate after loading
  4950. calculateStats();
  4951. calculatePartnerStats();
  4952. calculateNextLevel('characterExp', 'characterLevel', 'characterNextLevel');
  4953. calculateNextLevel('partnerExp', 'partnerLevel', 'partnerNextLevel');
  4954. }
  4955.  
  4956. function loadMechPartsOfType(type, parts) {
  4957. if (!parts || !parts.length) return;
  4958.  
  4959. const container = document.getElementById(`mech${type.charAt(0).toUpperCase() + type.slice(1)}sContainer`);
  4960. if (!container) return;
  4961.  
  4962. // Clear container
  4963. container.innerHTML = '';
  4964.  
  4965. // Add each part
  4966. parts.forEach((part, index) => {
  4967. const partElement = document.createElement('div');
  4968. partElement.className = 'mech-part';
  4969. partElement.innerHTML = `
  4970. <h4>${type.charAt(0).toUpperCase() + type.slice(1)} ${index + 1}</h4>
  4971. <button type="button" class="remove-button" onclick="removeMechPart(this.parentNode)">Remove</button>
  4972. <div class="form-group">
  4973. <label>Name</label>
  4974. <input type="text" name="mech${type}Name_${index}" value="${part.name || ''}">
  4975. </div>
  4976. <div class="form-group">
  4977. <label>Description</label>
  4978. <textarea name="mech${type}Desc_${index}">${part.description || ''}</textarea>
  4979. </div>
  4980. <div class="form-group">
  4981. <label>Stats</label>
  4982. <textarea name="mech${type}Stats_${index}">${part.stats || ''}</textarea>
  4983. </div>
  4984. `;
  4985. container.appendChild(partElement);
  4986. });
  4987. }
  4988.  
  4989. // Initialize with default settings
  4990. updateStatCaps();
  4991. updatePartnerStatCaps();
  4992.  
  4993. // Create initial Digimon lines and Mech parts on load
  4994. window.addEventListener('load', function() {
  4995. // Check if we have saved data first
  4996. const savedData = localStorage.getItem('digimonCharacter');
  4997. if (savedData) {
  4998. loadCharacterSheet();
  4999. } else {
  5000. // Otherwise create empty items
  5001. for (let i = 0; i < 3; i++) {
  5002. addDigimonLine();
  5003. }
  5004.  
  5005. // Add some initial mech parts
  5006. document.getElementById('mechPartType').value = 'core';
  5007. addMechPart();
  5008. document.getElementById('mechPartType').value = 'frame';
  5009. addMechPart();
  5010. document.getElementById('mechPartType').value = 'weapon';
  5011. addMechPart();
  5012. document.getElementById('mechPartType').value = 'arm';
  5013. addMechPart();
  5014. document.getElementById('mechPartType').value = 'leg';
  5015. addMechPart();
  5016. document.getElementById('mechPartType').value = 'head';
  5017. addMechPart();
  5018.  
  5019. // Add an initial item
  5020. addItem();
  5021.  
  5022. }
  5023. });
  5024. function addMove() {
  5025. const container = document.getElementById('movesContainer');
  5026. const moveIndex = container.children.length;
  5027.  
  5028. const move = document.createElement('div');
  5029. move.className = 'move-entry';
  5030. move.innerHTML = `
  5031. <div class="move-header">
  5032. <input type="text" id="moveName_${moveIndex}" placeholder="Move Name" class="move-name-input">
  5033. <div class="move-actions">
  5034. <button type="button" onclick="performMove(${moveIndex})" class="secondary">Use</button>
  5035. <button type="button" onclick="editMove(${moveIndex})" class="secondary">Edit</button>
  5036. <button type="button" onclick="removeMove(this.parentNode.parentNode.parentNode)" class="remove-button">Remove</button>
  5037. </div>
  5038. </div>
  5039.  
  5040. <div class="move-details">
  5041. <div class="form-group">
  5042. <label for="moveType_${moveIndex}">Type:</label>
  5043. <select id="moveType_${moveIndex}" onchange="updateMoveFields(${moveIndex})">
  5044. <option value="attack">Attack</option>
  5045. <option value="healing">Healing</option>
  5046. <option value="buff">Buff/Debuff</option>
  5047. <option value="utility">Utility</option>
  5048. </select>
  5049. </div>
  5050.  
  5051. <div class="form-group">
  5052. <label for="moveSPCost_${moveIndex}">SP Cost:</label>
  5053. <input type="number" id="moveSPCost_${moveIndex}" min="0" value="5">
  5054. </div>
  5055.  
  5056. <div class="form-group move-attack-field">
  5057. <label for="moveDamage_${moveIndex}">Base Damage:</label>
  5058. <input type="number" id="moveDamage_${moveIndex}" min="0" value="10">
  5059. </div>
  5060.  
  5061. <div class="form-group move-attack-field">
  5062. <label for="moveAttribute_${moveIndex}">Attribute:</label>
  5063. <select id="moveAttribute_${moveIndex}">
  5064. <option value="str">STR</option>
  5065. <option value="int">INT</option>
  5066. <option value="agi">AGI</option>
  5067. <option value="wil">WIL</option>
  5068. </select>
  5069. </div>
  5070.  
  5071. <div class="form-group move-healing-field" style="display: none;">
  5072. <label for="moveHealing_${moveIndex}">Healing Amount:</label>
  5073. <input type="number" id="moveHealing_${moveIndex}" min="0" value="10">
  5074. </div>
  5075.  
  5076. <div class="form-group move-buff-field" style="display: none;">
  5077. <label for="moveBuffStat_${moveIndex}">Buff Stat:</label>
  5078. <select id="moveBuffStat_${moveIndex}">
  5079. <option value="str">STR</option>
  5080. <option value="def">DEF</option>
  5081. <option value="int">INT</option>
  5082. <option value="agi">AGI</option>
  5083. <option value="wil">WIL</option>
  5084. </select>
  5085. </div>
  5086.  
  5087. <div class="form-group move-buff-field" style="display: none;">
  5088. <label for="moveBuffAmount_${moveIndex}">Buff Amount:</label>
  5089. <input type="number" id="moveBuffAmount_${moveIndex}" value="2">
  5090. </div>
  5091.  
  5092. <div class="form-group move-buff-field" style="display: none;">
  5093. <label for="moveBuffDuration_${moveIndex}">Duration (rounds):</label>
  5094. <input type="number" id="moveBuffDuration_${moveIndex}" min="1" value="3">
  5095. </div>
  5096.  
  5097. <div class="form-group move-description">
  5098. <label for="moveDescription_${moveIndex}">Description:</label>
  5099. <textarea id="moveDescription_${moveIndex}" rows="3" placeholder="Describe what the move does..."></textarea>
  5100. </div>
  5101. </div>
  5102.  
  5103. <div class="move-display">
  5104. <div id="moveDisplay_${moveIndex}"></div>
  5105. </div>
  5106. `;
  5107.  
  5108. container.appendChild(move);
  5109. updateMoveFields(moveIndex);
  5110. updateMoveSelector();
  5111.  
  5112. // Auto-save when adding a new move
  5113. if (autoSaveEnabled) saveCharacterSheet();
  5114. }
  5115.  
  5116. function updateMoveFields(moveIndex) {
  5117. const moveType = document.getElementById(`moveType_${moveIndex}`).value;
  5118.  
  5119. // Hide all type-specific fields
  5120. document.querySelectorAll(`#movesContainer .move-entry:nth-child(${moveIndex + 1}) .move-attack-field`).forEach(el => {
  5121. el.style.display = 'none';
  5122. });
  5123.  
  5124. document.querySelectorAll(`#movesContainer .move-entry:nth-child(${moveIndex + 1}) .move-healing-field`).forEach(el => {
  5125. el.style.display = 'none';
  5126. });
  5127.  
  5128. document.querySelectorAll(`#movesContainer .move-entry:nth-child(${moveIndex + 1}) .move-buff-field`).forEach(el => {
  5129. el.style.display = 'none';
  5130. });
  5131.  
  5132. // Show relevant fields based on move type
  5133. switch(moveType) {
  5134. case 'attack':
  5135. document.querySelectorAll(`#movesContainer .move-entry:nth-child(${moveIndex + 1}) .move-attack-field`).forEach(el => {
  5136. el.style.display = 'block';
  5137. });
  5138. break;
  5139. case 'healing':
  5140. document.querySelectorAll(`#movesContainer .move-entry:nth-child(${moveIndex + 1}) .move-healing-field`).forEach(el => {
  5141. el.style.display = 'block';
  5142. });
  5143. break;
  5144. case 'buff':
  5145. document.querySelectorAll(`#movesContainer .move-entry:nth-child(${moveIndex + 1}) .move-buff-field`).forEach(el => {
  5146. el.style.display = 'block';
  5147. });
  5148. break;
  5149. }
  5150.  
  5151. updateMoveDisplay(moveIndex);
  5152. }
  5153.  
  5154. function updateMoveDisplay(moveIndex) {
  5155. const moveName = document.getElementById(`moveName_${moveIndex}`).value || 'Unnamed Move';
  5156. const moveType = document.getElementById(`moveType_${moveIndex}`).value;
  5157. const spCost = document.getElementById(`moveSPCost_${moveIndex}`).value;
  5158.  
  5159. let displayHTML = `<div class="move-title">${moveName}`;
  5160. displayHTML += `<span class="move-type ${moveType}">${moveType.charAt(0).toUpperCase() + moveType.slice(1)}</span>`;
  5161. displayHTML += `<span class="move-sp-cost">${spCost} SP</span></div>`;
  5162.  
  5163. document.getElementById(`moveDisplay_${moveIndex}`).innerHTML = displayHTML;
  5164. }
  5165.  
  5166. function removeMove(moveElement) {
  5167. moveElement.remove();
  5168. updateMoveSelector();
  5169. if (autoSaveEnabled) saveCharacterSheet();
  5170. }
  5171.  
  5172. function editMove(moveIndex) {
  5173. // Toggle visibility of the move details
  5174. const moveEntry = document.querySelector(`#movesContainer .move-entry:nth-child(${moveIndex + 1})`);
  5175. const moveDetails = moveEntry.querySelector('.move-details');
  5176.  
  5177. if (moveDetails.style.display === 'none') {
  5178. moveDetails.style.display = 'grid';
  5179. } else {
  5180. moveDetails.style.display = 'none';
  5181. }
  5182.  
  5183. updateMoveDisplay(moveIndex);
  5184. if (autoSaveEnabled) saveCharacterSheet();
  5185. }
  5186.  
  5187. function performMove(moveIndex) {
  5188. const moveEntry = document.querySelector(`#movesContainer .move-entry:nth-child(${moveIndex + 1})`);
  5189. const moveName = document.getElementById(`moveName_${moveIndex}`).value;
  5190. const moveType = document.getElementById(`moveType_${moveIndex}`).value;
  5191. const spCost = parseInt(document.getElementById(`moveSPCost_${moveIndex}`).value) || 0;
  5192.  
  5193. // Check if have enough SP
  5194. const currentSP = parseInt(document.getElementById('currentSP').value) || 0;
  5195. if (currentSP < spCost) {
  5196. showNotification(`Not enough SP to use ${moveName}!`, true);
  5197. return;
  5198. }
  5199.  
  5200. // Deduct SP
  5201. document.getElementById('currentSP').value = currentSP - spCost;
  5202.  
  5203. // Visual effect
  5204. moveEntry.classList.add('performing');
  5205. setTimeout(() => {
  5206. moveEntry.classList.remove('performing');
  5207. }, 1000);
  5208.  
  5209. // Effect based on move type
  5210. let resultMessage = '';
  5211.  
  5212. switch(moveType) {
  5213. case 'attack':
  5214. const baseDamage = parseInt(document.getElementById(`moveDamage_${moveIndex}`).value) || 0;
  5215. const attribute = document.getElementById(`moveAttribute_${moveIndex}`).value;
  5216. const statBonus = parseInt(document.getElementById(attribute).value) || 0;
  5217.  
  5218. // Random factor (0.8 to 1.2)
  5219. const variance = 0.8 + Math.random() * 0.4;
  5220. const damage = Math.floor((baseDamage + statBonus) * variance);
  5221.  
  5222. resultMessage = `${moveName} deals ${damage} damage! (Base: ${baseDamage}, ${attribute.toUpperCase()}: +${statBonus})`;
  5223. break;
  5224.  
  5225. case 'healing':
  5226. const healAmount = parseInt(document.getElementById(`moveHealing_${moveIndex}`).value) || 0;
  5227. const intBonus = parseInt(document.getElementById('int').value) || 0;
  5228.  
  5229. // Random factor (0.9 to 1.1)
  5230. const healVariance = 0.9 + Math.random() * 0.2;
  5231. const healing = Math.floor((healAmount + intBonus) * healVariance);
  5232.  
  5233. // Apply healing
  5234. const currentHP = parseInt(document.getElementById('currentHP').value) || 0;
  5235. const maxHP = parseInt(document.getElementById('hp-value').textContent) || 0;
  5236. const newHP = Math.min(currentHP + healing, maxHP);
  5237. document.getElementById('currentHP').value = newHP;
  5238.  
  5239. resultMessage = `${moveName} heals for ${healing} HP! (Current HP: ${newHP}/${maxHP})`;
  5240. break;
  5241.  
  5242. case 'buff':
  5243. const buffStat = document.getElementById(`moveBuffStat_${moveIndex}`).value;
  5244. const buffAmount = parseInt(document.getElementById(`moveBuffAmount_${moveIndex}`).value) || 0;
  5245. const duration = parseInt(document.getElementById(`moveBuffDuration_${moveIndex}`).value) || 1;
  5246.  
  5247. resultMessage = `${moveName} buffs ${buffStat.toUpperCase()} by +${buffAmount} for ${duration} rounds!`;
  5248. // In a real game, you'd track this buff and its duration
  5249. break;
  5250.  
  5251. case 'utility':
  5252. resultMessage = `${moveName} activated! (Utility effect)`;
  5253. break;
  5254. }
  5255.  
  5256. // Display result
  5257. document.getElementById('rollResult').textContent = resultMessage;
  5258.  
  5259. // Switch to character tab to see result
  5260. document.querySelector('.tab[data-tab="character-tab"]').click();
  5261.  
  5262. if (autoSaveEnabled) saveCharacterSheet();
  5263. }
  5264.  
  5265. function updateMoveSelector() {
  5266. const moveSelector = document.getElementById('calcMoveName');
  5267.  
  5268. // Clear current options except the first one
  5269. while (moveSelector.options.length > 1) {
  5270. moveSelector.remove(1);
  5271. }
  5272.  
  5273. // Add an option for each move
  5274. const moveElements = document.querySelectorAll('#movesContainer .move-entry');
  5275. moveElements.forEach((moveEl, index) => {
  5276. const nameInput = moveEl.querySelector(`input[id^="moveName_"]`);
  5277. const name = nameInput.value || `Move ${index + 1}`;
  5278.  
  5279. const option = document.createElement('option');
  5280. option.value = index;
  5281. option.textContent = name;
  5282. moveSelector.appendChild(option);
  5283. });
  5284. }
  5285.  
  5286. function filterMoves() {
  5287. const filterValue = document.getElementById('moveFilter').value;
  5288. const moveElements = document.querySelectorAll('#movesContainer .move-entry');
  5289.  
  5290. moveElements.forEach((moveEl, index) => {
  5291. const moveType = document.getElementById(`moveType_${index}`).value;
  5292.  
  5293. if (filterValue === 'all' || moveType === filterValue) {
  5294. moveEl.style.display = 'block';
  5295. } else {
  5296. moveEl.style.display = 'none';
  5297. }
  5298. });
  5299. }
  5300.  
  5301. function calculateMoveEffect() {
  5302. const moveIndex = document.getElementById('calcMoveName').value;
  5303. if (!moveIndex) {
  5304. document.getElementById('moveCalcResult').textContent = 'Please select a move first';
  5305. return;
  5306. }
  5307.  
  5308. const moveName = document.getElementById(`moveName_${moveIndex}`).value;
  5309. const moveType = document.getElementById(`moveType_${moveIndex}`).value;
  5310. const targetDefense = parseInt(document.getElementById('calcTarget').value) || 0;
  5311.  
  5312. let result = '';
  5313.  
  5314. if (moveType === 'attack') {
  5315. const baseDamage = parseInt(document.getElementById(`moveDamage_${moveIndex}`).value) || 0;
  5316. const attribute = document.getElementById(`moveAttribute_${moveIndex}`).value;
  5317. const statBonus = parseInt(document.getElementById(attribute).value) || 0;
  5318.  
  5319. // Calculate average damage with defense reduction
  5320. const minDamage = Math.max(Math.floor((baseDamage + statBonus) * 0.8) - targetDefense, 1);
  5321. const maxDamage = Math.max(Math.floor((baseDamage + statBonus) * 1.2) - targetDefense, 1);
  5322. const avgDamage = Math.floor((minDamage + maxDamage) / 2);
  5323.  
  5324. result = `${moveName} vs DEF ${targetDefense}:
  5325. Damage range: ${minDamage}-${maxDamage}
  5326. Average damage: ${avgDamage}
  5327. Attribute: ${attribute.toUpperCase()} (+${statBonus})`;
  5328. } else if (moveType === 'healing') {
  5329. const healAmount = parseInt(document.getElementById(`moveHealing_${moveIndex}`).value) || 0;
  5330. const intBonus = parseInt(document.getElementById('int').value) || 0;
  5331.  
  5332. const minHeal = Math.floor((healAmount + intBonus) * 0.9);
  5333. const maxHeal = Math.floor((healAmount + intBonus) * 1.1);
  5334. const avgHeal = Math.floor((minHeal + maxHeal) / 2);
  5335.  
  5336. result = `${moveName} healing:
  5337. Heal range: ${minHeal}-${maxHeal}
  5338. Average healing: ${avgHeal}
  5339. INT bonus: +${intBonus}`;
  5340. } else if (moveType === 'buff') {
  5341. const buffStat = document.getElementById(`moveBuffStat_${moveIndex}`).value;
  5342. const buffAmount = parseInt(document.getElementById(`moveBuffAmount_${moveIndex}`).value) || 0;
  5343. const duration = parseInt(document.getElementById(`moveBuffDuration_${moveIndex}`).value) || 1;
  5344.  
  5345. result = `${moveName} buff effect:
  5346. Stat: ${buffStat.toUpperCase()}
  5347. Bonus: +${buffAmount}
  5348. Duration: ${duration} rounds`;
  5349. } else {
  5350. result = `${moveName} (Utility)
  5351. See move description for details.`;
  5352. }
  5353.  
  5354. document.getElementById('moveCalcResult').textContent = result;
  5355. }
  5356.  
  5357. // Function to collect moves data for saving
  5358. function collectMoves() {
  5359. const moves = [];
  5360. const moveElements = document.querySelectorAll('#movesContainer .move-entry');
  5361.  
  5362. moveElements.forEach((el, index) => {
  5363. const moveType = document.getElementById(`moveType_${index}`)?.value;
  5364.  
  5365. const move = {
  5366. name: document.getElementById(`moveName_${index}`)?.value || '',
  5367. type: moveType || 'attack',
  5368. spCost: document.getElementById(`moveSPCost_${index}`)?.value || '0',
  5369. description: document.getElementById(`moveDescription_${index}`)?.value || ''
  5370. };
  5371.  
  5372. // Add type-specific properties
  5373. if (moveType === 'attack') {
  5374. move.damage = document.getElementById(`moveDamage_${index}`)?.value || '0';
  5375. move.attribute = document.getElementById(`moveAttribute_${index}`)?.value || 'str';
  5376. } else if (moveType === 'healing') {
  5377. move.healing = document.getElementById(`moveHealing_${index}`)?.value || '0';
  5378. } else if (moveType === 'buff') {
  5379. move.buffStat = document.getElementById(`moveBuffStat_${index}`)?.value || 'str';
  5380. move.buffAmount = document.getElementById(`moveBuffAmount_${index}`)?.value || '0';
  5381. move.duration = document.getElementById(`moveBuffDuration_${index}`)?.value || '1';
  5382. }
  5383.  
  5384. moves.push(move);
  5385. });
  5386.  
  5387. return moves;
  5388. }
  5389.  
  5390. // Add a notification function if it doesn't exist
  5391. function showNotification(message, isError = false) {
  5392. // If you already have a notification system, you can remove this function
  5393.  
  5394. // Create notification element if it doesn't exist
  5395. let notificationArea = document.getElementById('notificationArea');
  5396. if (!notificationArea) {
  5397. notificationArea = document.createElement('div');
  5398. notificationArea.id = 'notificationArea';
  5399. notificationArea.style.position = 'fixed';
  5400. notificationArea.style.bottom = '20px';
  5401. notificationArea.style.right = '20px';
  5402. notificationArea.style.zIndex = '1000';
  5403. document.body.appendChild(notificationArea);
  5404. }
  5405.  
  5406. const notification = document.createElement('div');
  5407. notification.className = 'notification ' + (isError ? 'error' : 'success');
  5408. notification.style.padding = '10px 15px';
  5409. notification.style.borderRadius = '5px';
  5410. notification.style.marginTop = '10px';
  5411. notification.style.background = isError ? 'rgba(255, 100, 100, 0.9)' : 'rgba(100, 255, 100, 0.9)';
  5412. notification.style.color = 'white';
  5413. notification.style.boxShadow = '0 2px 10px rgba(0, 0, 0, 0.2)';
  5414. notification.textContent = message;
  5415.  
  5416. notificationArea.appendChild(notification);
  5417.  
  5418. // Auto-remove after 3 seconds
  5419. setTimeout(() => {
  5420. notification.style.opacity = '0';
  5421. notification.style.transition = 'opacity 0.5s';
  5422. setTimeout(() => {
  5423. notification.remove();
  5424. }, 500);
  5425. }, 3000);
  5426. }
  5427. function addPartnerMove() {
  5428. const container = document.getElementById('partnerMovesContainer');
  5429. const moveIndex = container.children.length;
  5430.  
  5431. const move = document.createElement('div');
  5432. move.className = 'move-entry partner-move';
  5433. move.innerHTML = `
  5434. <div class="move-header">
  5435. <input type="text" id="partnerMoveName_${moveIndex}" placeholder="Move Name" class="move-name-input">
  5436. <div class="move-actions">
  5437. <button type="button" onclick="performPartnerMove(${moveIndex})" class="secondary">Use</button>
  5438. <button type="button" onclick="editPartnerMove(${moveIndex})" class="secondary">Edit</button>
  5439. <button type="button" onclick="removePartnerMove(this.parentNode.parentNode.parentNode)" class="remove-button">Remove</button>
  5440. </div>
  5441. </div>
  5442.  
  5443. <div class="move-details">
  5444. <div class="form-group">
  5445. <label for="partnerMoveType_${moveIndex}">Type:</label>
  5446. <select id="partnerMoveType_${moveIndex}" onchange="updatePartnerMoveFields(${moveIndex})">
  5447. <option value="attack">Attack</option>
  5448. <option value="healing">Healing</option>
  5449. <option value="buff">Buff/Debuff</option>
  5450. <option value="utility">Utility</option>
  5451. </select>
  5452. </div>
  5453.  
  5454. <div class="form-group">
  5455. <label for="partnerMoveSPCost_${moveIndex}">SP Cost:</label>
  5456. <input type="number" id="partnerMoveSPCost_${moveIndex}" min="0" value="5">
  5457. </div>
  5458.  
  5459. <div class="form-group move-attack-field">
  5460. <label for="partnerMoveDamage_${moveIndex}">Base Damage:</label>
  5461. <input type="number" id="partnerMoveDamage_${moveIndex}" min="0" value="10">
  5462. </div>
  5463.  
  5464. <div class="form-group move-attack-field">
  5465. <label for="partnerMoveAttribute_${moveIndex}">Attribute:</label>
  5466. <select id="partnerMoveAttribute_${moveIndex}">
  5467. <option value="str">STR</option>
  5468. <option value="int">INT</option>
  5469. <option value="agi">AGI</option>
  5470. <option value="wil">WIL</option>
  5471. </select>
  5472. </div>
  5473.  
  5474. <div class="form-group move-healing-field" style="display: none;">
  5475. <label for="partnerMoveHealing_${moveIndex}">Healing Amount:</label>
  5476. <input type="number" id="partnerMoveHealing_${moveIndex}" min="0" value="10">
  5477. </div>
  5478.  
  5479. <div class="form-group move-buff-field" style="display: none;">
  5480. <label for="partnerMoveBuffStat_${moveIndex}">Buff Stat:</label>
  5481. <select id="partnerMoveBuffStat_${moveIndex}">
  5482. <option value="str">STR</option>
  5483. <option value="def">DEF</option>
  5484. <option value="int">INT</option>
  5485. <option value="agi">AGI</option>
  5486. <option value="wil">WIL</option>
  5487. </select>
  5488. </div>
  5489.  
  5490. <div class="form-group move-buff-field" style="display: none;">
  5491. <label for="partnerMoveBuffAmount_${moveIndex}">Buff Amount:</label>
  5492. <input type="number" id="partnerMoveBuffAmount_${moveIndex}" value="2">
  5493. </div>
  5494.  
  5495. <div class="form-group move-buff-field" style="display: none;">
  5496. <label for="partnerMoveBuffDuration_${moveIndex}">Duration (rounds):</label>
  5497. <input type="number" id="partnerMoveBuffDuration_${moveIndex}" min="1" value="3">
  5498. </div>
  5499.  
  5500. <div class="form-group move-description">
  5501. <label for="partnerMoveDescription_${moveIndex}">Description:</label>
  5502. <textarea id="partnerMoveDescription_${moveIndex}" rows="3" placeholder="Describe what the move does..."></textarea>
  5503. </div>
  5504. </div>
  5505.  
  5506. <div class="move-display">
  5507. <div id="partnerMoveDisplay_${moveIndex}"></div>
  5508. </div>
  5509. `;
  5510.  
  5511. container.appendChild(move);
  5512. updatePartnerMoveFields(moveIndex);
  5513. updatePartnerMoveSelector();
  5514.  
  5515. // Auto-save when adding a new move
  5516. if (autoSaveEnabled) saveCharacterSheet();
  5517. }
  5518.  
  5519. function updatePartnerMoveFields(moveIndex) {
  5520. const moveType = document.getElementById(`partnerMoveType_${moveIndex}`).value;
  5521.  
  5522. // Hide all type-specific fields
  5523. document.querySelectorAll(`#partnerMovesContainer .move-entry:nth-child(${moveIndex + 1}) .move-attack-field`).forEach(el => {
  5524. el.style.display = 'none';
  5525. });
  5526.  
  5527. document.querySelectorAll(`#partnerMovesContainer .move-entry:nth-child(${moveIndex + 1}) .move-healing-field`).forEach(el => {
  5528. el.style.display = 'none';
  5529. });
  5530.  
  5531. document.querySelectorAll(`#partnerMovesContainer .move-entry:nth-child(${moveIndex + 1}) .move-buff-field`).forEach(el => {
  5532. el.style.display = 'none';
  5533. });
  5534.  
  5535. // Show relevant fields based on move type
  5536. switch(moveType) {
  5537. case 'attack':
  5538. document.querySelectorAll(`#partnerMovesContainer .move-entry:nth-child(${moveIndex + 1}) .move-attack-field`).forEach(el => {
  5539. el.style.display = 'block';
  5540. });
  5541. break;
  5542. case 'healing':
  5543. document.querySelectorAll(`#partnerMovesContainer .move-entry:nth-child(${moveIndex + 1}) .move-healing-field`).forEach(el => {
  5544. el.style.display = 'block';
  5545. });
  5546. break;
  5547. case 'buff':
  5548. document.querySelectorAll(`#partnerMovesContainer .move-entry:nth-child(${moveIndex + 1}) .move-buff-field`).forEach(el => {
  5549. el.style.display = 'block';
  5550. });
  5551. break;
  5552. }
  5553.  
  5554. updatePartnerMoveDisplay(moveIndex);
  5555. }
  5556.  
  5557. function updatePartnerMoveDisplay(moveIndex) {
  5558. const moveName = document.getElementById(`partnerMoveName_${moveIndex}`).value || 'Unnamed Move';
  5559. const moveType = document.getElementById(`partnerMoveType_${moveIndex}`).value;
  5560. const spCost = document.getElementById(`partnerMoveSPCost_${moveIndex}`).value;
  5561.  
  5562. let displayHTML = `<div class="move-title">${moveName}`;
  5563. displayHTML += `<span class="move-type ${moveType}">${moveType.charAt(0).toUpperCase() + moveType.slice(1)}</span>`;
  5564. displayHTML += `<span class="move-sp-cost">${spCost} SP</span></div>`;
  5565.  
  5566. document.getElementById(`partnerMoveDisplay_${moveIndex}`).innerHTML = displayHTML;
  5567. }
  5568.  
  5569. function removePartnerMove(moveElement) {
  5570. moveElement.remove();
  5571. updatePartnerMoveSelector();
  5572. if (autoSaveEnabled) saveCharacterSheet();
  5573. }
  5574.  
  5575. function editPartnerMove(moveIndex) {
  5576. // Toggle visibility of the move details
  5577. const moveEntry = document.querySelector(`#partnerMovesContainer .move-entry:nth-child(${moveIndex + 1})`);
  5578. const moveDetails = moveEntry.querySelector('.move-details');
  5579.  
  5580. if (moveDetails.style.display === 'none') {
  5581. moveDetails.style.display = 'grid';
  5582. } else {
  5583. moveDetails.style.display = 'none';
  5584. }
  5585.  
  5586. updatePartnerMoveDisplay(moveIndex);
  5587. if (autoSaveEnabled) saveCharacterSheet();
  5588. }
  5589.  
  5590. function performPartnerMove(moveIndex) {
  5591. const moveEntry = document.querySelector(`#partnerMovesContainer .move-entry:nth-child(${moveIndex + 1})`);
  5592. const moveName = document.getElementById(`partnerMoveName_${moveIndex}`).value;
  5593. const moveType = document.getElementById(`partnerMoveType_${moveIndex}`).value;
  5594. const spCost = parseInt(document.getElementById(`partnerMoveSPCost_${moveIndex}`).value) || 0;
  5595.  
  5596. // Check if have enough SP
  5597. const currentSP = parseInt(document.getElementById('partnerCurrentSP').value) || 0;
  5598. if (currentSP < spCost) {
  5599. showNotification(`Not enough SP for your partner to use ${moveName}!`, true);
  5600. return;
  5601. }
  5602.  
  5603. // Deduct SP
  5604. document.getElementById('partnerCurrentSP').value = currentSP - spCost;
  5605.  
  5606. // Visual effect
  5607. moveEntry.classList.add('performing');
  5608. setTimeout(() => {
  5609. moveEntry.classList.remove('performing');
  5610. }, 1000);
  5611.  
  5612. // Effect based on move type
  5613. let resultMessage = '';
  5614.  
  5615. switch(moveType) {
  5616. case 'attack':
  5617. const baseDamage = parseInt(document.getElementById(`partnerMoveDamage_${moveIndex}`).value) || 0;
  5618. const attribute = document.getElementById(`partnerMoveAttribute_${moveIndex}`).value;
  5619. const statBonus = parseInt(document.getElementById(`partner_${attribute}`).value) || 0;
  5620.  
  5621. // Random factor (0.8 to 1.2)
  5622. const variance = 0.8 + Math.random() * 0.4;
  5623. const damage = Math.floor((baseDamage + statBonus) * variance);
  5624.  
  5625. resultMessage = `Partner's ${moveName} deals ${damage} damage! (Base: ${baseDamage}, ${attribute.toUpperCase()}: +${statBonus})`;
  5626. break;
  5627.  
  5628. case 'healing':
  5629. const healAmount = parseInt(document.getElementById(`partnerMoveHealing_${moveIndex}`).value) || 0;
  5630. const intBonus = parseInt(document.getElementById('partner_int').value) || 0;
  5631.  
  5632. // Random factor (0.9 to 1.1)
  5633. const healVariance = 0.9 + Math.random() * 0.2;
  5634. const healing = Math.floor((healAmount + intBonus) * healVariance);
  5635.  
  5636. // Apply healing - check whether we're healing the partner or the character
  5637. const healTarget = document.querySelector(`input[name="healTarget_${moveIndex}"]:checked`)?.value || 'partner';
  5638.  
  5639. if (healTarget === 'partner') {
  5640. const currentHP = parseInt(document.getElementById('partnerCurrentHP').value) || 0;
  5641. const maxHP = parseInt(document.getElementById('partner-hp-value').textContent) || 0;
  5642. const newHP = Math.min(currentHP + healing, maxHP);
  5643. document.getElementById('partnerCurrentHP').value = newHP;
  5644.  
  5645. resultMessage = `Partner's ${moveName} heals itself for ${healing} HP! (Current HP: ${newHP}/${maxHP})`;
  5646. } else {
  5647. const currentHP = parseInt(document.getElementById('currentHP').value) || 0;
  5648. const maxHP = parseInt(document.getElementById('hp-value').textContent) || 0;
  5649. const newHP = Math.min(currentHP + healing, maxHP);
  5650. document.getElementById('currentHP').value = newHP;
  5651.  
  5652. resultMessage = `Partner's ${moveName} heals you for ${healing} HP! (Your Current HP: ${newHP}/${maxHP})`;
  5653. }
  5654. break;
  5655.  
  5656. case 'buff':
  5657. const buffStat = document.getElementById(`partnerMoveBuffStat_${moveIndex}`).value;
  5658. const buffAmount = parseInt(document.getElementById(`partnerMoveBuffAmount_${moveIndex}`).value) || 0;
  5659. const duration = parseInt(document.getElementById(`partnerMoveBuffDuration_${moveIndex}`).value) || 1;
  5660.  
  5661. resultMessage = `Partner's ${moveName} buffs ${buffStat.toUpperCase()} by +${buffAmount} for ${duration} rounds!`;
  5662. break;
  5663.  
  5664. case 'utility':
  5665. resultMessage = `Partner's ${moveName} activated! (Utility effect)`;
  5666. break;
  5667. }
  5668.  
  5669. // Display result
  5670. document.getElementById('rollResult').textContent = resultMessage;
  5671.  
  5672. // Switch to partner tab to see result
  5673. document.querySelector('.tab[data-tab="partner-tab"]').click();
  5674.  
  5675. if (autoSaveEnabled) saveCharacterSheet();
  5676. }
  5677.  
  5678. function updatePartnerMoveSelector() {
  5679. const moveSelector = document.getElementById('calcPartnerMoveName');
  5680.  
  5681. // Clear current options except the first one
  5682. while (moveSelector.options.length > 1) {
  5683. moveSelector.remove(1);
  5684. }
  5685.  
  5686. // Add an option for each move
  5687. const moveElements = document.querySelectorAll('#partnerMovesContainer .move-entry');
  5688. moveElements.forEach((moveEl, index) => {
  5689. const nameInput = moveEl.querySelector(`input[id^="partnerMoveName_"]`);
  5690. const name = nameInput.value || `Move ${index + 1}`;
  5691.  
  5692. const option = document.createElement('option');
  5693. option.value = index;
  5694. option.textContent = name;
  5695. moveSelector.appendChild(option);
  5696. });
  5697. }
  5698.  
  5699. function filterPartnerMoves() {
  5700. const filterValue = document.getElementById('partnerMoveFilter').value;
  5701. const moveElements = document.querySelectorAll('#partnerMovesContainer .move-entry');
  5702.  
  5703. moveElements.forEach((moveEl, index) => {
  5704. const moveType = document.getElementById(`partnerMoveType_${index}`).value;
  5705.  
  5706. if (filterValue === 'all' || moveType === filterValue) {
  5707. moveEl.style.display = 'block';
  5708. } else {
  5709. moveEl.style.display = 'none';
  5710. }
  5711. });
  5712. }
  5713.  
  5714. function calculatePartnerMoveEffect() {
  5715. const moveIndex = document.getElementById('calcPartnerMoveName').value;
  5716. if (!moveIndex) {
  5717. document.getElementById('partnerMoveCalcResult').textContent = 'Please select a move first';
  5718. return;
  5719. }
  5720.  
  5721. const moveName = document.getElementById(`partnerMoveName_${moveIndex}`).value;
  5722. const moveType = document.getElementById(`partnerMoveType_${moveIndex}`).value;
  5723. const targetDefense = parseInt(document.getElementById('calcPartnerTarget').value) || 0;
  5724.  
  5725. let result = '';
  5726.  
  5727. if (moveType === 'attack') {
  5728. const baseDamage = parseInt(document.getElementById(`partnerMoveDamage_${moveIndex}`).value) || 0;
  5729. const attribute = document.getElementById(`partnerMoveAttribute_${moveIndex}`).value;
  5730. const statBonus = parseInt(document.getElementById(`partner_${attribute}`).value) || 0;
  5731.  
  5732. // Calculate average damage with defense reduction
  5733. const minDamage = Math.max(Math.floor((baseDamage + statBonus) * 0.8) - targetDefense, 1);
  5734. const maxDamage = Math.max(Math.floor((baseDamage + statBonus) * 1.2) - targetDefense, 1);
  5735. const avgDamage = Math.floor((minDamage + maxDamage) / 2);
  5736.  
  5737. result = `${moveName} vs DEF ${targetDefense}:
  5738. Damage range: ${minDamage}-${maxDamage}
  5739. Average damage: ${avgDamage}
  5740. Attribute: ${attribute.toUpperCase()} (+${statBonus})`;
  5741. } else if (moveType === 'healing') {
  5742. const healAmount = parseInt(document.getElementById(`partnerMoveHealing_${moveIndex}`).value) || 0;
  5743. const intBonus = parseInt(document.getElementById('partner_int').value) || 0;
  5744.  
  5745. const minHeal = Math.floor((healAmount + intBonus) * 0.9);
  5746. const maxHeal = Math.floor((healAmount + intBonus) * 1.1);
  5747. const avgHeal = Math.floor((minHeal + maxHeal) / 2);
  5748.  
  5749. result = `${moveName} healing:
  5750. Heal range: ${minHeal}-${maxHeal}
  5751. Average healing: ${avgHeal}
  5752. INT bonus: +${intBonus}`;
  5753. } else if (moveType === 'buff') {
  5754. const buffStat = document.getElementById(`partnerMoveBuffStat_${moveIndex}`).value;
  5755. const buffAmount = parseInt(document.getElementById(`partnerMoveBuffAmount_${moveIndex}`).value) || 0;
  5756. const duration = parseInt(document.getElementById(`partnerMoveBuffDuration_${moveIndex}`).value) || 1;
  5757.  
  5758. result = `${moveName} buff effect:
  5759. Stat: ${buffStat.toUpperCase()}
  5760. Bonus: +${buffAmount}
  5761. Duration: ${duration} rounds`;
  5762. } else {
  5763. result = `${moveName} (Utility)
  5764. See move description for details.`;
  5765. }
  5766.  
  5767. document.getElementById('partnerMoveCalcResult').textContent = result;
  5768. }
  5769.  
  5770. // Function to collect partner moves data for saving
  5771. function collectPartnerMoves() {
  5772. const moves = [];
  5773. const moveElements = document.querySelectorAll('#partnerMovesContainer .move-entry');
  5774.  
  5775. moveElements.forEach((el, index) => {
  5776. const moveType = document.getElementById(`partnerMoveType_${index}`)?.value;
  5777.  
  5778. const move = {
  5779. name: document.getElementById(`partnerMoveName_${index}`)?.value || '',
  5780. type: moveType || 'attack',
  5781. spCost: document.getElementById(`partnerMoveSPCost_${index}`)?.value || '0',
  5782. description: document.getElementById(`partnerMoveDescription_${index}`)?.value || ''
  5783. };
  5784.  
  5785. // Add type-specific properties
  5786. if (moveType === 'attack') {
  5787. move.damage = document.getElementById(`partnerMoveDamage_${index}`)?.value || '0';
  5788. move.attribute = document.getElementById(`partnerMoveAttribute_${index}`)?.value || 'str';
  5789. } else if (moveType === 'healing') {
  5790. move.healing = document.getElementById(`partnerMoveHealing_${index}`)?.value || '0';
  5791. } else if (moveType === 'buff') {
  5792. move.buffStat = document.getElementById(`partnerMoveBuffStat_${index}`)?.value || 'str';
  5793. move.buffAmount = document.getElementById(`partnerMoveBuffAmount_${index}`)?.value || '0';
  5794. move.duration = document.getElementById(`partnerMoveBuffDuration_${index}`)?.value || '1';
  5795. }
  5796.  
  5797. moves.push(move);
  5798. });
  5799.  
  5800. return moves;
  5801. }
  5802. </script>
  5803. </body>
  5804. </html>
Add Comment
Please, Sign In to add comment