package game import ( "fmt" "math/rand" "thehouseoficarus/internal/action" "thehouseoficarus/internal/engine" "thehouseoficarus/internal/net" "thehouseoficarus/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 }