horsegen: generate skills
This commit is contained in:
@@ -3,4 +3,4 @@
|
|||||||
Models, data, algorithms, and tools for Umamusume: Pretty Derby.
|
Models, data, algorithms, and tools for Umamusume: Pretty Derby.
|
||||||
|
|
||||||
Data is generated from the game's local database.
|
Data is generated from the game's local database.
|
||||||
Algorithms come from either Erzzy and Kireina's reference document or Crazyfellow's parenting and gene guide.
|
Algorithms come from Erzzy and Kireina's reference, KuromiAK's race mechanics reference, and Crazyfellow's parenting and gene guide.
|
||||||
|
|||||||
@@ -130,6 +130,53 @@ race sparks with skills always give +1, skill sparks always give +1-5, unique sp
|
|||||||
- support card skill hints are defined in single_mode_hint_gain
|
- support card skill hints are defined in single_mode_hint_gain
|
||||||
- skill_set is NOT trainee skills, seems to be npcs
|
- skill_set is NOT trainee skills, seems to be npcs
|
||||||
|
|
||||||
|
skill categories:
|
||||||
|
- 0 passive
|
||||||
|
- 1 early race
|
||||||
|
- 2 mid-race
|
||||||
|
- 3 late race or last spurt
|
||||||
|
- 4 anytime
|
||||||
|
- 5 unique
|
||||||
|
|
||||||
|
unique_skill_id_1 is for inherited uniques, points to non-inherited version.
|
||||||
|
unique_skill_id_2 is same but points to 1\*/2\* version.
|
||||||
|
|
||||||
|
exp_type appears to be whether the skill gains levels, i.e. own unique.
|
||||||
|
|
||||||
|
ability time and cooldown time are given in tenths of milliseconds, i.e. divide by 10000 to get seconds.
|
||||||
|
|
||||||
|
ability types:
|
||||||
|
- 1 speed bonus => ability_value / 10000 is flat gain
|
||||||
|
- 2 stamina bonus
|
||||||
|
- 3 power bonus
|
||||||
|
- 4 guts bonus
|
||||||
|
- 5 wit bonus
|
||||||
|
- 6 runaway => ability_value = 0
|
||||||
|
- 8 vision => ability_value / 10000 is amount (what are the units? what does vision do??)
|
||||||
|
- 9 heal or stam debuff => ability_value / 10000 is hp modify
|
||||||
|
- 10 starting gate delay (focus, concentration, gatekept) => ability_value / 10000 is multiplier
|
||||||
|
- 13 frenzy => ability_value / 10000 is rush time modifier (add?)
|
||||||
|
- 21 current speed => ability_value / 10000 is multiplier modifier
|
||||||
|
- 27 target speed => ''
|
||||||
|
- 28 lane change speed => ''
|
||||||
|
- 31 accel => ''
|
||||||
|
- 35 force lane change? it's only on dodging danger/sixth sense with a value of 5000 on both, gametora says "change lane (50% of the track)"
|
||||||
|
|
||||||
|
target types:
|
||||||
|
- 0 none (second and third abilities on skills that only have one)
|
||||||
|
- 1 self
|
||||||
|
- 4 others in view
|
||||||
|
- 9 others ahead, target_value is number of targets (18 for all)
|
||||||
|
- 10 others behind, target_value is number of targets
|
||||||
|
- 18 others in style, target_value is style (1=front, 2=pace, 3=late, 4=end)
|
||||||
|
- 19 rushing others ahead
|
||||||
|
- 20 rushing others behind
|
||||||
|
- 21 rushing others in style, target_value is style
|
||||||
|
|
||||||
|
ability_value_usage can be 1 for plain or 2-6 for aoharu stat skill stat scaling
|
||||||
|
|
||||||
|
seems to be activate_lot = 1 means wit check, 0 means guaranteed
|
||||||
|
|
||||||
# races
|
# races
|
||||||
|
|
||||||
- group 1, grade: g1 100, g2 200, g3 300, op 400, pre-op 700
|
- group 1, grade: g1 100, g2 200, g3 300, op 400, pre-op 700
|
||||||
|
|||||||
1025
horse/skill-group.kk
Normal file
1025
horse/skill-group.kk
Normal file
File diff suppressed because it is too large
Load Diff
2301
horse/skill.kk
2301
horse/skill.kk
File diff suppressed because it is too large
Load Diff
@@ -61,25 +61,37 @@ func ExecCharacterKK(t *template.Template, w io.Writer, c []NamedID[Character],
|
|||||||
return t.ExecuteTemplate(w, "koka-character", &data)
|
return t.ExecuteTemplate(w, "koka-character", &data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExecSkillKK(t *template.Template, w io.Writer, g []NamedID[SkillGroup]) error {
|
func ExecSkillKK(t *template.Template, w io.Writer, g []NamedID[SkillGroup], s []Skill) error {
|
||||||
data := struct {
|
data := struct {
|
||||||
Groups []NamedID[SkillGroup]
|
Groups []NamedID[SkillGroup]
|
||||||
}{g}
|
Skills []Skill
|
||||||
|
}{g, s}
|
||||||
return t.ExecuteTemplate(w, "koka-skill", &data)
|
return t.ExecuteTemplate(w, "koka-skill", &data)
|
||||||
}
|
}
|
||||||
|
|
||||||
const replaceDash = " ,!?/+();#○◎☆♡'&=♪∀゚∴"
|
func ExecSkillGroupKK(t *template.Template, w io.Writer, g []NamedID[SkillGroup], s []Skill) error {
|
||||||
|
data := struct {
|
||||||
|
Groups []NamedID[SkillGroup]
|
||||||
|
Skills []Skill
|
||||||
|
}{g, s}
|
||||||
|
return t.ExecuteTemplate(w, "koka-skill-group", &data)
|
||||||
|
}
|
||||||
|
|
||||||
|
const replaceDash = " ,!?/+();#○☆♡'&=♪∀゚∴"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
kkReplace = func() *strings.Replacer {
|
kkReplace = func() *strings.Replacer {
|
||||||
r := []string{
|
r := []string{
|
||||||
"Triple 7s", "Triple-Sevens", // hard to replace with the right thing automatically
|
"Triple 7s", "Triple-Sevens", // hard to replace with the right thing automatically
|
||||||
"1,500,000 CC", "Million-CC",
|
"1,500,000 CC", "One-Million-CC",
|
||||||
|
"15,000,000 CC", "Fifteen-Million-CC",
|
||||||
"1st", "First",
|
"1st", "First",
|
||||||
".", "",
|
".", "",
|
||||||
"'s", "s",
|
"'s", "s",
|
||||||
"ó", "o",
|
"ó", "o",
|
||||||
"∞", "Infinity",
|
"∞", "Infinity",
|
||||||
|
"×", "x",
|
||||||
|
"◎", "Lv2",
|
||||||
}
|
}
|
||||||
for _, c := range replaceDash {
|
for _, c := range replaceDash {
|
||||||
r = append(r, string(c), "-")
|
r = append(r, string(c), "-")
|
||||||
|
|||||||
133
horsegen/load.go
133
horsegen/load.go
@@ -20,6 +20,9 @@ var characterAffinity3SQL string
|
|||||||
//go:embed skill-group.sql
|
//go:embed skill-group.sql
|
||||||
var skillGroupSQL string
|
var skillGroupSQL string
|
||||||
|
|
||||||
|
//go:embed skill.sql
|
||||||
|
var skillSQL string
|
||||||
|
|
||||||
type (
|
type (
|
||||||
Character struct{}
|
Character struct{}
|
||||||
SkillGroup struct{}
|
SkillGroup struct{}
|
||||||
@@ -174,3 +177,133 @@ func SkillGroups(ctx context.Context, db *sqlitex.Pool) ([]NamedID[SkillGroup],
|
|||||||
}
|
}
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Skill struct {
|
||||||
|
ID int
|
||||||
|
Name string
|
||||||
|
Description string
|
||||||
|
GroupID int
|
||||||
|
GroupName string
|
||||||
|
Rarity int
|
||||||
|
GroupRate int
|
||||||
|
GradeValue int
|
||||||
|
WitCheck bool
|
||||||
|
Activations [2]SkillActivation
|
||||||
|
IconID int
|
||||||
|
Index int
|
||||||
|
}
|
||||||
|
|
||||||
|
type SkillActivation struct {
|
||||||
|
Precondition string
|
||||||
|
Condition string
|
||||||
|
Duration float64
|
||||||
|
Cooldown float64
|
||||||
|
Abilities [3]SkillAbility
|
||||||
|
}
|
||||||
|
|
||||||
|
type SkillAbility struct {
|
||||||
|
Type int
|
||||||
|
ValueUsage int
|
||||||
|
Value float64
|
||||||
|
Target int
|
||||||
|
TargetValue int
|
||||||
|
}
|
||||||
|
|
||||||
|
func Skills(ctx context.Context, db *sqlitex.Pool) ([]Skill, error) {
|
||||||
|
conn, err := db.Take(ctx)
|
||||||
|
defer db.Put(conn)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("couldn't get connection for skills: %w", err)
|
||||||
|
}
|
||||||
|
stmt, _, err := conn.PrepareTransient(skillSQL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("couldn't prepare statement for skills: %w", err)
|
||||||
|
}
|
||||||
|
defer stmt.Finalize()
|
||||||
|
|
||||||
|
var r []Skill
|
||||||
|
for {
|
||||||
|
ok, err := stmt.Step()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error stepping skills: %w", err)
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s := Skill{
|
||||||
|
ID: stmt.ColumnInt(0),
|
||||||
|
Name: stmt.ColumnText(1),
|
||||||
|
Description: stmt.ColumnText(2),
|
||||||
|
GroupID: stmt.ColumnInt(3),
|
||||||
|
GroupName: stmt.ColumnText(4),
|
||||||
|
Rarity: stmt.ColumnInt(5),
|
||||||
|
GroupRate: stmt.ColumnInt(6),
|
||||||
|
GradeValue: stmt.ColumnInt(7),
|
||||||
|
WitCheck: stmt.ColumnInt(8) != 0,
|
||||||
|
Activations: [2]SkillActivation{
|
||||||
|
{
|
||||||
|
Precondition: stmt.ColumnText(9),
|
||||||
|
Condition: stmt.ColumnText(10),
|
||||||
|
Duration: stmt.ColumnFloat(11),
|
||||||
|
Cooldown: stmt.ColumnFloat(12),
|
||||||
|
Abilities: [3]SkillAbility{
|
||||||
|
{
|
||||||
|
Type: stmt.ColumnInt(13),
|
||||||
|
ValueUsage: stmt.ColumnInt(14),
|
||||||
|
Value: stmt.ColumnFloat(15),
|
||||||
|
Target: stmt.ColumnInt(16),
|
||||||
|
TargetValue: stmt.ColumnInt(17),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: stmt.ColumnInt(18),
|
||||||
|
ValueUsage: stmt.ColumnInt(19),
|
||||||
|
Value: stmt.ColumnFloat(20),
|
||||||
|
Target: stmt.ColumnInt(21),
|
||||||
|
TargetValue: stmt.ColumnInt(22),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: stmt.ColumnInt(23),
|
||||||
|
ValueUsage: stmt.ColumnInt(24),
|
||||||
|
Value: stmt.ColumnFloat(25),
|
||||||
|
Target: stmt.ColumnInt(26),
|
||||||
|
TargetValue: stmt.ColumnInt(27),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Precondition: stmt.ColumnText(28),
|
||||||
|
Condition: stmt.ColumnText(29),
|
||||||
|
Duration: stmt.ColumnFloat(30),
|
||||||
|
Cooldown: stmt.ColumnFloat(31),
|
||||||
|
Abilities: [3]SkillAbility{
|
||||||
|
{
|
||||||
|
Type: stmt.ColumnInt(32),
|
||||||
|
ValueUsage: stmt.ColumnInt(33),
|
||||||
|
Value: stmt.ColumnFloat(34),
|
||||||
|
Target: stmt.ColumnInt(35),
|
||||||
|
TargetValue: stmt.ColumnInt(36),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: stmt.ColumnInt(37),
|
||||||
|
ValueUsage: stmt.ColumnInt(38),
|
||||||
|
Value: stmt.ColumnFloat(39),
|
||||||
|
Target: stmt.ColumnInt(40),
|
||||||
|
TargetValue: stmt.ColumnInt(41),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: stmt.ColumnInt(42),
|
||||||
|
ValueUsage: stmt.ColumnInt(43),
|
||||||
|
Value: stmt.ColumnFloat(44),
|
||||||
|
Target: stmt.ColumnInt(45),
|
||||||
|
TargetValue: stmt.ColumnInt(46),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
IconID: stmt.ColumnInt(47),
|
||||||
|
Index: stmt.ColumnInt(48),
|
||||||
|
}
|
||||||
|
r = append(r, s)
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ func main() {
|
|||||||
pairs []AffinityRelation
|
pairs []AffinityRelation
|
||||||
trios []AffinityRelation
|
trios []AffinityRelation
|
||||||
sg []NamedID[SkillGroup]
|
sg []NamedID[SkillGroup]
|
||||||
|
skills []Skill
|
||||||
)
|
)
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
slog.Info("get characters")
|
slog.Info("get characters")
|
||||||
@@ -72,6 +73,12 @@ func main() {
|
|||||||
sg = r
|
sg = r
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
eg.Go(func() error {
|
||||||
|
slog.Info("get skills")
|
||||||
|
r, err := Skills(ctx, db)
|
||||||
|
skills = r
|
||||||
|
return err
|
||||||
|
})
|
||||||
if err := eg.Wait(); err != nil {
|
if err := eg.Wait(); err != nil {
|
||||||
slog.Error("load", slog.Any("err", err))
|
slog.Error("load", slog.Any("err", err))
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
@@ -92,7 +99,15 @@ func main() {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
slog.Info("write skills")
|
slog.Info("write skills")
|
||||||
return ExecSkillKK(t, sf, sg)
|
return ExecSkillKK(t, sf, sg, skills)
|
||||||
|
})
|
||||||
|
eg.Go(func() error {
|
||||||
|
sf, err := os.Create(filepath.Join(out, "skill-group.kk"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
slog.Info("write skill groups")
|
||||||
|
return ExecSkillGroupKK(t, sf, sg, skills)
|
||||||
})
|
})
|
||||||
if err := eg.Wait(); err != nil {
|
if err := eg.Wait(); err != nil {
|
||||||
slog.Error("generate", slog.Any("err", err))
|
slog.Error("generate", slog.Any("err", err))
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{{ define "koka-skill" -}}
|
{{- define "koka-skill-group" -}}
|
||||||
module horse/skill
|
module horse/skill-group
|
||||||
|
|
||||||
// Automatically generated with the horsegen tool; DO NOT EDIT
|
// Automatically generated with horsegen; DO NOT EDIT
|
||||||
|
|
||||||
// Skill groups.
|
// Skill groups.
|
||||||
// A skill group may contain white, circle, double-circle, gold, and purple skills
|
// A skill group may contain white, circle, double-circle, gold, and purple skills
|
||||||
@@ -27,7 +27,7 @@ pub fip(1) fun skill-group/from-id(^id: int): maybe<skill-group>
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
|
|
||||||
// Get names for skill groups.
|
// Get the name for a skill group.
|
||||||
// Skill group names are the name of the base skill in the group.
|
// Skill group names are the name of the base skill in the group.
|
||||||
pub fun skill-group/show(sg: skill-group): string
|
pub fun skill-group/show(sg: skill-group): string
|
||||||
match sg
|
match sg
|
||||||
@@ -45,4 +45,291 @@ pub fip fun skill-group/order2(a: skill-group, b: skill-group): order2<skill-gro
|
|||||||
pub fun skill-group/(==)(a: skill-group, b: skill-group): bool
|
pub fun skill-group/(==)(a: skill-group, b: skill-group): bool
|
||||||
a.group-id == b.group-id
|
a.group-id == b.group-id
|
||||||
|
|
||||||
{{- end }}
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "koka-skill" -}}
|
||||||
|
module horse/skill
|
||||||
|
|
||||||
|
import std/num/float64
|
||||||
|
pub import horse/skill-group
|
||||||
|
|
||||||
|
// Skills instances.
|
||||||
|
pub type skill
|
||||||
|
{{- range $s := $.Skills }}
|
||||||
|
{{ kkenum $s.Name }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
// Map a skill to its ID.
|
||||||
|
pub fip fun skill/skill-id(^s: skill): int
|
||||||
|
match s
|
||||||
|
{{- range $s := $.Skills }}
|
||||||
|
{{ kkenum $s.Name }} -> {{ $s.ID }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
// Get the skill for an ID.
|
||||||
|
pub fip(1) fun skill/from-id(^id: int): maybe<skill>
|
||||||
|
match id
|
||||||
|
{{- range $s := $.Skills }}
|
||||||
|
{{ $s.ID }} -> Just( {{- kkenum $s.Name -}} )
|
||||||
|
{{- end }}
|
||||||
|
_ -> Nothing
|
||||||
|
|
||||||
|
// Get the name of a skill.
|
||||||
|
pub fun skill/show(s: skill): string
|
||||||
|
match s
|
||||||
|
{{- range $s := $.Skills }}
|
||||||
|
{{ kkenum $s.Name }} -> {{ printf "%q" $s.Name }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
// Compare two skills by ID order.
|
||||||
|
pub fip fun skill/order2(a: skill, b: skill): order2<skill>
|
||||||
|
match cmp(a.skill-id, b.skill-id)
|
||||||
|
Lt -> Lt2(a, b)
|
||||||
|
Eq -> Eq2(a)
|
||||||
|
Gt -> Gt2(a, b)
|
||||||
|
|
||||||
|
pub fun skill/(==)(a: skill, b: skill): bool
|
||||||
|
a.skill-id == b.skill-id
|
||||||
|
|
||||||
|
// Get complete skill info.
|
||||||
|
pub fun skill/detail(^s: skill): skill-detail
|
||||||
|
match s
|
||||||
|
{{- range $s := $.Skills }}
|
||||||
|
{{ kkenum $s.Name }} -> {{ template "kk-render-skill-detail" $s }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
// Details about a skill.
|
||||||
|
pub struct skill-detail
|
||||||
|
skill-id: int
|
||||||
|
name: string
|
||||||
|
description: string
|
||||||
|
group: skill-group
|
||||||
|
rarity: rarity
|
||||||
|
group-rate: int
|
||||||
|
grade-value: int
|
||||||
|
wit-check: bool
|
||||||
|
activations: list<activation>
|
||||||
|
icon-id: int
|
||||||
|
|
||||||
|
// Automatically generated.
|
||||||
|
// Shows a string representation of the `skill-detail` type.
|
||||||
|
pub fun skill-detail/show(this : skill-detail) : e string
|
||||||
|
match this
|
||||||
|
Skill-detail(skill-id, name, description, group, rarity, group-rate, grade-value, wit-check, activations, icon-id) -> "Skill-detail(skill-id: " ++ skill-id.show ++ ", name: " ++ name.show ++ ", description: " ++ description.show ++ ", group: " ++ group.show ++ ", rarity: " ++ rarity.show ++ ", group-rate: " ++ group-rate.show ++ ", grade-value: " ++ grade-value.show ++ ", wit-check: " ++ wit-check.show ++ ", activations: " ++ activations.show ++ ", icon-id: " ++ icon-id.show ++ ")"
|
||||||
|
|
||||||
|
// Skill rarity.
|
||||||
|
pub type rarity
|
||||||
|
Common // white
|
||||||
|
Rare // gold
|
||||||
|
Unique-Low // 1*/2* unique
|
||||||
|
Unique-Upgraded // 3*+ unique on a trainee upgraded from 1*/2*
|
||||||
|
Unique // base 3* unique
|
||||||
|
|
||||||
|
pub fun rarity/show(r: rarity): string
|
||||||
|
match r
|
||||||
|
Common -> "Common"
|
||||||
|
Rare -> "Rare"
|
||||||
|
Unique-Low -> "Unique (1☆/2☆)"
|
||||||
|
Unique-Upgraded -> "Unique (3☆+ from 1☆/2☆ upgraded)"
|
||||||
|
Unique -> "Unique (3☆+)"
|
||||||
|
|
||||||
|
// Condition and precondition logic.
|
||||||
|
pub alias condition = string
|
||||||
|
|
||||||
|
// Activation conditions and effects.
|
||||||
|
// A skill has one or two activations.
|
||||||
|
pub struct activation
|
||||||
|
precondition: condition
|
||||||
|
condition: condition
|
||||||
|
duration: float64 // seconds
|
||||||
|
cooldown: float64 // seconds
|
||||||
|
abilities: list<ability> // one to three elements
|
||||||
|
|
||||||
|
pub fun activation/show(a: activation): string
|
||||||
|
match a
|
||||||
|
Activation("", condition, -1.0, _, abilities) -> condition ++ " -> " ++ abilities.show
|
||||||
|
Activation("", condition, duration, cooldown, abilities) | cooldown >= 500.0 -> condition ++ " -> " ++ abilities.show ++ " for " ++ duration.show ++ "s"
|
||||||
|
Activation("", condition, duration, cooldown, abilities) -> condition ++ " -> " ++ abilities.show ++ " for " ++ duration.show ++ "s on " ++ cooldown.show ++ "s cooldown"
|
||||||
|
Activation(precondition, condition, -1.0, _, abilities)-> precondition ++ " -> " ++ condition ++ " -> " ++ abilities.show
|
||||||
|
Activation(precondition, condition, duration, cooldown, abilities) | cooldown >= 500.0 -> precondition ++ " -> " ++ condition ++ " -> " ++ abilities.show ++ " for " ++ duration.show ++ "s"
|
||||||
|
Activation(precondition, condition, duration, cooldown, abilities) -> precondition ++ "-> " ++ condition ++ " -> " ++ abilities.show ++ " for " ++ duration.show ++ "s on " ++ cooldown.show ++ "s cooldown"
|
||||||
|
|
||||||
|
// Effects of activating a skill.
|
||||||
|
pub struct ability
|
||||||
|
ability-type: ability-type
|
||||||
|
value-usage: value-usage
|
||||||
|
target: target
|
||||||
|
|
||||||
|
pub fun ability/show(a: ability): string
|
||||||
|
match a
|
||||||
|
Ability(t, Direct, Self) -> t.show
|
||||||
|
Ability(t, Direct, target) -> t.show ++ " " ++ target.show
|
||||||
|
Ability(t, v, Self) -> t.show ++ " scaling by " ++ v.show
|
||||||
|
Ability(t, v, target) -> t.show ++ " " ++ target.show ++ " scaling by " ++ v.show
|
||||||
|
|
||||||
|
// Target of a skill activation effect.
|
||||||
|
pub type ability-type
|
||||||
|
Passive-Speed(bonus: float64)
|
||||||
|
Passive-Stamina(bonus: float64)
|
||||||
|
Passive-Power(bonus: float64)
|
||||||
|
Passive-Guts(bonus: float64)
|
||||||
|
Passive-Wit(bonus: float64)
|
||||||
|
Runaway
|
||||||
|
Vision(bonus: float64)
|
||||||
|
HP(rate: float64)
|
||||||
|
Gate-Delay(rate: float64)
|
||||||
|
Frenzy(add: float64)
|
||||||
|
Current-Speed(rate: float64)
|
||||||
|
Target-Speed(rate: float64)
|
||||||
|
Lane-Speed(rate: float64)
|
||||||
|
Accel(rate: float64)
|
||||||
|
Lane-Change(rate: float64)
|
||||||
|
|
||||||
|
pub fun ability-type/show(a: ability-type): string
|
||||||
|
match a
|
||||||
|
Passive-Speed(bonus) -> "passive " ++ bonus.show ++ " Speed"
|
||||||
|
Passive-Stamina(bonus) -> "passive " ++ bonus.show ++ " Stamina"
|
||||||
|
Passive-Power(bonus) -> "passive " ++ bonus.show ++ " Power"
|
||||||
|
Passive-Guts(bonus) -> "passive " ++ bonus.show ++ " Guts"
|
||||||
|
Passive-Wit(bonus) -> "passive " ++ bonus.show ++ " Wit"
|
||||||
|
Runaway -> "enable Great Escape style"
|
||||||
|
Vision(bonus) -> bonus.show ++ " vision"
|
||||||
|
HP(rate) | rate >= 0.0 -> show(rate * 100.0) ++ "% HP recovery"
|
||||||
|
HP(rate) -> show(rate * 100.0) ++ "% HP loss"
|
||||||
|
Gate-Delay(rate) -> rate.show ++ "× gate delay"
|
||||||
|
Frenzy(add) -> add.show ++ "s longer Rushed"
|
||||||
|
Current-Speed(rate) -> show(rate * 100.0) ++ "% current speed"
|
||||||
|
Target-Speed(rate) -> show(rate * 100.0) ++ "% target speed"
|
||||||
|
Lane-Speed(rate) -> show(rate * 100.0) ++ "% lane speed"
|
||||||
|
Accel(rate) -> show(rate * 100.0) ++ "% acceleration"
|
||||||
|
Lane-Change(rate) -> rate.show ++ " course width movement"
|
||||||
|
|
||||||
|
// Special scaling for skill activation effects.
|
||||||
|
pub type value-usage
|
||||||
|
Direct
|
||||||
|
Team-Speed
|
||||||
|
Team-Stamina
|
||||||
|
Team-Power
|
||||||
|
Team-Guts
|
||||||
|
Team-Wit
|
||||||
|
Multiply-Random
|
||||||
|
|
||||||
|
pub fun value-usage/show(v: value-usage): string
|
||||||
|
match v
|
||||||
|
Direct -> "no scaling"
|
||||||
|
Team-Speed -> "team's Speed"
|
||||||
|
Team-Stamina -> "team's Stamina"
|
||||||
|
Team-Power -> "team's Power"
|
||||||
|
Team-Guts -> "team's Guts"
|
||||||
|
Team-Wit -> "team's Wit"
|
||||||
|
Multiply-Random -> "random multiplier (0× to 0.04×)"
|
||||||
|
|
||||||
|
// Who a skill activation targets.
|
||||||
|
pub type target
|
||||||
|
Self
|
||||||
|
In-View
|
||||||
|
Ahead(limit: int)
|
||||||
|
Behind(limit: int)
|
||||||
|
Style(style: style)
|
||||||
|
Rushing-Ahead(limit: int)
|
||||||
|
Rushing-Behind(limit: int)
|
||||||
|
Rushing-Style(style: style)
|
||||||
|
|
||||||
|
pub fun target/show(t: target): string
|
||||||
|
match t
|
||||||
|
Self -> "self"
|
||||||
|
In-View -> "others in field of view"
|
||||||
|
Ahead(limit) | limit >= 18 -> "others ahead"
|
||||||
|
Ahead(limit) -> "next " ++ limit.show ++ " others ahead"
|
||||||
|
Behind(limit) | limit >= 18 -> "others behind"
|
||||||
|
Behind(limit) -> "next " ++ limit.show ++ " others behind"
|
||||||
|
Style(Front-Runner) -> "other Front Runners"
|
||||||
|
Style(Pace-Chaser) -> "other Pace Chasers"
|
||||||
|
Style(Late-Surger) -> "other Late Surgers"
|
||||||
|
Style(End-Closer) -> "other End Closers"
|
||||||
|
Rushing-Ahead(limit) | limit >= 18 -> "others rushing ahead"
|
||||||
|
Rushing-Ahead(limit) -> "next " ++ limit.show ++ " others rushing ahead"
|
||||||
|
Rushing-Behind(limit) | limit >= 18 -> "others rushing behind"
|
||||||
|
Rushing-Behind(limit) -> "next " ++ limit.show ++ " others rushing behind"
|
||||||
|
Rushing-Style(Front-Runner) -> "rushing Front Runners"
|
||||||
|
Rushing-Style(Pace-Chaser) -> "rushing Pace Chasers"
|
||||||
|
Rushing-Style(Late-Surger) -> "rushing Late Surgers"
|
||||||
|
Rushing-Style(End-Closer) -> "rushing End Closers"
|
||||||
|
|
||||||
|
// Running style for skill targets.
|
||||||
|
// TODO(zeph): there is definitely a better place for this to live
|
||||||
|
pub type style
|
||||||
|
Front-Runner
|
||||||
|
Pace-Chaser
|
||||||
|
Late-Surger
|
||||||
|
End-Closer
|
||||||
|
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{ define "kk-render-skill-detail" }}
|
||||||
|
{{- /* Call with Skill structure as argument. */ -}}
|
||||||
|
Skill-detail(skill-id = {{ $.ID -}}
|
||||||
|
, name = {{ printf "%q" $.Name -}}
|
||||||
|
, description = {{ printf "%q" $.Description -}}
|
||||||
|
, group = {{ kkenum $.GroupName -}}
|
||||||
|
, rarity = {{ if eq $.Rarity 1 }}Common{{ else if eq $.Rarity 2 }}Rare{{ else if eq $.Rarity 3 }}Unique-Low{{ else if eq $.Rarity 4 }}Unique-Upgraded{{ else if eq $.Rarity 5 }}Unique{{ else }}??? $.Rarity={{ $.Rarity }}{{ end -}}
|
||||||
|
, group-rate = {{ $.GroupRate -}}
|
||||||
|
, grade-value = {{ $.GradeValue -}}
|
||||||
|
, wit-check = {{ if $.WitCheck }}True{{ else }}False{{ end -}}
|
||||||
|
, activations = [
|
||||||
|
{{- range $a := $.Activations -}}
|
||||||
|
{{- if ne $a.Condition "" -}}
|
||||||
|
Activation(precondition = {{ printf "%q" $a.Precondition -}}
|
||||||
|
, condition = {{ printf "%q" $a.Condition -}}
|
||||||
|
, duration = {{ printf "%f" $a.Duration -}}
|
||||||
|
, cooldown = {{ printf "%f" $a.Cooldown -}}
|
||||||
|
, abilities = [
|
||||||
|
{{- range $abil := $a.Abilities -}}
|
||||||
|
{{- if ne $abil.Type 0 -}}
|
||||||
|
Ability(ability-type =
|
||||||
|
{{- if eq $abil.Type 1 -}}Passive-Speed({{ printf "%f" $abil.Value }})
|
||||||
|
{{- else if eq $abil.Type 2 -}}Passive-Stamina({{ printf "%f" $abil.Value }})
|
||||||
|
{{- else if eq $abil.Type 3 -}}Passive-Power({{ printf "%f" $abil.Value }})
|
||||||
|
{{- else if eq $abil.Type 4 -}}Passive-Guts({{ printf "%f" $abil.Value }})
|
||||||
|
{{- else if eq $abil.Type 5 -}}Passive-Wit({{ printf "%f" $abil.Value }})
|
||||||
|
{{- else if eq $abil.Type 6 -}}Runaway
|
||||||
|
{{- else if eq $abil.Type 8 -}}Vision({{ printf "%f" $abil.Value }})
|
||||||
|
{{- else if eq $abil.Type 9 -}}HP({{ printf "%f" $abil.Value }})
|
||||||
|
{{- else if eq $abil.Type 10 -}}Gate-Delay({{ printf "%f" $abil.Value }})
|
||||||
|
{{- else if eq $abil.Type 13 -}}Frenzy({{ printf "%f" $abil.Value }})
|
||||||
|
{{- else if eq $abil.Type 21 -}}Current-Speed({{ printf "%f" $abil.Value }})
|
||||||
|
{{- else if eq $abil.Type 27 -}}Target-Speed({{ printf "%f" $abil.Value }})
|
||||||
|
{{- else if eq $abil.Type 28 -}}Lane-Speed({{ printf "%f" $abil.Value }})
|
||||||
|
{{- else if eq $abil.Type 31 -}}Accel({{ printf "%f" $abil.Value }})
|
||||||
|
{{- else if eq $abil.Type 35 -}}Lane-Change({{ printf "%f" $abil.Value }})
|
||||||
|
{{- else -}}??? $abil.Type={{$abil.Type}}
|
||||||
|
{{- end -}}
|
||||||
|
, value-usage =
|
||||||
|
{{- if eq $abil.ValueUsage 1 -}}Direct
|
||||||
|
{{- else if eq $abil.ValueUsage 3 -}}Team-Speed
|
||||||
|
{{- else if eq $abil.ValueUsage 4 -}}Team-Stamina
|
||||||
|
{{- else if eq $abil.ValueUsage 5 -}}Team-Power
|
||||||
|
{{- else if eq $abil.ValueUsage 6 -}}Team-Guts
|
||||||
|
{{- else if eq $abil.ValueUsage 7 -}}Team-Wit
|
||||||
|
{{- else if eq $abil.ValueUsage 8 -}}Multiply-Random
|
||||||
|
{{- else -}}??? $abil.ValueUsage={{ $abil.ValueUsage }}
|
||||||
|
{{- end -}}
|
||||||
|
, target =
|
||||||
|
{{- if eq $abil.Target 1 -}}Self
|
||||||
|
{{- else if eq $abil.Target 4 -}}In-View
|
||||||
|
{{- else if eq $abil.Target 9 -}}Ahead({{ $abil.TargetValue }})
|
||||||
|
{{- else if eq $abil.Target 10 -}}Behind({{ $abil.TargetValue }})
|
||||||
|
{{- else if eq $abil.Target 18 -}}Style({{ if eq $abil.TargetValue 1 }}Front-Runner{{ else if eq $abil.TargetValue 2 }}Pace-Chaser{{ else if eq $abil.TargetValue 3 }}Late-Surger{{ else if eq $abil.TargetValue 4 }}End-Closer{{ else }}??? $abil.TargetValue={{ $abil.TargetValue }}{{ end }})
|
||||||
|
{{- else if eq $abil.Target 19 -}}Rushing-Ahead({{ $abil.TargetValue }})
|
||||||
|
{{- else if eq $abil.Target 20 -}}Rushing-Behind({{ $abil.TargetValue }})
|
||||||
|
{{- else if eq $abil.Target 21 -}}Rushing-Style({{ if eq $abil.TargetValue 1 }}Front-Runner{{ else if eq $abil.TargetValue 2 }}Pace-Chaser{{ else if eq $abil.TargetValue 3 }}Late-Surger{{ else if eq $abil.TargetValue 4 }}End-Closer{{ else }}??? $abil.TargetValue={{ $abil.TargetValue }}{{ end }})
|
||||||
|
{{- end -}}
|
||||||
|
),
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
]),
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
], icon-id = {{ $.IconID -}}
|
||||||
|
)
|
||||||
|
{{- end -}}
|
||||||
|
|||||||
69
horsegen/skill.sql
Normal file
69
horsegen/skill.sql
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
WITH skill_names AS (
|
||||||
|
SELECT
|
||||||
|
n."index" AS "id",
|
||||||
|
n."text" AS "name",
|
||||||
|
d."text" AS "description"
|
||||||
|
FROM text_data n
|
||||||
|
JOIN text_data d ON n."index" = d."index" AND n."category" = 47 AND d."category" = 48
|
||||||
|
), skill_groups AS (
|
||||||
|
SELECT
|
||||||
|
group_id,
|
||||||
|
name
|
||||||
|
FROM skill_data d
|
||||||
|
JOIN skill_names n ON d.id = n.id
|
||||||
|
WHERE group_rate = 1
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
d.id,
|
||||||
|
n.name,
|
||||||
|
n.description,
|
||||||
|
d.group_id,
|
||||||
|
g.name,
|
||||||
|
d.rarity,
|
||||||
|
d.group_rate,
|
||||||
|
d.grade_value,
|
||||||
|
d.activate_lot,
|
||||||
|
d.precondition_1,
|
||||||
|
d.condition_1,
|
||||||
|
IIF(d.float_ability_time_1 <= 0, CAST(d.float_ability_time_1 AS REAL), d.float_ability_time_1 / 1e4) AS float_ability_time_1,
|
||||||
|
IIF(d.float_cooldown_time_1 <= 0, CAST(d.float_cooldown_time_1 AS REAL), d.float_cooldown_time_1 / 1e4) AS float_cooldown_time_1,
|
||||||
|
d.ability_type_1_1,
|
||||||
|
d.ability_value_usage_1_1,
|
||||||
|
d.float_ability_value_1_1 / 1e4 AS float_ability_value_1_1,
|
||||||
|
d.target_type_1_1,
|
||||||
|
d.target_value_1_1,
|
||||||
|
d.ability_type_1_2,
|
||||||
|
d.ability_value_usage_1_2,
|
||||||
|
d.float_ability_value_1_2 / 1e4 AS float_ability_value_1_2,
|
||||||
|
d.target_type_1_2,
|
||||||
|
d.target_value_1_2,
|
||||||
|
d.ability_type_1_3,
|
||||||
|
d.ability_value_usage_1_3,
|
||||||
|
d.float_ability_value_1_3 / 1e4 AS float_ability_value_1_3,
|
||||||
|
d.target_type_1_3,
|
||||||
|
d.target_value_1_3,
|
||||||
|
d.precondition_2,
|
||||||
|
d.condition_2,
|
||||||
|
IIF(d.float_ability_time_2 <= 0, CAST(d.float_ability_time_2 AS REAL), d.float_ability_time_2 / 1e4) AS float_ability_time_2,
|
||||||
|
IIF(d.float_cooldown_time_2 <= 0, CAST(d.float_cooldown_time_2 AS REAL), d.float_cooldown_time_2 / 1e4) AS float_cooldown_time_2,
|
||||||
|
d.ability_type_2_1,
|
||||||
|
d.ability_value_usage_2_1,
|
||||||
|
d.float_ability_value_2_1 / 1e4 AS float_ability_value_2_1,
|
||||||
|
d.target_type_2_1,
|
||||||
|
d.target_value_2_1,
|
||||||
|
d.ability_type_2_2,
|
||||||
|
d.ability_value_usage_2_2,
|
||||||
|
d.float_ability_value_2_2 / 1e4 AS float_ability_value_2_2,
|
||||||
|
d.target_type_2_2,
|
||||||
|
d.target_value_2_2,
|
||||||
|
d.ability_type_2_3,
|
||||||
|
d.ability_value_usage_2_3,
|
||||||
|
d.float_ability_value_2_3 / 1e4 AS float_ability_value_2_3,
|
||||||
|
d.target_type_2_3,
|
||||||
|
d.target_value_2_3,
|
||||||
|
d.icon_id,
|
||||||
|
ROW_NUMBER() OVER (ORDER BY d.id) - 1 AS "index"
|
||||||
|
FROM skill_data d
|
||||||
|
JOIN skill_names n ON d.id = n.id
|
||||||
|
JOIN skill_groups g ON d.group_id = g.group_id
|
||||||
|
ORDER BY d.id
|
||||||
Reference in New Issue
Block a user