diff options
Diffstat (limited to 'internal/game/action_cook.go')
| -rw-r--r-- | internal/game/action_cook.go | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/internal/game/action_cook.go b/internal/game/action_cook.go new file mode 100644 index 0000000..e4d2597 --- /dev/null +++ b/internal/game/action_cook.go @@ -0,0 +1,153 @@ +package game + +import ( + "fmt" + "math/rand" + + "thirdcollapse/internal/action" + "thirdcollapse/internal/engine" + "thirdcollapse/internal/net" + "thirdcollapse/internal/player" +) + +func (g *Game) startCook(sess *net.Session, p *player.Player, recipe *action.RecipeDef, stationName string) { + g.CancelAction(p) + + if recipe.Skill != "" { + skillLevel := p.Level(player.SkillName(recipe.Skill)) + if skillLevel < recipe.Level { + sess.WriteLine(fmt.Sprintf("You need level %d %s to cook that.", recipe.Level, recipe.Skill)) + return + } + } + + if !recipe.HasAllItems(p.HasItem) { + sess.WriteLine("You don't have the required ingredients.") + return + } + + wait := recipe.Wait + if wait <= 0 { + wait = 6 + } + + p.Action = &action.Action{ + Type: "cook", + TargetID: recipe.ID, + TargetName: recipe.DisplayName(), + Data: map[string]any{ + "recipe_id": recipe.ID, + "station_name": stationName, + "phase": 0, + "wait": wait, + }, + WaitLeft: engine.ToTicks(1), + } + + p.ActionState = &ActionState{Type: ActionCooking, TargetName: recipe.DisplayName()} +} + +func (g *Game) advanceCook(sess *net.Session, p *player.Player) bool { + recipeID := p.Action.Data["recipe_id"].(string) + stationName := p.Action.Data["station_name"].(string) + phase := p.Action.Data["phase"].(int) + wait := p.Action.Data["wait"].(float64) + + all, err := g.RecipeStore.LoadAll() + if err != nil { + g.CancelAction(p) + return false + } + var recipe *action.RecipeDef + for _, r := range all { + if r.ID == recipeID { + recipe = &r + break + } + } + if recipe == nil { + g.CancelAction(p) + return false + } + + if phase == 0 { + firstItem := recipe.FirstItemName(func(id string) (string, bool) { + def, err := g.ItemStore.Load(id) + if err != nil { + return id, false + } + return def.Name, true + }) + p.ActionState = &ActionState{Type: ActionCooking, TargetName: recipe.DisplayName()} + if stationName != "" && stationName != "inventory" && stationName != "ground" { + sess.WriteLine(fmt.Sprintf("\nYou start cooking %s on the %s.", firstItem, stationName)) + } else { + sess.WriteLine(fmt.Sprintf("\nYou start making %s.", recipe.DisplayName())) + } + p.Action.Data["phase"] = 1 + p.Action.WaitLeft = engine.ToTicks(wait) + return true + } + + skillLevel := p.Level(player.SkillName(recipe.Skill)) + chance := 1.0 + if recipe.Success != nil { + chance = action.SuccessChance(*recipe.Success, skillLevel, recipe.Level) + } + + if rand.Float64() < chance { + outputID := recipe.Output + + freeSlot := p.FirstFreeSlot() + if freeSlot == -1 { + sess.WriteLine("Your inventory is too full!") + g.CancelAction(p) + return false + } + + recipe.ConsumeAll(p.HasItem, p.RemoveItem) + p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: outputID, Quantity: 1}) + + if recipe.XP > 0 { + if newLevel := p.AddSkillXP(player.SkillName(recipe.Skill), recipe.XP); newLevel > 0 { + sess.WriteLine(g.colorize(sess, "level_up", fmt.Sprintf("*** You are now level %d %s! ***", newLevel, recipe.Skill))) + } + } + g.AccountStore.SaveCharacter(p) + + msg := recipe.Message + if msg == "" { + msg = fmt.Sprintf("Cooked to perfection. It looks great!") + } + sess.WriteLine(msg) + if p.OptionBool("xp_drops") && recipe.XP > 0 { + abbr := player.SkillAbbr[player.SkillName(recipe.Skill)] + sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf(" (+%dxp %s)", recipe.XP, abbr))) + } + } else { + recipe.ConsumeAll(p.HasItem, p.RemoveItem) + + if recipe.Fail != "" { + freeSlot := p.FirstFreeSlot() + if freeSlot >= 0 { + p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: recipe.Fail, Quantity: 1}) + } + } + g.AccountStore.SaveCharacter(p) + + msg := recipe.FailMessage + if msg == "" { + msg = "You badly overcook it." + } + sess.WriteLine(msg) + } + + if recipe.HasAllItems(p.HasItem) && p.FirstFreeSlot() >= 0 { + p.Action.Data["phase"] = 1 + p.Action.WaitLeft = engine.ToTicks(wait) + return true + } + + g.CancelAction(p) + return false +} |
