issue-3: add unified biolog quest system

This commit is contained in:
server
2026-04-16 17:14:10 +02:00
parent 2179c46ce0
commit 6bf5769199
2 changed files with 420 additions and 11 deletions

View File

@@ -0,0 +1,419 @@
quest biolog_system begin
state start begin
function get_duration()
return 60 * 60 * 24 * 365 * 60
end
function get_npc_vnum()
return 20084
end
function get_stage_count()
return 9
end
function get_stages()
local stages = {}
stages[1] = {
level = 30,
item_vnum = 30006,
item_count = 10,
drop_pct = 20,
reward_apply = apply.MOV_SPEED,
reward_value = 10,
reward_text = "Movement speed +10",
mobs = { 601, },
}
stages[2] = {
level = 40,
item_vnum = 30047,
item_count = 15,
drop_pct = 15,
reward_apply = apply.CAST_SPEED,
reward_value = 10,
reward_text = "Casting speed +10",
mobs = { 731, 732, 733, 734, 735, 736, 737, 701, 702, 703, 704, 705, 706, 707, },
}
stages[3] = {
level = 50,
item_vnum = 30015,
item_count = 20,
drop_pct = 12,
reward_apply = apply.DEF_GRADE_BONUS,
reward_value = 60,
reward_text = "Defense +60",
mobs = { 901, 902, 903, 904, 905, 906, 907, },
}
stages[4] = {
level = 60,
item_vnum = 30050,
item_count = 20,
drop_pct = 10,
reward_apply = apply.INT,
reward_value = 10,
reward_text = "INT +10",
mobs = { 1101, 1102, 1103, 1104, 1105, 1106, 1107, },
}
stages[5] = {
level = 70,
item_vnum = 30165,
item_count = 25,
drop_pct = 10,
reward_apply = apply.STR,
reward_value = 10,
reward_text = "STR +10",
mobs = { 2301, 2302, 2303, 2304, 2305, 2311, 2312, 2313, 2314, 2315, },
}
stages[6] = {
level = 80,
item_vnum = 30166,
item_count = 30,
drop_pct = 8,
reward_apply = apply.CRITICAL_PCT,
reward_value = 10,
reward_text = "Critical chance +10%",
mobs = { 1401, 1402, 1403, 1601, 1602, 1603, },
}
stages[7] = {
level = 85,
item_vnum = 30167,
item_count = 30,
drop_pct = 6,
reward_apply = apply.PENETRATE_PCT,
reward_value = 10,
reward_text = "Piercing chance +10%",
mobs = { 2311, 2312, 2313, 2314, 2315, },
}
stages[8] = {
level = 92,
item_vnum = 30251,
item_count = 40,
drop_pct = 5,
reward_apply = apply.RESIST_MAGIC,
reward_value = 10,
reward_text = "Magic resistance +10%",
mobs = { 1135, 1137, },
}
stages[9] = {
level = 94,
item_vnum = 30252,
item_count = 40,
drop_pct = 4,
reward_apply = apply.DEF_GRADE_BONUS,
reward_value = 10,
reward_text = "Defense +10",
mobs = { 2412, 2414, },
}
return stages
end
function get_stage(stage_index)
return biolog_system.get_stages()[stage_index]
end
function get_completed_stage_count()
local stage = pc.getqf("biolog_stage")
if stage <= 1 then
return 0
end
if stage > biolog_system.get_stage_count() then
return biolog_system.get_stage_count()
end
return stage - 1
end
function is_complete()
return pc.getqf("biolog_stage") > biolog_system.get_stage_count()
end
function ensure_started()
if pc.getqf("biolog_stage") == 0 and pc.get_level() >= biolog_system.get_stage(1).level then
pc.setqf("biolog_stage", 1)
pc.setqf("biolog_submitted", 0)
pc.setqf("biolog_timer", 0)
end
end
function remove_reward(stage)
affect.remove_collect(stage.reward_apply, stage.reward_value)
end
function add_reward(stage)
affect.add_collect(stage.reward_apply, stage.reward_value, biolog_system.get_duration())
end
function sync_rewards()
local stages = biolog_system.get_stages()
for stage_index = 1, biolog_system.get_stage_count() do
biolog_system.remove_reward(stages[stage_index])
end
local completed = biolog_system.get_completed_stage_count()
for stage_index = 1, completed do
biolog_system.add_reward(stages[stage_index])
end
end
function get_status_text()
if pc.getqf("biolog_stage") == 0 then
return "Reach level 30 to unlock the first biolog stage."
end
if biolog_system.is_complete() then
return "All biolog stages are complete."
end
local stage_index = pc.getqf("biolog_stage")
local stage = biolog_system.get_stage(stage_index)
local submitted = pc.getqf("biolog_submitted")
local remaining = stage.item_count - submitted
local cooldown = pc.getqf("biolog_timer") - get_time()
if cooldown < 0 then
cooldown = 0
end
local text = string.format(
"Stage %d requires %d more x %s. Reward: %s.",
stage_index,
remaining,
item_name(stage.item_vnum),
stage.reward_text
)
if cooldown > 0 then
text = text .. string.format(" Cooldown remaining: %d:%02d:%02d.", math.floor(cooldown / 3600), math.floor(cooldown / 60) % 60, cooldown % 60)
end
return text
end
function refresh_tracker()
if pc.getqf("biolog_stage") == 0 or biolog_system.is_complete() then
clear_letter()
q.done()
return
end
local stage_index = pc.getqf("biolog_stage")
local stage = biolog_system.get_stage(stage_index)
local submitted = pc.getqf("biolog_submitted")
local remaining = stage.item_count - submitted
local cooldown = pc.getqf("biolog_timer") - get_time()
send_letter("Biolog Research")
q.set_title(string.format("Biolog Stage %d", stage_index))
q.set_counter_name(item_name(stage.item_vnum))
q.set_counter_value(remaining)
if cooldown > 0 then
q.set_clock("Cooldown", cooldown)
else
q.set_clock_name("")
end
q.start()
end
function can_submit()
if pc.getqf("biolog_stage") == 0 then
return false, "The biolog quest has not unlocked yet."
end
if biolog_system.is_complete() then
return false, "You already completed all biolog stages."
end
local stage = biolog_system.get_stage(pc.getqf("biolog_stage"))
if pc.get_level() < stage.level then
return false, string.format("Stage %d unlocks at level %d.", pc.getqf("biolog_stage"), stage.level)
end
if pc.getqf("biolog_timer") > get_time() then
return false, "The biolog is still analyzing your previous sample."
end
if pc.count_item(stage.item_vnum) <= 0 then
return false, string.format("You need %s before you can submit.", item_name(stage.item_vnum))
end
return true, ""
end
function complete_stage(stage_index)
local stage = biolog_system.get_stage(stage_index)
biolog_system.add_reward(stage)
local next_stage = stage_index + 1
pc.setqf("biolog_stage", next_stage)
pc.setqf("biolog_submitted", 0)
pc.setqf("biolog_timer", 0)
say_title("Biolog Research")
say(string.format("Stage %d is complete.", stage_index))
say_reward(stage.reward_text)
if next_stage > biolog_system.get_stage_count() then
say("")
say("You completed every biolog stage.")
else
local next_data = biolog_system.get_stage(next_stage)
say("")
say(string.format("Stage %d unlocks at level %d and needs %d x %s.",
next_stage,
next_data.level,
next_data.item_count,
item_name(next_data.item_vnum)))
end
end
function submit_sample()
local can_submit, reason = biolog_system.can_submit()
if not can_submit then
say_title("Biolog Research")
say(reason)
return false
end
local stage_index = pc.getqf("biolog_stage")
local stage = biolog_system.get_stage(stage_index)
pc.remove_item(stage.item_vnum, 1)
pc.setqf("biolog_submitted", pc.getqf("biolog_submitted") + 1)
if not is_test_server() then
pc.setqf("biolog_timer", get_time() + 60 * 60 * 22)
else
pc.setqf("biolog_timer", 0)
end
local submitted = pc.getqf("biolog_submitted")
if submitted >= stage.item_count then
biolog_system.complete_stage(stage_index)
else
say_title("Biolog Research")
say(string.format(
"Sample accepted. Progress: %d / %d.",
submitted,
stage.item_count
))
if pc.getqf("biolog_timer") > get_time() then
local cooldown = pc.getqf("biolog_timer") - get_time()
say(string.format("Next sample in %d:%02d:%02d.", math.floor(cooldown / 3600), math.floor(cooldown / 60) % 60, cooldown % 60))
end
end
biolog_system.refresh_tracker()
return true
end
function is_target_mob(stage_index, race)
local stage = biolog_system.get_stage(stage_index)
if not stage then
return false
end
for _, mob_vnum in ipairs(stage.mobs) do
if mob_vnum == race then
return true
end
end
return false
end
function give_drop()
if pc.getqf("biolog_stage") == 0 or biolog_system.is_complete() then
return
end
local stage_index = pc.getqf("biolog_stage")
local stage = biolog_system.get_stage(stage_index)
if pc.get_level() < stage.level then
return
end
local progress = pc.getqf("biolog_submitted") + pc.count_item(stage.item_vnum)
if progress >= stage.item_count then
return
end
if is_test_server() or number(1, 100) <= stage.drop_pct then
pc.give_item2(stage.item_vnum, 1)
end
end
when login or enter or levelup begin
biolog_system.ensure_started()
biolog_system.sync_rewards()
biolog_system.refresh_tracker()
end
when letter begin
biolog_system.refresh_tracker()
end
when button or info begin
say_title("Biolog Research")
say(biolog_system.get_status_text())
say("")
if not biolog_system.is_complete() then
local stage = biolog_system.get_stage(pc.getqf("biolog_stage"))
say_item_vnum(stage.item_vnum)
say_reward(string.format("Submitted: %d / %d", pc.getqf("biolog_submitted"), stage.item_count))
end
end
when 20084.chat."Biolog Research" begin
say_title("Biolog Research")
say(biolog_system.get_status_text())
say("")
if not biolog_system.is_complete() and pc.getqf("biolog_stage") > 0 then
local stage = biolog_system.get_stage(pc.getqf("biolog_stage"))
say_item_vnum(stage.item_vnum)
say_reward(string.format("Submitted: %d / %d", pc.getqf("biolog_submitted"), stage.item_count))
say_reward(string.format("Inventory: %d x %s", pc.count_item(stage.item_vnum), item_name(stage.item_vnum)))
say("")
local submit = select("Submit sample", "Close")
if submit == 1 then
biolog_system.submit_sample()
end
end
end
when 20084.chat."GM: Skip biolog cooldown" with pc.is_gm() begin
pc.setqf("biolog_timer", 0)
say_title("Biolog Research")
say("Cooldown cleared.")
biolog_system.refresh_tracker()
end
when kill begin
if pc.getqf("biolog_stage") == 0 or biolog_system.is_complete() then
return
end
if biolog_system.is_target_mob(pc.getqf("biolog_stage"), npc.get_race()) then
biolog_system.give_drop()
end
end
end
end

View File

@@ -37,7 +37,6 @@ dragon_lair.quest
ride_mount_change.quest
ride.quest
heavens_cave_escape.quest
check_collect_reward.quest
heavens_cave_keyquest.quest
arena_manager.quest
blacksmith.quest
@@ -53,16 +52,7 @@ collect_herb_lv20.quest
collect_herb_lv25.quest
collect_herb_lv4.quest
collect_herb_lv7.quest
collect_quest_lv30.quest
collect_quest_lv40.quest
collect_quest_lv50.quest
collect_quest_lv60.quest
collect_quest_lv70.quest
collect_quest_lv80.quest
collect_quest_lv85.quest
collect_quest_lv90.quest
collect_quest_lv92.quest
collect_quest_lv94.quest
biolog_system.quest
couple_ring.quest
cube.quest
deviltower_zone.quest