Surprise! We've been running on hardware provided by BuyVM for a few months and wanted to show them a little appreciation.
Running a paste site comes with unique challenges, ones that aren't always obvious and hard to control. As such, BuyVM offered us a home where we could worry less about the hosting side of things and focus on maintaining a clean and useful service! Go check them out and show them some love!
Submitted on December 2, 2020 at 11:44 PM

New Paste 1 (Crystal)

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