diff --git a/src/core/game3/encounter_rules/frlg.lua b/src/core/game3/encounter_rules/frlg.lua index 9dd96886..d8fe6323 100644 --- a/src/core/game3/encounter_rules/frlg.lua +++ b/src/core/game3/encounter_rules/frlg.lua @@ -263,6 +263,26 @@ function Encounters.rollWater(mapId, enterFromOther) return roll_area(mapId, "water", WATER_WEIGHTS, enterFromOther, 15) end +-- pokefirered/src/wild_encounter.c:464 +function Encounters.rollSweetScent(mapId, terrain) + Encounters.ensureLoaded() + local water = terrain == "water" + local t = table_for(mapId) + local area = water and normalize_area(t and t.water, 15) + or normalize_area(t and (t.land or t.grass), nil) + local okR, Roamer = pcall(require, "src.core.game3.roamer") + if okR and Roamer and Roamer.tryEncounter then + local okRt, Runtime = pcall(require, "src.core.game3.runtime") + local session = okRt and Runtime and Runtime.getSession and Runtime.getSession() + local roamerEnc = Roamer.tryEncounter(session, mapId, water and "water" or "land") + if roamerEnc then return roamerEnc end + end + if not area or #area.slots == 0 then return nil end + local entry = pick_slot(area.slots, water and WATER_WEIGHTS or LAND_WEIGHTS) + if type(entry) ~= "table" then return nil end + return { species = entry.species or entry[1], level = level_of(entry), item = entry.item } +end + --- pokefirered/src/wild_encounter.c:446 function Encounters.rollRocks(mapId) Encounters.ensureLoaded() diff --git a/src/core/game3/encounter_rules/rse.lua b/src/core/game3/encounter_rules/rse.lua index 0055d779..731cc845 100644 --- a/src/core/game3/encounter_rules/rse.lua +++ b/src/core/game3/encounter_rules/rse.lua @@ -456,6 +456,48 @@ function M.bind(E, H) return try_generate(area, "water", true, true) end + -- pokeemerald/src/wild_encounter.c:704 + function R.sweetScentFacility(mapId) + for _, f in ipairs({ + { "src.core.game3.rse.frontier.pike", "WILD_ROOM" }, + { "src.core.game3.rse.frontier.pyramid", "FLOOR_MAP" }, + }) do + local F = package.loaded[f[1]] + if F and mapId == F[f[2]] then + local sess = require("src.core.game3.rse.init").session() + return sess ~= nil and F.sweetScentWildEncounter(sess) == true + end + end + return nil + end + + -- pokeemerald/src/wild_encounter.c:697 + function R.rollSweetScent(mapId, terrain) + E.ensureLoaded() + local t = H.table_for(mapId) + local water = terrain == "water" + local area + if water then + if sootopolis_blocks(mapId) then return nil end + area = H.normalize_area(t and t.water, 15) + else + area = land_area(t) + end + if not area or #area.slots == 0 then return nil end + local s = session() + if s and type(s.roamer) == "table" and s.roamer.active then + local okR, Roamer = pcall(require, "src.core.game3.roamer") + local enc = okR and Roamer and Roamer.tryEncounter and Roamer.tryEncounter(s, mapId, water and "water" or "land") + if enc then return enc end + end + if not water then + local o = outbreak_test(mapId) + local enc = o and outbreak_mon(o, false) + if enc then return enc end + end + return try_generate(area, water and "water" or "land", false, false) + end + -- pokeemerald/src/wild_encounter.c:668 function R.rollRocks(mapId) E.ensureLoaded() diff --git a/src/core/game3/encounters.lua b/src/core/game3/encounters.lua index b8508cc4..00f02001 100644 --- a/src/core/game3/encounters.lua +++ b/src/core/game3/encounters.lua @@ -397,7 +397,7 @@ Encounters.rules = rules for _, name in ipairs({ "mapBaseCooldown", "cooldownMinSteps", "handleCooldown", "resetRateModifiers", - "encounterRate", "rollLand", "rollWater", "rollRocks", "hasFishingMons", "rollFishing", + "encounterRate", "rollLand", "rollWater", "rollRocks", "rollSweetScent", "sweetScentFacility", "hasFishingMons", "rollFishing", }) do Encounters[name] = function(...) local f = rules()[name] diff --git a/src/core/game3/field.lua b/src/core/game3/field.lua index 5cc0bfac..0c93b291 100644 --- a/src/core/game3/field.lua +++ b/src/core/game3/field.lua @@ -1428,15 +1428,46 @@ function Field.executeFieldMove(payload) if payload.se then Audio.playSe(payload.se) end FieldEffects.startSweetScent(function() Field.locked = false - local okE, Encounters = pcall(lazyReq, "src.core.game3.encounters") - if okE and Encounters and Encounters.tryBattle then - Encounters.tryBattle(Field._game, true) - end + Field.finishSweetScent(payload) end) end) end end +-- pokefirered/src/fldeff_sweetscent.c:62 +function Field.finishSweetScent(payload) + local Encounters = lazyReq("src.core.game3.encounters") + local Runtime = package.loaded["src.core.game3.runtime"] + local session = Field._session + local mapId = session and session.map + if not mapId then + local Map = package.loaded["src.core.game3.map"] + mapId = Map and Map.current + end + local rules = Encounters.rules() + if rules.sweetScentFacility then + local handled = rules.sweetScentFacility(mapId) + if handled == true then return end + if handled == false then + if not payload.failText then return end + local Message = lazyReq("src.ui.game3.message") + Message.show(RomText.box(payload.failText), { session = session, done = function() Message.close() end }) + return + end + end + local terrain = Encounters.terrainAt(Player.cellX, Player.cellY) + local enc = (terrain == "land" or terrain == "water") and Encounters.rollSweetScent(mapId, terrain) or nil + if enc then + local BattleBridge = lazyReq("src.core.game3.battle_bridge") + local ok, err = BattleBridge.startWild(Runtime and Runtime._mod, Field._game, enc, {}) + if ok then return end + print("[game3/field] sweet scent startWild failed: " .. tostring(err)) + end + if not payload.failText then return end + local Message = lazyReq("src.ui.game3.message") + Message.show(RomText.box(payload.failText), { session = session, done = function() Message.close() end }) +end + -- pokefirered/src/wild_encounter.c:446 function Field.tryRockSmashEncounter() local Encounters = lazyReq("src.core.game3.encounters") diff --git a/src/core/game3/rse/frontier/pike.lua b/src/core/game3/rse/frontier/pike.lua index f1dbf1bc..dcaa07fb 100644 --- a/src/core/game3/rse/frontier/pike.lua +++ b/src/core/game3/rse/frontier/pike.lua @@ -500,6 +500,19 @@ function Pike.standardWildEncounter(sess, cur, prev) return Pike.tryGenerateWildMon(sess, enc, true) end +-- pokeemerald/src/wild_encounter.c:706 +function Pike.sweetScentWildEncounter(sess) + local R = encounterRules() + local header = Pike.manifest().wildHeaders[Pike.wildMonHeaderId(sess) + 1] + local land = header and header.land + if not land then return false end + local enc = R.tryGenerate(land, "land", false, false) + if not enc then return false end + enc = Pike.tryGenerateWildMon(sess, enc, false) + if not enc then return false end + return Pike.startWildBattle(sess, enc) ~= false +end + -- pokeemerald/src/battle_setup.c:445 function Pike.startWildBattle(sess, enc) local Runtime = package.loaded["src.core.game3.runtime"] diff --git a/src/core/game3/rse/frontier/pyramid.lua b/src/core/game3/rse/frontier/pyramid.lua index 0a34c4de..17279dd8 100644 --- a/src/core/game3/rse/frontier/pyramid.lua +++ b/src/core/game3/rse/frontier/pyramid.lua @@ -1294,6 +1294,19 @@ function Pyramid.standardWildEncounter(sess, cur, prev) return Pyramid.generateWildMon(sess, enc) end +-- pokeemerald/src/wild_encounter.c:716 +function Pyramid.sweetScentWildEncounter(sess) + local Encounters = require("src.core.game3.encounters") + local header = wildHeader(sess) + local land = header and header.land + if not land then return false end + local enc = Encounters.rules().tryGenerate(land, "land", false, false) + if not enc then return false end + enc = Pyramid.generateWildMon(sess, enc) + if not enc then return false end + return Pyramid.startWildBattle(sess, enc) ~= false +end + -- pokeemerald/src/battle_setup.c:402 function Pyramid.startWildBattle(sess, enc) local Runtime = package.loaded["src.core.game3.runtime"]