From 9b634fa907aba697f90b8445ed0703819fc5e51f Mon Sep 17 00:00:00 2001 From: NocTempre <158857236+NocTempre@users.noreply.github.com> Date: Thu, 4 Sep 2025 21:23:31 -0400 Subject: [PATCH 1/3] UseSkillTrees flag added. --- model/gurps/sheet_settings.go | 1 + ux/sheet_settings_dockable.go | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/model/gurps/sheet_settings.go b/model/gurps/sheet_settings.go index 1148ddf1b..68aaa748c 100644 --- a/model/gurps/sheet_settings.go +++ b/model/gurps/sheet_settings.go @@ -53,6 +53,7 @@ type SheetSettingsData struct { ExcludeUnspentPointsFromTotal bool `json:"exclude_unspent_points_from_total,omitempty"` ShowLiftingSTDamage bool `json:"show_lifting_st_damage,omitempty"` ShowIQBasedDamage bool `json:"show_iq_based_damage,omitempty"` + UseSkillTrees bool `json:"use_skill_trees,omitempty"` } // SheetSettings holds sheet settings. diff --git a/ux/sheet_settings_dockable.go b/ux/sheet_settings_dockable.go index 885a2552a..dbd8841d4 100644 --- a/ux/sheet_settings_dockable.go +++ b/ux/sheet_settings_dockable.go @@ -52,6 +52,7 @@ type sheetSettingsDockable struct { useHalfStatDefaults *unison.CheckBox showLiftingSTDamage *unison.CheckBox showIQBasedDamage *unison.CheckBox + UseSkillTrees *unison.CheckBox lengthUnitsPopup *unison.PopupMenu[fxp.LengthUnit] weightUnitsPopup *unison.PopupMenu[fxp.WeightUnit] userDescDisplayPopup *unison.PopupMenu[display.Option] @@ -221,6 +222,11 @@ func (d *sheetSettingsDockable) createOptions(content *unison.Panel) { d.settings().ShowIQBasedDamage = d.showIQBasedDamage.State == check.On d.syncSheet(false) }) + d.UseSkillTrees = d.addCheckBoxWithLink(panel, i18n.Text("Use Skill Trees"), "PU10:1+", + s.UseSkillTrees, func() { + d.settings().UseSkillTrees = d.UseSkillTrees.State == check.On + d.syncSheet(false) + }) content.AddChild(panel) } @@ -481,6 +487,7 @@ func (d *sheetSettingsDockable) sync() { d.showTitleInsteadOfNameInPageFooter.State = check.FromBool(s.UseTitleInFooter) d.showLiftingSTDamage.State = check.FromBool(s.ShowLiftingSTDamage) d.showIQBasedDamage.State = check.FromBool(s.ShowIQBasedDamage) + d.UseSkillTrees.State = check.FromBool(s.UseSkillTrees) d.useMultiplicativeModifiers.State = check.FromBool(s.UseMultiplicativeModifiers) d.useHalfStatDefaults.State = check.FromBool(s.UseHalfStatDefaults) d.useModifyDicePlusAdds.State = check.FromBool(s.UseModifyingDicePlusAdds) From d9acfbc030494d564eba47a211d1d0aee3749f38 Mon Sep 17 00:00:00 2001 From: NocTempre <158857236+NocTempre@users.noreply.github.com> Date: Sun, 7 Sep 2025 16:18:30 -0400 Subject: [PATCH 2/3] Skill Tree Flag Turns off Default Skill Chaining Behavior --- build.sh | 5 +++++ model/gurps/sheet_settings.go | 2 +- model/gurps/skill.go | 35 +++++++++++++++++++++++------------ ux/pageref_name_mappings.go | 1 + 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/build.sh b/build.sh index debb3e5ab..2dbfb596a 100755 --- a/build.sh +++ b/build.sh @@ -56,6 +56,11 @@ for arg in "$@"; do BUILD_GEN=1 SOMETHING=1 ;; + --custom | -c) + EXTRA_LD_FLAGS="-s -w" + BUILD_GO=1 + SOMETHING=1 + ;; --help | -h) echo "$0 [options]" echo " -a, --all Equivalent to --gen --go --lint --race" diff --git a/model/gurps/sheet_settings.go b/model/gurps/sheet_settings.go index 68aaa748c..7e3763b57 100644 --- a/model/gurps/sheet_settings.go +++ b/model/gurps/sheet_settings.go @@ -53,7 +53,7 @@ type SheetSettingsData struct { ExcludeUnspentPointsFromTotal bool `json:"exclude_unspent_points_from_total,omitempty"` ShowLiftingSTDamage bool `json:"show_lifting_st_damage,omitempty"` ShowIQBasedDamage bool `json:"show_iq_based_damage,omitempty"` - UseSkillTrees bool `json:"use_skill_trees,omitempty"` + UseSkillTrees bool `json:"use_skill_trees,omitempty"` } // SheetSettings holds sheet settings. diff --git a/model/gurps/skill.go b/model/gurps/skill.go index b7526c85c..7833b1eee 100644 --- a/model/gurps/skill.go +++ b/model/gurps/skill.go @@ -524,10 +524,11 @@ func (s *Skill) DefaultSkill() *Skill { if e == nil { return nil } + requirePoints := e.SheetSettings.UseSkillTrees if s.IsTechnique() { - return s.BaseSkill(e, s.TechniqueDefault, true) + return s.BaseSkill(e, s.TechniqueDefault, requirePoints) } - return s.BaseSkill(e, s.DefaultedFrom, true) + return s.BaseSkill(e, s.DefaultedFrom, requirePoints) } // HasDefaultTo returns true if the set of possible defaults includes the other skill. @@ -732,8 +733,10 @@ func (s *Skill) DecrementSkillLevel() { func (s *Skill) CalculateLevel(excludes map[string]bool) Level { points := s.AdjustedPoints(nil) if s.IsTechnique() { - return CalculateTechniqueLevel(EntityFromNode(s), s.Replacements, s.NameWithReplacements(), - s.SpecializationWithReplacements(), s.Tags, s.TechniqueDefault, s.Difficulty.Difficulty, points, true, + e := EntityFromNode(s) + requirePoints := !e.SheetSettings.UseSkillTrees + return CalculateTechniqueLevel(e, s.Replacements, s.NameWithReplacements(), + s.SpecializationWithReplacements(), s.Tags, s.TechniqueDefault, s.Difficulty.Difficulty, points, requirePoints, s.TechniqueLimitModifier, excludes) } return CalculateSkillLevel(EntityFromNode(s), s.NameWithReplacements(), s.SpecializationWithReplacements(), s.Tags, @@ -830,7 +833,8 @@ func CalculateTechniqueLevel(e *Entity, replacements map[string]string, name, sp } } else { // Take the modifier back out, as we wanted the base, not the final value. - level = def.SkillLevelFast(e, replacements, true, nil, false) - def.Modifier + requirePoints := !e.SheetSettings.UseSkillTrees + level = def.SkillLevelFast(e, replacements, requirePoints, nil, false) - def.Modifier } if level != fxp.Min { baseLevel := level @@ -896,13 +900,14 @@ func (s *Skill) bestDefault(excluded *SkillDefault) *SkillDefault { if EntityFromNode(s) == nil || len(s.Defaults) == 0 { return nil } + e := EntityFromNode(s) excludes := make(map[string]bool) excludes[s.String()] = true var bestDef *SkillDefault best := fxp.Min for _, def := range s.resolveToSpecificDefaults() { // For skill-based defaults, prune out any that already use a default that we are involved with - if def.Equivalent(s.Replacements, excluded) || s.inDefaultChain(def, make(map[*Skill]bool)) { + if def.Equivalent(s.Replacements, excluded) || (s.inDefaultChain(def, make(map[*Skill]bool)) && !e.SheetSettings.UseSkillTrees) { continue } if level := s.calcSkillDefaultLevel(def, excludes); best < level { @@ -916,11 +921,11 @@ func (s *Skill) bestDefault(excluded *SkillDefault) *SkillDefault { func (s *Skill) calcSkillDefaultLevel(def *SkillDefault, excludes map[string]bool) fxp.Int { e := EntityFromNode(s) - level := def.SkillLevel(e, s.Replacements, true, excludes, !s.IsTechnique()) - if def.SkillBased() { + level := def.SkillLevel(e, s.Replacements, !e.SheetSettings.UseSkillTrees, excludes, !s.IsTechnique()) + if def.SkillBased() && e != nil && e.SheetSettings.UseSkillTrees { defName := def.NameWithReplacements(s.Replacements) defSpec := def.SpecializationWithReplacements(s.Replacements) - if other := e.BestSkillNamed(defName, defSpec, true, excludes); other != nil { + if other := e.BestSkillNamed(defName, defSpec, !e.SheetSettings.UseSkillTrees, excludes); other != nil { level -= e.SkillBonusFor(defName, defSpec, s.Tags, nil) } } @@ -932,8 +937,9 @@ func (s *Skill) inDefaultChain(def *SkillDefault, lookedAt map[*Skill]bool) bool if e == nil || def == nil || !def.SkillBased() { return false } + requirePoints := !e.SheetSettings.UseSkillTrees for _, one := range e.SkillNamed(def.NameWithReplacements(s.Replacements), - def.SpecializationWithReplacements(s.Replacements), true, nil) { + def.SpecializationWithReplacements(s.Replacements), requirePoints, nil) { if one == s { return true } @@ -954,8 +960,9 @@ func (s *Skill) resolveToSpecificDefaults() []*SkillDefault { if e == nil || def == nil || !def.SkillBased() { result = append(result, def) } else { + requirePoints := !e.SheetSettings.UseSkillTrees for _, one := range e.SkillNamed(def.NameWithReplacements(s.Replacements), - def.SpecializationWithReplacements(s.Replacements), true, + def.SpecializationWithReplacements(s.Replacements), requirePoints, map[string]bool{s.String(): true}) { local := *def local.Name = one.NameWithReplacements() @@ -973,6 +980,9 @@ func (s *Skill) TechniqueSatisfied(tooltip *xbytes.InsertBuffer, prefix string) return true } e := EntityFromNode(s) + if e.SheetSettings.UseSkillTrees { + return true + } sk := e.BestSkillNamed(s.TechniqueDefault.NameWithReplacements(s.Replacements), s.TechniqueDefault.SpecializationWithReplacements(s.Replacements), false, nil) satisfied := sk != nil && (sk.IsTechnique() || sk.Points > 0) @@ -1127,7 +1137,8 @@ func (s *Skill) SwapDefaults() { def := s.DefaultedFrom s.DefaultedFrom = nil if e := EntityFromNode(s); e != nil { - if baseSkill := s.BaseSkill(e, s.bestDefault(nil), true); baseSkill != nil { + requirePoints := !e.SheetSettings.UseSkillTrees + if baseSkill := s.BaseSkill(e, s.bestDefault(nil), requirePoints); baseSkill != nil { s.DefaultedFrom = s.bestDefaultWithPoints(def) baseSkill.UpdateLevel() s.UpdateLevel() diff --git a/ux/pageref_name_mappings.go b/ux/pageref_name_mappings.go index a290b0172..126c2b756 100644 --- a/ux/pageref_name_mappings.go +++ b/ux/pageref_name_mappings.go @@ -227,6 +227,7 @@ var PageRefKeyNameMappings = map[string]string{ "PU7:": "Power-Ups 7: Wildcard Skills", "PU8:": "Power-Ups 8: Limitations", "PU9:": "Power-Ups 9: Alternate Attributes", + "PU10:": "Power-Ups 10: Skill Trees", "PW": "Powers: The Weird", "PY#:": "Pyramid 3 issues (replace # with the issue number, but leave out the leading \"3-\")", "PY4-#:": "Pyramid 4 issues (replace # with the issue number)", From 3168201d6e964e141de51baa75c5f30e69888da8 Mon Sep 17 00:00:00 2001 From: NocTempre <158857236+NocTempre@users.noreply.github.com> Date: Tue, 9 Sep 2025 08:58:38 -0400 Subject: [PATCH 3/3] Fix typos and added guards. --- build.sh | 3 ++- model/gurps/skill.go | 27 +++++++++++++++++---------- ux/sheet_settings_dockable.go | 8 ++++---- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/build.sh b/build.sh index 2dbfb596a..c3dcdb60b 100755 --- a/build.sh +++ b/build.sh @@ -56,7 +56,7 @@ for arg in "$@"; do BUILD_GEN=1 SOMETHING=1 ;; - --custom | -c) + --win | -w) EXTRA_LD_FLAGS="-s -w" BUILD_GO=1 SOMETHING=1 @@ -72,6 +72,7 @@ for arg in "$@"; do echo " -l, --lint Run the linters" echo " -r, --race Run the tests with race-checking enabled" echo " -t, --test Run the tests" + echo " -w, --win Force Build for Windows" echo " -h, --help This help text" exit 0 ;; diff --git a/model/gurps/skill.go b/model/gurps/skill.go index 7833b1eee..052a9b90f 100644 --- a/model/gurps/skill.go +++ b/model/gurps/skill.go @@ -524,7 +524,7 @@ func (s *Skill) DefaultSkill() *Skill { if e == nil { return nil } - requirePoints := e.SheetSettings.UseSkillTrees + requirePoints := !e.SheetSettings.UseSkillTrees if s.IsTechnique() { return s.BaseSkill(e, s.TechniqueDefault, requirePoints) } @@ -734,7 +734,10 @@ func (s *Skill) CalculateLevel(excludes map[string]bool) Level { points := s.AdjustedPoints(nil) if s.IsTechnique() { e := EntityFromNode(s) - requirePoints := !e.SheetSettings.UseSkillTrees + requirePoints := true + if e != nil { + requirePoints = !e.SheetSettings.UseSkillTrees + } return CalculateTechniqueLevel(e, s.Replacements, s.NameWithReplacements(), s.SpecializationWithReplacements(), s.Tags, s.TechniqueDefault, s.Difficulty.Difficulty, points, requirePoints, s.TechniqueLimitModifier, excludes) @@ -833,7 +836,6 @@ func CalculateTechniqueLevel(e *Entity, replacements map[string]string, name, sp } } else { // Take the modifier back out, as we wanted the base, not the final value. - requirePoints := !e.SheetSettings.UseSkillTrees level = def.SkillLevelFast(e, replacements, requirePoints, nil, false) - def.Modifier } if level != fxp.Min { @@ -897,17 +899,18 @@ func (s *Skill) bestDefaultWithPoints(excluded *SkillDefault) *SkillDefault { } func (s *Skill) bestDefault(excluded *SkillDefault) *SkillDefault { - if EntityFromNode(s) == nil || len(s.Defaults) == 0 { + e := EntityFromNode(s) + if e == nil || len(s.Defaults) == 0 { return nil } - e := EntityFromNode(s) + requirePoints := !e.SheetSettings.UseSkillTrees excludes := make(map[string]bool) excludes[s.String()] = true var bestDef *SkillDefault best := fxp.Min for _, def := range s.resolveToSpecificDefaults() { // For skill-based defaults, prune out any that already use a default that we are involved with - if def.Equivalent(s.Replacements, excluded) || (s.inDefaultChain(def, make(map[*Skill]bool)) && !e.SheetSettings.UseSkillTrees) { + if def.Equivalent(s.Replacements, excluded) || (s.inDefaultChain(def, make(map[*Skill]bool)) && requirePoints) { continue } if level := s.calcSkillDefaultLevel(def, excludes); best < level { @@ -921,11 +924,15 @@ func (s *Skill) bestDefault(excluded *SkillDefault) *SkillDefault { func (s *Skill) calcSkillDefaultLevel(def *SkillDefault, excludes map[string]bool) fxp.Int { e := EntityFromNode(s) - level := def.SkillLevel(e, s.Replacements, !e.SheetSettings.UseSkillTrees, excludes, !s.IsTechnique()) - if def.SkillBased() && e != nil && e.SheetSettings.UseSkillTrees { + requirePoints := true + if e != nil { + requirePoints = !e.SheetSettings.UseSkillTrees + } + level := def.SkillLevel(e, s.Replacements, requirePoints, excludes, !s.IsTechnique()) + if def.SkillBased() && e != nil { defName := def.NameWithReplacements(s.Replacements) defSpec := def.SpecializationWithReplacements(s.Replacements) - if other := e.BestSkillNamed(defName, defSpec, !e.SheetSettings.UseSkillTrees, excludes); other != nil { + if other := e.BestSkillNamed(defName, defSpec, requirePoints, excludes); other != nil { level -= e.SkillBonusFor(defName, defSpec, s.Tags, nil) } } @@ -980,7 +987,7 @@ func (s *Skill) TechniqueSatisfied(tooltip *xbytes.InsertBuffer, prefix string) return true } e := EntityFromNode(s) - if e.SheetSettings.UseSkillTrees { + if e != nil && e.SheetSettings.UseSkillTrees { return true } sk := e.BestSkillNamed(s.TechniqueDefault.NameWithReplacements(s.Replacements), diff --git a/ux/sheet_settings_dockable.go b/ux/sheet_settings_dockable.go index dbd8841d4..0d22b0a58 100644 --- a/ux/sheet_settings_dockable.go +++ b/ux/sheet_settings_dockable.go @@ -52,7 +52,7 @@ type sheetSettingsDockable struct { useHalfStatDefaults *unison.CheckBox showLiftingSTDamage *unison.CheckBox showIQBasedDamage *unison.CheckBox - UseSkillTrees *unison.CheckBox + useSkillTrees *unison.CheckBox lengthUnitsPopup *unison.PopupMenu[fxp.LengthUnit] weightUnitsPopup *unison.PopupMenu[fxp.WeightUnit] userDescDisplayPopup *unison.PopupMenu[display.Option] @@ -222,9 +222,9 @@ func (d *sheetSettingsDockable) createOptions(content *unison.Panel) { d.settings().ShowIQBasedDamage = d.showIQBasedDamage.State == check.On d.syncSheet(false) }) - d.UseSkillTrees = d.addCheckBoxWithLink(panel, i18n.Text("Use Skill Trees"), "PU10:1+", + d.useSkillTrees = d.addCheckBoxWithLink(panel, i18n.Text("Use Skill Trees"), "PU10:4", s.UseSkillTrees, func() { - d.settings().UseSkillTrees = d.UseSkillTrees.State == check.On + d.settings().UseSkillTrees = d.useSkillTrees.State == check.On d.syncSheet(false) }) content.AddChild(panel) @@ -487,7 +487,7 @@ func (d *sheetSettingsDockable) sync() { d.showTitleInsteadOfNameInPageFooter.State = check.FromBool(s.UseTitleInFooter) d.showLiftingSTDamage.State = check.FromBool(s.ShowLiftingSTDamage) d.showIQBasedDamage.State = check.FromBool(s.ShowIQBasedDamage) - d.UseSkillTrees.State = check.FromBool(s.UseSkillTrees) + d.useSkillTrees.State = check.FromBool(s.UseSkillTrees) d.useMultiplicativeModifiers.State = check.FromBool(s.UseMultiplicativeModifiers) d.useHalfStatDefaults.State = check.FromBool(s.UseHalfStatDefaults) d.useModifyDicePlusAdds.State = check.FromBool(s.UseModifyingDicePlusAdds)