123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
class Quest
property current_talk_to_list = Array(Int32).new
property current_kill_amount = 0
property date_accepted = 0_i64
JSON.mapping(
current_talk_to_list: Array(Int32),
current_kill_amount: Int32,
date_accepted: Int64
)
def initialize(quest_id, current_talk_to_list2 = "", current_kill_amount2 = 0, @date_accepted = Time.local.to_unix_ms)
return unless quest_obj = Quests[quest_id]?
if quest_obj.quest_type == "talk_to"
@current_talk_to_list = current_talk_to_list2.split(";").map &.to_i if current_talk_to_list2.size > 0
end
@current_kill_amount = current_kill_amount2
# pp "Creating a quest object for the quest: #{quest_obj}"
# pp self
end
end
class GameServer
def handle_quest_interact(msg, client)
a = msg["message"]["a"].as_i
# Accepting a Quest
if a == 0
quest_id = msg["message"]["qid"].as_i
return unless c_quest_obj = Quests[quest_id]
return unless main_quest_obj = Quests[quest_id]
raise "You already have this quest." if client.active_quests[quest_id]?
raise "You already completed this quest!" if client.completed_quests.includes? quest_id
raise "You don't have the required quest(s) for this quest." if (main_quest_obj.required_quests - client.completed_quests).size != 0
client.active_quests[quest_id] = Quest.new(quest_id)
db.exec "insert into rpg_quest_tracker (character_id, quest_id, date_accepted) values (?, ?, ?)", client.selected_characterid, quest_id, Time.local.to_unix_ms
# tell them..
client.send ({quest_id: quest_id, a: 0, data: client.active_quests[quest_id]}), "QUEST"
if c_quest_obj.quest_type == "first_galactic"
# spawn first galactic portal for this player
pp "hez"
end
end
# Abandoning a quest
if a == 1
quest_id = msg["message"]["qid"].as_i
return unless c_quest_obj = Quests[quest_id]
raise "You can't abandon a quest you don't have?" if !client.completed_quests.includes? quest_id
client.send ({quest_id: quest_id, a: 1}), "QUEST"
end
if a == 3 # clicking on quest reward item
quest_id = msg["message"]["qid"].as_i
raise "Invalid quest id." unless main_quest_obj = Quests[quest_id]?
x = msg["message"]["x"].as_i
y = msg["message"]["y"].as_i
raise "You don't have this quest active." if !client.completed_quests.includes? quest_id
raise "You already received the rewards for this quest." if client.completed_quests.count(quest_id) == 2
client.completed_quests << quest_id
update_rpg_db_character(client)
mods = QueryUpdate.new
mods["pos"] = "#{x}x#{y}"
new_duped_item = generate_item_by_id(main_quest_obj.quest_rewards.first, mods).to_a
item_query = item_to_mysql_insert_query(new_duped_item, client)
result = db.exec(item_query)
new_duped_item[0] = result.last_insert_id
client.stash[0].items[result.last_insert_id] = ItemTuple.from(new_duped_item)
client.send ({a: 5, quest_id: quest_id, x: x, y: y, item: new_duped_item, new_itemid: 12345}), "QUEST"
end
# Talking to NPC
if a == 2
incoming_npc_id = msg["message"]["npc_id"].as_i
return unless npc_obj = NPCS[incoming_npc_id]?
# Does this user have any quests where they need to talk to a specific npc?
if client.active_quests.size > 0
client.active_quests.each do |quest_id, quest_obj|
main_quest_obj = Quests[quest_id]
# Does this player have any quest item ids that this quest object needs?
if main_quest_obj.required_itemids.size > 0
client.stash[0].items.each do |k, v|
i_item_id = v[1]
if main_quest_obj.required_itemids.includes? i_item_id
handle_quest_completion(client, main_quest_obj, quest_id)
client.stash[0].items.delete k # no item anymore
db.exec "delete from rpg_user_items where itemid = ? and user_id = ?", k, client.user_id
client.send ({a: 6, q: 0, itemid: k}), "ITEMUPDATE"
break
end
end
end
if main_quest_obj.quest_type == "talk_to"
# They talked to a NPC!
if !quest_obj.current_talk_to_list.includes? npc_obj.npc_id
quest_obj.current_talk_to_list << npc_obj.npc_id
db.exec "update rpg_quest_tracker set current_talk_to_list = ? where character_id = ?", quest_obj.current_talk_to_list.join(";"), client.selected_characterid
client.send ({a: 2, quest_id: quest_id, data: quest_obj.current_talk_to_list}), "QUEST"
pp "You have talked to this NPC!"
# Have they completed the talk to quest?
# 3 = QuestCompleted.
main_talk_to_list = main_quest_obj.talk_to_list.split(";").map &.to_i
if (main_talk_to_list - quest_obj.current_talk_to_list).empty?
handle_quest_completion(client, main_quest_obj, quest_id)
end
end
end
end
end
end
rescue e
client.send e.message, "E"
end
# When a player loads into the gameserver, we need to update the active_quests hash with current quests
def update_rpg_quest_tracker(client)
results = db.query_all "select quest_id, current_talk_to_list, current_kill_amount, date_accepted from rpg_quest_tracker where character_id = ?", client.selected_characterid, as: {Int32, String, Int32, Int64}
results.each do |obj|
quest_id, current_talk_to_list, current_kill_amount, date_accepted = obj
# append the active quests this user has..
client.active_quests[quest_id] = Quest.new(quest_id, current_talk_to_list, current_kill_amount, date_accepted)
end
end
def handle_quest_item_must_be_looted(item_id, client)
client.active_quests.each do |quest_id, quest_obj|
next unless main_quest_obj = Quests[quest_id]
case main_quest_obj.quest_type
when "item_must_be_looted"
if main_quest_obj.items_to_drop.includes? item_id # it's complete!
handle_quest_completion(client, main_quest_obj, quest_id)
end
end
end
end
# Quest Completion and rewards...
# quest_rewards should be a delimited list (;) of the item ids.
def handle_quest_completion(client, main_quest_obj, quest_id, item_x = nil, item_y = nil)
client.completed_quests << quest_id
client.active_quests.delete quest_id
return unless zone = client.in_zone_obj
item_x = client.x if !item_x
item_y = client.y if !item_y
db.exec "update rpg_characters set completed_quests = ? where character_id = ?", client.completed_quests.join(";"), client.selected_characterid
db.exec "delete from rpg_quest_tracker where quest_id = ? and character_id = ?", quest_id, client.selected_characterid
client.send ({a: 3, quest_id: quest_id}), "QUEST"
# Special Quests.. first galactic?
if (quest_id == 11)
zone.galactic_device = GalacticDevice.new(zone.level_info.galactic_device_pos.x, zone.level_info.galactic_device_pos.y)
if galactic_device = zone.galactic_device
zone.send_to_players ({scene_name: "galactic_device", cdata: "", x: galactic_device.x, y: galactic_device.y}), "ENTITY_U"
end
end
# Does the quest give any experience?
give_exp(client, main_quest_obj.quest_exp)
# Does this quest have any rewards?
if quest_id == 8 # take a look around. Special case. Scroll of Wisdom and a rare/magic short axe
if scroll_of_wisdom = generate_item_by_id(42)
zone.drop_item(scroll_of_wisdom, item_x, item_y)
end
mods = QueryUpdate.new
mod_rolls = Array(String).new
current_mod_count = 2
mod_rolls << select_random_weapon_prefix.mod_type
mod_rolls << select_random_weapon_suffix.mod_type
if rand < (0.5)
# roll for a rare?
mod_rolls << (ModGlobalWeapons.shuffle - mod_rolls).first
current_mod_count += 1
end
mods["identified"] = 0
mods["rare_name"] = generate_rare_name("Weapons") if current_mod_count > 2
mod_rolls.each do |mod_key|
mod_struct = GlobalItemModsMapping[mod_key].select { |v| rand < v.mod_chance }.last
final_roll_value = rand(mod_struct.min_value..mod_struct.max_value)
mods[mod_struct.mod_type] = final_roll_value
end
if short_axe = generate_item_by_id(40, mods)
zone.drop_item(short_axe, item_x, item_y)
end
else
if main_quest_obj.must_talk_to_receive_reward == 0
main_quest_obj.quest_rewards.each do |item_id|
if item = generate_item_by_id(item_id)
drop_generated_item(client, item, item_x, item_y)
end
end
end
end
rescue e
pp "Error Handling Quest Completion:"
pp e
end
end