[{"data":1,"prerenderedAt":1049},["ShallowReactive",2],{"doc-global_essentials\u002Fcharacters\u002Fcharacters_computed":3},{"id":4,"title":5,"body":6,"description":1039,"extension":1040,"meta":1041,"navigation":660,"path":1045,"seo":1046,"stem":1047,"__hash__":1048},"docs\u002Fdocs\u002Fglobal_essentials\u002Fcharacters\u002Fcharacters_computed.md","Computed Stats",{"type":7,"value":8,"toc":1031},"minimark",[9,13,23,26,29,32,38,54,61,63,68,71,103,105,109,116,121,160,165,197,200,202,206,209,215,316,322,337,345,347,351,356,359,443,448,451,551,556,559,760,765,768,883,885,889,894,964,969,978,984,990,992,996,1006,1012,1018,1027],[10,11,5],"h1",{"id":12},"computed-stats",[14,15,16,17,22],"p",{},"This guide covers computed stats - a scripting feature for dynamic stat calculations. If you're new to characters in Dryad Engine, start with ",[18,19,21],"a",{"href":20},"\u002Fdocs\u002Fglobal_essentials\u002Fcharacters\u002Fcharacters_overview","Overview"," first.",[24,25],"hr",{},[14,27,28],{},"In the basic character system, stats simply add up. If your template gives +100 Health and an item gives +20 Health, you have 120 Health. Simple addition.",[14,30,31],{},"But what if you need stats that depend on something else entirely?",[14,33,34],{},[35,36,37],"strong",{},"Examples:",[39,40,41,45,48,51],"ul",{},[42,43,44],"li",{},"Endurance stat gives +10 Stamina per point",[42,46,47],{},"A global \"difficulty\" property affects all characters' defense",[42,49,50],{},"Having 3+ equipped items from the same set gives a bonus",[42,52,53],{},"Party size affects individual character stats",[14,55,56,57,60],{},"This is what computed stats are for - stats calculated dynamically from ",[35,58,59],{},"any game data",".",[24,62],{},[64,65,67],"h3",{"id":66},"why-use-computed-stats","Why Use Computed Stats?",[14,69,70],{},"Computed stats let you create relationships that simple addition can't handle:",[39,72,73,79,85,91,97],{},[42,74,75,78],{},[35,76,77],{},"Derived stats"," - Endurance gives Stamina, Intelligence gives Mana",[42,80,81,84],{},[35,82,83],{},"Global modifiers"," - A \"world danger\" property affects all combat stats",[42,86,87,90],{},[35,88,89],{},"Set bonuses"," - Equipping multiple items from a set grants extra stats",[42,92,93,96],{},[35,94,95],{},"Conditional bonuses"," - Stats that depend on character state, attributes, or traits",[42,98,99,102],{},[35,100,101],{},"Cross-character effects"," - Party composition affecting individual stats",[24,104],{},[64,106,108],{"id":107},"what-you-can-access","What You Can Access",[14,110,111,112,115],{},"Your computed stat function receives the character, but you can access ",[35,113,114],{},"anything in the game",":",[14,117,118],{},[35,119,120],{},"From the Character:",[39,122,123,130,136,142,148,154],{},[42,124,125,129],{},[126,127,128],"code",{},"character.getStat(name)"," - other stats",[42,131,132,135],{},[126,133,134],{},"character.getTrait(key)"," - character traits",[42,137,138,141],{},[126,139,140],{},"character.getAttribute(key)"," - character attributes",[42,143,144,147],{},[126,145,146],{},"character.getEquippedItems()"," - equipped items",[42,149,150,153],{},[126,151,152],{},"character.learnedSkills"," - learned skills",[42,155,156,159],{},[126,157,158],{},"character.statuses"," - active status effects",[14,161,162],{},[35,163,164],{},"From game:",[39,166,167,173,179,185,191],{},[42,168,169,172],{},[126,170,171],{},"game.getProperty(id)"," - global properties",[42,174,175,178],{},[126,176,177],{},"game.getState(key)"," - global game state",[42,180,181,184],{},[126,182,183],{},"game.getStore(id)"," - custom stores",[42,186,187,190],{},[126,188,189],{},"game.getAllCharacters()"," - all characters",[42,192,193,196],{},[126,194,195],{},"game.getParty()"," - party members",[14,198,199],{},"All game data is reactive - when the underlying data changes, computed stats automatically recalculate.",[24,201],{},[64,203,205],{"id":204},"how-they-work","How They Work",[14,207,208],{},"Computed stats have two parts:",[14,210,211,214],{},[35,212,213],{},"1. A stat computer function"," (defined in your game's script)",[216,217,222],"pre",{"className":218,"code":219,"language":220,"meta":221,"style":221},"language-typescript shiki shiki-themes github-light github-dark","game.registerStatComputer(\"myComputer\", (character) => {\n  \u002F\u002F Access any game data here\n  \u002F\u002F Return stat bonuses as { statName: amount }\n  return {\n    health: 50,\n    stamina: 20\n  };\n});\n","typescript","",[126,223,224,261,268,274,282,295,304,310],{"__ignoreMap":221},[225,226,229,233,237,240,244,247,251,254,258],"span",{"class":227,"line":228},"line",1,[225,230,232],{"class":231},"sVt8B","game.",[225,234,236],{"class":235},"sScJk","registerStatComputer",[225,238,239],{"class":231},"(",[225,241,243],{"class":242},"sZZnC","\"myComputer\"",[225,245,246],{"class":231},", (",[225,248,250],{"class":249},"s4XuR","character",[225,252,253],{"class":231},") ",[225,255,257],{"class":256},"szBVR","=>",[225,259,260],{"class":231}," {\n",[225,262,264],{"class":227,"line":263},2,[225,265,267],{"class":266},"sJ8bj","  \u002F\u002F Access any game data here\n",[225,269,271],{"class":227,"line":270},3,[225,272,273],{"class":266},"  \u002F\u002F Return stat bonuses as { statName: amount }\n",[225,275,277,280],{"class":227,"line":276},4,[225,278,279],{"class":256},"  return",[225,281,260],{"class":231},[225,283,285,288,292],{"class":227,"line":284},5,[225,286,287],{"class":231},"    health: ",[225,289,291],{"class":290},"sj4cs","50",[225,293,294],{"class":231},",\n",[225,296,298,301],{"class":227,"line":297},6,[225,299,300],{"class":231},"    stamina: ",[225,302,303],{"class":290},"20\n",[225,305,307],{"class":227,"line":306},7,[225,308,309],{"class":231},"  };\n",[225,311,313],{"class":227,"line":312},8,[225,314,315],{"class":231},"});\n",[14,317,318,321],{},[35,319,320],{},"2. A reference in the template or status"," (in the editor)",[14,323,324,325,328,329,332,333,336],{},"In the ",[35,326,327],{},"Character Templates"," or ",[35,330,331],{},"Character Statuses"," form, add the computer's name to the ",[126,334,335],{},"computed_stats"," field:",[216,338,343],{"className":339,"code":341,"language":342},[340],"language-text","computed_stats: [\"myComputer\"]\n","text",[126,344,341],{"__ignoreMap":221},[24,346],{},[64,348,350],{"id":349},"examples","Examples",[14,352,353],{},[35,354,355],{},"Example 1: Stat to Stat",[14,357,358],{},"Every point of Endurance gives +10 Stamina:",[216,360,362],{"className":218,"code":361,"language":220,"meta":221,"style":221},"game.registerStatComputer(\"enduranceToStamina\", (character) => {\n  const endurance = character.getStat(\"endurance\") || 0;\n  return {\n    stamina: endurance * 10\n  };\n});\n",[126,363,364,385,418,424,435,439],{"__ignoreMap":221},[225,365,366,368,370,372,375,377,379,381,383],{"class":227,"line":228},[225,367,232],{"class":231},[225,369,236],{"class":235},[225,371,239],{"class":231},[225,373,374],{"class":242},"\"enduranceToStamina\"",[225,376,246],{"class":231},[225,378,250],{"class":249},[225,380,253],{"class":231},[225,382,257],{"class":256},[225,384,260],{"class":231},[225,386,387,390,393,396,399,402,404,407,409,412,415],{"class":227,"line":263},[225,388,389],{"class":256},"  const",[225,391,392],{"class":290}," endurance",[225,394,395],{"class":256}," =",[225,397,398],{"class":231}," character.",[225,400,401],{"class":235},"getStat",[225,403,239],{"class":231},[225,405,406],{"class":242},"\"endurance\"",[225,408,253],{"class":231},[225,410,411],{"class":256},"||",[225,413,414],{"class":290}," 0",[225,416,417],{"class":231},";\n",[225,419,420,422],{"class":227,"line":270},[225,421,279],{"class":256},[225,423,260],{"class":231},[225,425,426,429,432],{"class":227,"line":276},[225,427,428],{"class":231},"    stamina: endurance ",[225,430,431],{"class":256},"*",[225,433,434],{"class":290}," 10\n",[225,436,437],{"class":227,"line":284},[225,438,309],{"class":231},[225,440,441],{"class":227,"line":297},[225,442,315],{"class":231},[14,444,445],{},[35,446,447],{},"Example 2: Global Property to Stat",[14,449,450],{},"A global \"difficulty\" property affects all characters' defense:",[216,452,454],{"className":218,"code":453,"language":220,"meta":221,"style":221},"game.registerStatComputer(\"difficultyPenalty\", (character) => {\n  const difficulty = Number(game.getProperty(\"difficulty\")?.currentValue) || 1;\n  return {\n    defense: -10 * (difficulty - 1)  \u002F\u002F Higher difficulty = less defense\n  };\n});\n",[126,455,456,477,510,516,543,547],{"__ignoreMap":221},[225,457,458,460,462,464,467,469,471,473,475],{"class":227,"line":228},[225,459,232],{"class":231},[225,461,236],{"class":235},[225,463,239],{"class":231},[225,465,466],{"class":242},"\"difficultyPenalty\"",[225,468,246],{"class":231},[225,470,250],{"class":249},[225,472,253],{"class":231},[225,474,257],{"class":256},[225,476,260],{"class":231},[225,478,479,481,484,486,489,492,495,497,500,503,505,508],{"class":227,"line":263},[225,480,389],{"class":256},[225,482,483],{"class":290}," difficulty",[225,485,395],{"class":256},[225,487,488],{"class":235}," Number",[225,490,491],{"class":231},"(game.",[225,493,494],{"class":235},"getProperty",[225,496,239],{"class":231},[225,498,499],{"class":242},"\"difficulty\"",[225,501,502],{"class":231},")?.currentValue) ",[225,504,411],{"class":256},[225,506,507],{"class":290}," 1",[225,509,417],{"class":231},[225,511,512,514],{"class":227,"line":270},[225,513,279],{"class":256},[225,515,260],{"class":231},[225,517,518,521,524,527,530,533,535,537,540],{"class":227,"line":276},[225,519,520],{"class":231},"    defense: ",[225,522,523],{"class":256},"-",[225,525,526],{"class":290},"10",[225,528,529],{"class":256}," *",[225,531,532],{"class":231}," (difficulty ",[225,534,523],{"class":256},[225,536,507],{"class":290},[225,538,539],{"class":231},")  ",[225,541,542],{"class":266},"\u002F\u002F Higher difficulty = less defense\n",[225,544,545],{"class":227,"line":284},[225,546,309],{"class":231},[225,548,549],{"class":227,"line":297},[225,550,315],{"class":231},[14,552,553],{},[35,554,555],{},"Example 3: Equipped Items (Set Bonus)",[14,557,558],{},"Count equipped items with a specific trait for a set bonus:",[216,560,562],{"className":218,"code":561,"language":220,"meta":221,"style":221},"game.registerStatComputer(\"armorSetBonus\", (character) => {\n  const equipped = character.getEquippedItems();\n  const setPieces = equipped.filter(item =>\n    item.getTrait(\"item_set\") === \"dragon_armor\"\n  ).length;\n\n  \u002F\u002F 3+ pieces = full bonus\n  if (setPieces >= 3) {\n    return { defense: 50, fire_resistance: 30 };\n  }\n  \u002F\u002F 2 pieces = partial bonus\n  if (setPieces >= 2) {\n    return { defense: 20 };\n  }\n  return {};\n});\n",[126,563,564,585,602,625,646,656,662,667,684,704,710,716,730,742,747,755],{"__ignoreMap":221},[225,565,566,568,570,572,575,577,579,581,583],{"class":227,"line":228},[225,567,232],{"class":231},[225,569,236],{"class":235},[225,571,239],{"class":231},[225,573,574],{"class":242},"\"armorSetBonus\"",[225,576,246],{"class":231},[225,578,250],{"class":249},[225,580,253],{"class":231},[225,582,257],{"class":256},[225,584,260],{"class":231},[225,586,587,589,592,594,596,599],{"class":227,"line":263},[225,588,389],{"class":256},[225,590,591],{"class":290}," equipped",[225,593,395],{"class":256},[225,595,398],{"class":231},[225,597,598],{"class":235},"getEquippedItems",[225,600,601],{"class":231},"();\n",[225,603,604,606,609,611,614,617,619,622],{"class":227,"line":270},[225,605,389],{"class":256},[225,607,608],{"class":290}," setPieces",[225,610,395],{"class":256},[225,612,613],{"class":231}," equipped.",[225,615,616],{"class":235},"filter",[225,618,239],{"class":231},[225,620,621],{"class":249},"item",[225,623,624],{"class":256}," =>\n",[225,626,627,630,633,635,638,640,643],{"class":227,"line":276},[225,628,629],{"class":231},"    item.",[225,631,632],{"class":235},"getTrait",[225,634,239],{"class":231},[225,636,637],{"class":242},"\"item_set\"",[225,639,253],{"class":231},[225,641,642],{"class":256},"===",[225,644,645],{"class":242}," \"dragon_armor\"\n",[225,647,648,651,654],{"class":227,"line":284},[225,649,650],{"class":231},"  ).",[225,652,653],{"class":290},"length",[225,655,417],{"class":231},[225,657,658],{"class":227,"line":297},[225,659,661],{"emptyLinePlaceholder":660},true,"\n",[225,663,664],{"class":227,"line":306},[225,665,666],{"class":266},"  \u002F\u002F 3+ pieces = full bonus\n",[225,668,669,672,675,678,681],{"class":227,"line":312},[225,670,671],{"class":256},"  if",[225,673,674],{"class":231}," (setPieces ",[225,676,677],{"class":256},">=",[225,679,680],{"class":290}," 3",[225,682,683],{"class":231},") {\n",[225,685,687,690,693,695,698,701],{"class":227,"line":686},9,[225,688,689],{"class":256},"    return",[225,691,692],{"class":231}," { defense: ",[225,694,291],{"class":290},[225,696,697],{"class":231},", fire_resistance: ",[225,699,700],{"class":290},"30",[225,702,703],{"class":231}," };\n",[225,705,707],{"class":227,"line":706},10,[225,708,709],{"class":231},"  }\n",[225,711,713],{"class":227,"line":712},11,[225,714,715],{"class":266},"  \u002F\u002F 2 pieces = partial bonus\n",[225,717,719,721,723,725,728],{"class":227,"line":718},12,[225,720,671],{"class":256},[225,722,674],{"class":231},[225,724,677],{"class":256},[225,726,727],{"class":290}," 2",[225,729,683],{"class":231},[225,731,733,735,737,740],{"class":227,"line":732},13,[225,734,689],{"class":256},[225,736,692],{"class":231},[225,738,739],{"class":290},"20",[225,741,703],{"class":231},[225,743,745],{"class":227,"line":744},14,[225,746,709],{"class":231},[225,748,750,752],{"class":227,"line":749},15,[225,751,279],{"class":256},[225,753,754],{"class":231}," {};\n",[225,756,758],{"class":227,"line":757},16,[225,759,315],{"class":231},[14,761,762],{},[35,763,764],{},"Example 4: Multiple Sources Combined",[14,766,767],{},"Combine character stats with global properties:",[216,769,771],{"className":218,"code":770,"language":220,"meta":221,"style":221},"game.registerStatComputer(\"combatPower\", (character) => {\n  const strength = character.getStat(\"strength\") || 0;\n  const worldBonus = Number(game.getProperty(\"combat_bonus\")?.currentValue) || 0;\n\n  return {\n    attack: (strength * 2) + worldBonus\n  };\n});\n",[126,772,773,794,820,848,852,858,875,879],{"__ignoreMap":221},[225,774,775,777,779,781,784,786,788,790,792],{"class":227,"line":228},[225,776,232],{"class":231},[225,778,236],{"class":235},[225,780,239],{"class":231},[225,782,783],{"class":242},"\"combatPower\"",[225,785,246],{"class":231},[225,787,250],{"class":249},[225,789,253],{"class":231},[225,791,257],{"class":256},[225,793,260],{"class":231},[225,795,796,798,801,803,805,807,809,812,814,816,818],{"class":227,"line":263},[225,797,389],{"class":256},[225,799,800],{"class":290}," strength",[225,802,395],{"class":256},[225,804,398],{"class":231},[225,806,401],{"class":235},[225,808,239],{"class":231},[225,810,811],{"class":242},"\"strength\"",[225,813,253],{"class":231},[225,815,411],{"class":256},[225,817,414],{"class":290},[225,819,417],{"class":231},[225,821,822,824,827,829,831,833,835,837,840,842,844,846],{"class":227,"line":270},[225,823,389],{"class":256},[225,825,826],{"class":290}," worldBonus",[225,828,395],{"class":256},[225,830,488],{"class":235},[225,832,491],{"class":231},[225,834,494],{"class":235},[225,836,239],{"class":231},[225,838,839],{"class":242},"\"combat_bonus\"",[225,841,502],{"class":231},[225,843,411],{"class":256},[225,845,414],{"class":290},[225,847,417],{"class":231},[225,849,850],{"class":227,"line":276},[225,851,661],{"emptyLinePlaceholder":660},[225,853,854,856],{"class":227,"line":284},[225,855,279],{"class":256},[225,857,260],{"class":231},[225,859,860,863,865,867,869,872],{"class":227,"line":297},[225,861,862],{"class":231},"    attack: (strength ",[225,864,431],{"class":256},[225,866,727],{"class":290},[225,868,253],{"class":231},[225,870,871],{"class":256},"+",[225,873,874],{"class":231}," worldBonus\n",[225,876,877],{"class":227,"line":306},[225,878,309],{"class":231},[225,880,881],{"class":227,"line":312},[225,882,315],{"class":231},[24,884],{},[64,886,888],{"id":887},"step-by-step-adding-a-computed-stat","Step-by-Step: Adding a Computed Stat",[14,890,891],{},[35,892,893],{},"Step 1: Register the computer in your game script",[216,895,896],{"className":218,"code":361,"language":220,"meta":221,"style":221},[126,897,898,918,942,948,956,960],{"__ignoreMap":221},[225,899,900,902,904,906,908,910,912,914,916],{"class":227,"line":228},[225,901,232],{"class":231},[225,903,236],{"class":235},[225,905,239],{"class":231},[225,907,374],{"class":242},[225,909,246],{"class":231},[225,911,250],{"class":249},[225,913,253],{"class":231},[225,915,257],{"class":256},[225,917,260],{"class":231},[225,919,920,922,924,926,928,930,932,934,936,938,940],{"class":227,"line":263},[225,921,389],{"class":256},[225,923,392],{"class":290},[225,925,395],{"class":256},[225,927,398],{"class":231},[225,929,401],{"class":235},[225,931,239],{"class":231},[225,933,406],{"class":242},[225,935,253],{"class":231},[225,937,411],{"class":256},[225,939,414],{"class":290},[225,941,417],{"class":231},[225,943,944,946],{"class":227,"line":270},[225,945,279],{"class":256},[225,947,260],{"class":231},[225,949,950,952,954],{"class":227,"line":276},[225,951,428],{"class":231},[225,953,431],{"class":256},[225,955,434],{"class":290},[225,957,958],{"class":227,"line":284},[225,959,309],{"class":231},[225,961,962],{"class":227,"line":297},[225,963,315],{"class":231},[14,965,966],{},[35,967,968],{},"Step 2: Add to template or status",[14,970,971,972,975,976,115],{},"In ",[35,973,974],{},"Characters → Character Templates",", add to ",[126,977,335],{},[216,979,982],{"className":980,"code":981,"language":342},[340],"computed_stats: [\"enduranceToStamina\"]\n",[126,983,981],{"__ignoreMap":221},[14,985,986,989],{},[35,987,988],{},"Result:"," Characters with this template now get +10 Stamina per point of Endurance, updating automatically when Endurance changes.",[24,991],{},[64,993,995],{"id":994},"important-notes","Important Notes",[14,997,998,1001,1002,1005],{},[35,999,1000],{},"Return only what changes"," - Your function should return only the stats you want to add. Return an empty object ",[126,1003,1004],{},"{}"," if no bonus applies.",[14,1007,1008,1011],{},[35,1009,1010],{},"Results are cached"," - Results are cached and only recalculate when dependencies change - not on every access.",[14,1013,1014,1017],{},[35,1015,1016],{},"Order matters"," - Computed stats are calculated in order. If one depends on another's result, list dependencies first.",[14,1019,1020,1023,1024,1026],{},[35,1021,1022],{},"Works with statuses too"," - Add ",[126,1025,335],{}," to any status(remember everything is a status, including items and skills) for temporary computed bonuses. A buff could add a relationship that disappears when the buff ends.",[1028,1029,1030],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":221,"searchDepth":263,"depth":263,"links":1032},[1033,1034,1035,1036,1037,1038],{"id":66,"depth":270,"text":67},{"id":107,"depth":270,"text":108},{"id":204,"depth":270,"text":205},{"id":349,"depth":270,"text":350},{"id":887,"depth":270,"text":888},{"id":994,"depth":270,"text":995},"This guide covers computed stats - a scripting feature for dynamic stat calculations. If you're new to characters in Dryad Engine, start with Overview first.","md",{"plugin":1042,"category":1043,"page":1044},"global_essentials","characters","characters_computed","\u002Fdocs\u002Fglobal_essentials\u002Fcharacters\u002Fcharacters_computed",{"title":5,"description":1039},"docs\u002Fglobal_essentials\u002Fcharacters\u002Fcharacters_computed","6Pi1bL8lmRRV-fPvQAQsxpwFxMm_4I0yCvlt-3pZRZ0",1779582261155]