Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 49 additions & 1 deletion cmd/zoodle/bootstrap/compileenv.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,21 @@ func installCompilerFunctions(these *settings.Zootr) mido.ConfigureCompiler {

return func(env *mido.CompileEnv) {
hasNotesForSong := env.Symbols.Declare("has_notes_for_song", symbols.BUILT_IN_FUNCTION)
needsHeartForDamageMult := env.Symbols.Declare("needs_hearts_for_damage_multipler", symbols.BUILT_IN_FUNCTION)
checkTod := env.Symbols.Declare("check_tod", symbols.BUILT_IN_FUNCTION)
isGlitchEnabled := func(args []ast.Node, _ ast.Rewriting) (ast.Node, error) {
switch arg := args[0].(type) {
case ast.String:
return ast.Boolean(these.Skills.Glitches[string(arg)]), nil
default:
return nil, fmt.Errorf("is_glitch_enabled expects string as first argument got %#v", arg)
}
}

isTrickEnabled := func(args []ast.Node, _ ast.Rewriting) (ast.Node, error) {
switch arg := args[0].(type) {
case ast.String:
return ast.Boolean(these.Tricks.Enabled[string(arg)]), nil
return ast.Boolean(these.Skills.Tricks[string(arg)]), nil
default:
return nil, fmt.Errorf("is_trick_enabled expects string as first argument got %#v", arg)
}
Expand All @@ -164,6 +174,41 @@ func installCompilerFunctions(these *settings.Zootr) mido.ConfigureCompiler {
}, nil
}

canLiveDmg := func(args []ast.Node, rewriting ast.Rewriting) (ast.Node, error) {
invokes := make([]ast.Node, 3)
invokes[0] = ast.Invoke{
Target: ast.IdentifierFrom(needsHeartForDamageMult),
Args: []ast.Node{args[0]},
}
invokes[1] = ast.Invoke{
Target: ast.IdentifierFrom(env.Symbols.LookUpByName("Fairy")),
}
invokes[2] = ast.Invoke{
Target: ast.IdentifierFrom(env.Symbols.LookUpByName("can_use")),
Args: []ast.Node{ast.IdentifierFrom(env.Symbols.LookUpByName("Nayrus_Love"))},
}

switch len(args) {
case 3:
if !args[1].(ast.Boolean) {
invokes[1] = ast.Boolean(false)
}
if !args[2].(ast.Boolean) {
invokes[2] = ast.Boolean(false)
}
case 2:
if !args[1].(ast.Boolean) {
invokes[1] = ast.Boolean(false)
}
case 1:
break
default:
return nil, fmt.Errorf("can_live_dmg expects between 1 and 3 args, received %v", len(args))
}

return ast.AnyOf(invokes), nil
}

isTrialSkipped := func(args []ast.Node, _ ast.Rewriting) (ast.Node, error) {
return ast.Boolean(false), nil
}
Expand Down Expand Up @@ -197,13 +242,16 @@ func installCompilerFunctions(these *settings.Zootr) mido.ConfigureCompiler {
mido.WithCompilerFunctions(func(*mido.CompileEnv) optimizer.CompilerFunctionTable {
return optimizer.CompilerFunctionTable{
"region_has_shortcuts": regionHasShortcuts,
"is_glitch_enabled": isGlitchEnabled,
"is_trick_enabled": isTrickEnabled,
"had_night_start": hadNightStart,
"has_all_notes_for_song": hasAllNotesForSong,
"at_dampe_time": needsTodChecks("dampe"),
"at_day": needsTodChecks("day"),
"at_night": needsTodChecks("night"),
"is_trial_skipped": isTrialSkipped,
"has_soul": ConstCompileFunc(true),
"can_live_dmg": canLiveDmg,
}
})(env)
}
Expand Down
7 changes: 1 addition & 6 deletions cmd/zoodle/explore.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,8 @@ func fromStartingAge(start settings.StartingAge) Age {
func explore(ctx context.Context, xplr *magicbean.Exploration, generation *magicbean.Generation, age Age) magicbean.ExplorationResults {
pockets := magicbean.NewPockets(&generation.Inventory, &generation.Ocm)

var shuffleFlags magicbean.ShuffleFlags
if generation.Settings.Shuffling.OcarinaNotes {
shuffleFlags = shuffleFlags | magicbean.SHUFFLE_OCARINA_NOTES
}

funcs := magicbean.BuiltIns{}
magicbean.CreateBuiltInHasFuncs(&funcs, &pockets, shuffleFlags)
magicbean.CreateBuiltInHasFuncs(&funcs, &pockets, &generation.Settings)
funcs.CheckTodAccess = magicbean.ConstBool(true)
funcs.IsAdult = magicbean.ConstBool(age == AgeAdult)
funcs.IsChild = magicbean.ConstBool(age == AgeChild)
Expand Down
4 changes: 2 additions & 2 deletions internal/settings/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func Default() Zootr {
s.Shuffling.Tokens = ShuffleGoldTokenOff
s.Shuffling.WonderItems = false

s.Tricks.Enabled = map[string]bool{
s.Skills.Tricks = map[string]bool{
"fewer_tunic_requirements": true,
"grottos_without_agony": true,
"child_deadhand": true,
Expand All @@ -94,7 +94,6 @@ func Default() Zootr {
s.Starting.Hearts = 3
s.Starting.RauruReward = true
s.Starting.Rupees = 0
s.Starting.Scarecrow = false
s.Starting.TimeOfDay = StartingTimeOfDayDefault
s.Starting.Tokens = []string{
"Deku Shield",
Expand All @@ -118,6 +117,7 @@ func Default() Zootr {
s.Trades.Child = ChildTradeStartMaskKeaton

s.ItemPool = ItemPoolDefault
s.ScarecrowBehavior = ScarecrowBehaviorDefault

return s
}
1 change: 1 addition & 0 deletions internal/settings/names.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ var names = []string{
"entrance_shuffle",
"fix_broken_drops",
"free_bombchu_drops",
"scarecrow_behavior",
"free_scarecrow",
"ganon_bosskey_hearts",
"ganon_bosskey_medallions",
Expand Down
6 changes: 4 additions & 2 deletions internal/settings/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ func (this *Zootr) String(name string) (string, error) {
val = this.Damage.Bonk.String()
case "shuffle_gerudo_fortress_heart_piece":
val = "remove"
case "scarecrow_behavior":
val = this.ScarecrowBehavior.String()
default:
return val, unknown(name)
}
Expand Down Expand Up @@ -256,11 +258,11 @@ func (this *Zootr) Bool(name string) (bool, error) {
case "fast_chests":
val = this.FastChests
case "free_scarecrow":
val = this.Starting.Scarecrow
val = this.ScarecrowBehavior == ScarecrowBehaviorFree
case "plant_beans":
val = this.Starting.PlantBeans
case "easier_fire_arrow_entry":
val = this.Tricks.ShadowFireArrowEntry != 0
val = this.Skills.ShadowFireArrowEntry != 0
case "ruto_already_f1_jabu":
val = this.Skips.RutoAlreadyOnFloor1
case "chicken_count_random":
Expand Down
10 changes: 6 additions & 4 deletions internal/settings/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type Zootr struct {
Entrances EntranceRandomizer
Spawns SpawnSettings
Shuffling Shuffling
Tricks Tricks
Skills Skills
Starting Starting
Skips Skips
Minigames Minigames
Expand All @@ -41,8 +41,10 @@ type Zootr struct {
UsefulCutscenes bool
FastChests bool
NoCollectibleHearts bool
ScarecrowBehavior ScarecrowBehavior
}

type ScarecrowBehavior uint8
type LogicRuleSet uint8
type Medallions uint8

Expand Down Expand Up @@ -110,15 +112,15 @@ type Starting struct {
Hearts uint8
RauruReward bool
Rupees uint16
Scarecrow bool
TimeOfDay StartingTimeOfDay
Tokens []string // ootr uses equip, song and inventory separately
WithConsumables bool
CompleteMaskQuest bool
}

type Tricks struct {
Enabled map[string]bool
type Skills struct {
Tricks map[string]bool
Glitches map[string]bool

ShadowFireArrowEntry uint8
}
Expand Down
19 changes: 19 additions & 0 deletions internal/settings/values.go
Original file line number Diff line number Diff line change
Expand Up @@ -659,3 +659,22 @@ const (
ForestTempleAmyMeg = 1
ForestTempleJoBeth = 2
)

const (
ScarecrowBehaviorDefault ScarecrowBehavior = 0
ScarecrowBehaviorFast = 1
ScarecrowBehaviorFree = 2
)

func (this ScarecrowBehavior) String() string {
switch this {
case ScarecrowBehaviorDefault:
return "vanilla"
case ScarecrowBehaviorFast:
return "fast"
case ScarecrowBehaviorFree:
return "free"
default:
panic(slipup.Createf("unknown scarecrow behavior %x", uint(this)))
}
}
59 changes: 38 additions & 21 deletions magicbean/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package magicbean

import (
"fmt"
"sudonters/libzootr/internal/settings"
"sudonters/libzootr/mido/objects"
"sudonters/libzootr/zecs"
)
Expand All @@ -17,19 +18,20 @@ func ConstBool(b bool) objects.BuiltInFunction {
}

type BuiltIns struct {
CheckTodAccess objects.BuiltInFunction `libzootr:"check_tod_access,params=1"`
Has objects.BuiltInFunction `libzootr:"has,params=2"`
HasAnyOf objects.BuiltInFunction `libzootr:"has_anyof,params=-1"`
HasBottle objects.BuiltInFunction `libzootr:"has_bottle,params=0"`
HasDungeonRewards objects.BuiltInFunction `libzootr:"has_dungeon_rewards,params=1"`
HasEvery objects.BuiltInFunction `libzootr:"has_every,params=-1"`
HasHearts objects.BuiltInFunction `libzootr:"has_hearts,params=1"`
HasMedallions objects.BuiltInFunction `libzootr:"has_medallions,params=1"`
HasNotesForSong objects.BuiltInFunction `libzootr:"has_notes_for_song,params=1"`
HasStones objects.BuiltInFunction `libzootr:"has_stones,params=1"`
IsAdult objects.BuiltInFunction `libzootr:"is_adult,params=0"`
IsChild objects.BuiltInFunction `libzootr:"is_child,params=0"`
IsStartingAge objects.BuiltInFunction `libzootr:"is_starting_age,params=0"`
CheckTodAccess objects.BuiltInFunction `libzootr:"check_tod_access,params=1"`
Has objects.BuiltInFunction `libzootr:"has,params=2"`
HasAnyOf objects.BuiltInFunction `libzootr:"has_anyof,params=-1"`
HasBottle objects.BuiltInFunction `libzootr:"has_bottle,params=0"`
HasDungeonRewards objects.BuiltInFunction `libzootr:"has_dungeon_rewards,params=1"`
HasEvery objects.BuiltInFunction `libzootr:"has_every,params=-1"`
HasHearts objects.BuiltInFunction `libzootr:"has_hearts,params=1"`
HasMedallions objects.BuiltInFunction `libzootr:"has_medallions,params=1"`
HasNotesForSong objects.BuiltInFunction `libzootr:"has_notes_for_song,params=1"`
HasStones objects.BuiltInFunction `libzootr:"has_stones,params=1"`
IsAdult objects.BuiltInFunction `libzootr:"is_adult,params=0"`
IsChild objects.BuiltInFunction `libzootr:"is_child,params=0"`
IsStartingAge objects.BuiltInFunction `libzootr:"is_starting_age,params=0"`
NeedsHeartForDamageMult objects.BuiltInFunction `libzootr:"needs_hearts_for_damage_multipler,params=3"`
}

func (this BuiltIns) Table() objects.BuiltInFunctions {
Expand All @@ -47,6 +49,7 @@ func (this BuiltIns) Table() objects.BuiltInFunctions {
this.IsAdult,
this.IsChild,
this.IsStartingAge,
this.NeedsHeartForDamageMult,
}
}

Expand All @@ -65,16 +68,11 @@ func CreateBuiltInDefs() []objects.BuiltInFunctionDef {
{Name: "is_adult", Params: 0},
{Name: "is_child", Params: 0},
{Name: "is_starting_age", Params: 0},
{Name: "needs_hearts_for_damage_multipler", Params: 1},
}
}

type ShuffleFlags uint64

const (
SHUFFLE_OCARINA_NOTES = 1
)

func CreateBuiltInHasFuncs(builtins *BuiltIns, pocket *Pocket, flags ShuffleFlags) {
func CreateBuiltInHasFuncs(builtins *BuiltIns, pocket *Pocket, zootrSettings *settings.Zootr) {
builtins.Has = func(tbl *objects.Table, args []objects.Object) (objects.Object, error) {
if len(args) != 2 {
return objects.Null, fmt.Errorf("has expects 2 arguments, got %d", len(args))
Expand Down Expand Up @@ -132,7 +130,26 @@ func CreateBuiltInHasFuncs(builtins *BuiltIns, pocket *Pocket, flags ShuffleFlag
return objects.PackBool(pocket.HasMedallions(qty)), nil
}

if flags&SHUFFLE_OCARINA_NOTES == SHUFFLE_OCARINA_NOTES {
builtins.NeedsHeartForDamageMult = func(tbl *objects.Table, args []objects.Object) (objects.Object, error) {
canLive := func(hearts float64) bool {
switch zootrSettings.Damage.Multiplier {
case settings.DamageMultiplierQuad:
return hearts < 0.75
case settings.DamageMultiplierDouble:
return hearts < 1.5
case settings.DamageMultiplierNormal:
return hearts < 3
case settings.DamageMultiplierHalf:
return hearts < 6
default:
return false
}
}

return objects.PackBool(canLive(objects.UnpackF64(args[0]))), nil
}

if zootrSettings.Shuffling.OcarinaNotes {
builtins.HasNotesForSong = func(_ *objects.Table, args []objects.Object) (objects.Object, error) {
ptr := objects.UnpackPtr32(args[0])
return objects.PackBool(pocket.HasAllNotes(zecs.Entity(ptr.Addr))), nil
Expand Down
11 changes: 10 additions & 1 deletion mido/ast/lower.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ var (
)

const (
isTrickEnabledPrefix = "logic_"
isTrickEnabledPrefix = "logic_"
isAdvTrickEnabledPrefix = "adv_"
isGlitchEnabledPrefix = "glitch_"
)

type CouldNotLowerTree struct {
Expand Down Expand Up @@ -108,6 +110,13 @@ func Lower(tbl *symbols.Table, node ruleparser.Tree) (Node, error) {
return createCall(tbl, "is_trick_enabled", ruleparser.StringLiteral(trimmed))
}
}
if trimmed, didTrim := strings.CutPrefix(node.Value, isAdvTrickEnabledPrefix); didTrim {
return createCall(tbl, "is_trick_enabled", ruleparser.StringLiteral(trimmed))
}
if trimmed, didTrim := strings.CutPrefix(node.Value, isGlitchEnabledPrefix); didTrim {
return createCall(tbl, "is_glitch_enabled", ruleparser.StringLiteral(trimmed))
}

symbol := tbl.Declare(node.Value, symbols.UNKNOWN)
return IdentifierFrom(symbol), nil
case *ruleparser.Literal:
Expand Down