• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Hansiec's Mystery Gift System

1,748
Posts
14
Years
Intro:
Alright, for those of you who don't know I am Ho-oh 112 ok, and I thought to re-make my mystery gift system from scratch making it better in a few places.

The Code:

Code:
=begin
  * Mystery Gift
  
  * By Hansiec
  
  * Allows for the game's host to give out items via the internet
  
  * Gifts supported:
    Eggs
    Pokemon
    Items
    Game Variables
    Game Switches
    
  * TODO:
    Add Badge checks
    Add Mystery Cards (storing 3 gifts by default)
    Add more gift types (script execution support, badge support, ect.)
    Add a GUI (Graphical User Interface)
    Add Menu Support (From the load menu)
    Add Anything worth while from user requests
    
  Although there may only be 1 per gift.
  
  * Full Features:
    Obviously supports gifts of the things above
    Allows for downloaded gifts (if you know what I mean by this)
    No Switches/Variables needed to work this
    Built in Encryption/Mystery Gift Creator
    A Custom Encryption Key (below this commentary) for better safety
    Only 1 gift per person (unless you change the gift)
    Everyone get's the EXACT SAME GIFT right down to the personalID of a pokemon.
    
    
    Do not mistake this for Raptor's Mystery Gift System as this is coded in a
    different manor (Yes this is needed to say as of complaints of my previous
    system)
    
  * Call Methods:
    (Normally you call with MysteryGift.function)
    MysteryGift.create_x (x being egg/pokemon/item/variable/switch/pglobal)
     * This creates a mystery gift code (depending on what you selected)
    MysteryGift.get_gift(url) (url being the url of your gift)
     * This downloads and attempts to give you the selected gift. I have done some
       checks against hacks/double gifts but I most likely missed some.
       
       
  Improvements:
    Added a never to fail pokemon compiler
    Added more features to the eggs
    Added a check if $PokemonGlobal.last_gift exists
    Added a default URL (although you can use something else)
    Added a/an check for the pokemon and it actually displays the correct info.
    Added a confirmation message after making the gift code
    Added a default file to save your gift codes in (MysteryGift.txt)
    Removed the PokemonGlobal option
=end

ENCRYPTION_KEY = "any string here! 0.o o.0 0.0 o.o ??>><<??"
GIFT_DEFAULT_URL = "http://localhost/MysteryGift.txt"

class PokeBattle_Pokemon
=begin
  def to_s
    moves=[]
    for i in 0..3
      if @moves[i] != nil
        moves[i] = [@moves[i].id, @moves[i].ppup]
      else
        moves[i] = [-1, -1]
      end
    end
    ary=[
    @iv[0],
    @iv[1],
    @iv[2],
    @iv[4],
    @iv[5],
    @iv[6],
    @ev[0],
    @ev[1],
    @ev[2],
    @ev[4],
    @ev[5],
    @ev[6],
    @species,
    @personalID,
    @trainerID,
    @pokerus,
    @item,
    @name,
    @exp,
    @happiness,
    @status,
    @statusCount,
    @eggsteps,
    moves[0][0],
    moves[0][1],
    moves[1][0],
    moves[1][1],
    moves[2][0],
    moves[2][1],
    moves[3][0],
    moves[3][1],
    @ballused,
    @obtainMap,
    @obtainLevel,
    @hatchedMap,
    @language,
    @ot,
    @otgender,
    @abilityflag.to_i,
    @genderflag.to_i,
    @natureflag,
    @shinyflag.to_i,
    @cool,
    @beauty,
    @smart,
    @tough,
    @cute,
    @sheen,
    isShadow?.to_i
    ]
    str=""
    for i in ary
      str+=i.to_s+"!@#"
    end
    return str
  end
=end
  def to_s
    save_data(self,"TEMP_FILE")
    f=File.open("TEMP_FILE", 'rb')
    data=""
    data+=f.read while !f.eof?
    f.close
    File.delete("TEMP_FILE")
    return data
  end
end

# The below methods add simple to_i and to_b values for the booleans and fixnums
class TrueClass
  def to_i
    return 1
  end
end

class FalseClass
  def to_i
    return 0
  end
end

class Fixnum
  def to_b
    if self == 1
      ret = true
    else
      ret = false
    end
    return ret
  end
end


# Adds the methods to_mpokemon and crypt to the string class
class String
=begin
  def to_mpokemon
    ary=self.split("!@#")
    ret = PokeBattle_Pokemon.new(1,1)
    for i in 0..ret.iv.length-1
      ret.iv[i]=ary[i].to_i
    end    
    for i in 0..ret.ev.length-1
      ret.ev[i]=ary[i+5].to_i
    end
    ret.species=ary[12].to_i
    ret.personalID=ary[13].to_i
    ret.trainerID=ary[14].to_i
    ret.pokerus=ary[15].to_i
    ret.item=ary[16].to_i
    ret.name=ary[17]
    ret.exp=ary[18].to_i
    ret.happiness=70
    ret.status=ary[20].to_i
    ret.statusCount=ary[21].to_i
    ret.eggsteps=ary[22].to_i
    moves=[[ary[23].to_i,ary[24].to_i],[ary[25].to_i,ary[26].to_i],
    [ary[27].to_i,ary[28].to_i],[ary[29].to_i,ary[30].to_i]]
    ret.ballused=ary[31].to_i
    ret.obtainMode=4 # Fateful Encounter
    ret.obtainMap=ary[32].to_i
    ret.obtainLevel=ary[33].to_i
    ret.hatchedMap=ary[34].to_i
    ret.language=ary[35].to_i
    ret.ot=ary[36]
    ret.otgender=ary[37].to_i
    ret.abilityflag=ary[38].to_i.to_b
    ret.genderflag=ary[39].to_i.to_b
    ret.natureflag=ary[40].to_i
    ret.shinyflag=ary[41].to_i.to_b
    ret.cool=ary[42].to_i
    ret.beauty=ary[43].to_i
    ret.smart=ary[44].to_i
    ret.tough=ary[45].to_i
    ret.cute=ary[46].to_i
    ret.sheen=ary[47].to_i
    ret.makeShadow if ary[48].to_i == 1 || ary[48] == "true"
    for i in 0..moves.length-1
      break if moves[i][0] == -1
      ret.moves[i] = PBMove.new(moves[i][0])
      ret.moves[i].ppup = moves[i][1]
    end
    ret.calcStats
    return ret
  end
=end
  def to_mpokemon
    f=File.open("TEMP_FILE", 'wb')
    f.write(self)
    f.close
    ret=load_data("TEMP_FILE")
    File.delete("TEMP_FILE")
    return ret
  end
  
  def crypt(salt)
    ret=self
    for i in 0..length-1
      ret[i] ^= salt[i%salt.length-1]
    end
    return ret
  end
end

# Inserts the last gift variable to pokemon global so we don't need to use variables
class PokemonGlobalMetadata
  attr_accessor :last_gift
  attr_accessor :mystery_items
  alias init_mystery initialize
  def initialize
    init_mystery
    init_mysterygift
  end
  
  def init_mysterygift
    @last_gift = ""
    @mystery_items = []
  end
end


# Our Mystery gift class
class Mysterygift
  
  # Creates a file (of what you want to name it) with a code for a mystery gift egg
  def create_egg
    species=pbChooseSpeciesOrdered(1)
    dexdata=pbOpenDexData
    pbDexDataOffset(dexdata,getID(PBSpecies,species),21)
    eggsteps=dexdata.fgetw
    dexdata.close
    return if species < 1
    p=PokeBattle_Pokemon.new(species,EGGINITIALLEVEL)
    p.eggsteps = eggsteps
    params=ChooseNumberParams.new
    params.setRange(0,99999)
    params.setDefaultValue(0)
    p.form=Kernel.pbMessageChooseNumber(_INTL("Set the form."),params)
    p.shinyflag = 1 if Kernel.pbMessage(_INTL("Make the pokemon shiny"), ["Shiny", "Not Shiny"], 1) == 0
    p.makeShadow if Kernel.pbMessage(_INTL("Make the pokemon shadow"), ["Shadow", "Not Shadow"], 1) == 0
    p.ballused = $BallTypes[15] # Cherish ball
    p.ot = Kernel.pbMessageFreeText(_INTL("Enter an Owner"), "", false, 10)
    p.name = _INTL("Egg")
    p.item = pbChooseItemList(1)
    id = Kernel.pbMessageFreeText(_INTL("Enter a numer ID"), "", false, 5)
    if id.to_i > 0
      p.trainerID = id
    end
    for i in 0..3
      move = pbChooseMoveList
      p.moves[i] = PBMove.new(move) if move != 0
      p.resetMoves if move == 0 && i == 0
      break if move == 0
    end
    commands=[]
    (PBNatures.getCount).times do |i|
      commands.push(PBNatures.getName(i))
    end
    cmdwin=pbListWindow([],200)
    command=pbCommands2(cmdwin,commands,-1,0,true)
    if command>=0
      p.setNature(command)
      p.calcStats
    end
    g = Kernel.pbMessage(_INTL("Set the pokemon's gender"), ["Male", "Female"], 0)
    p.genderflag = g if p.genderflag != 2
    params=ChooseNumberParams.new
    params.setRange(0,2)
    params.setDefaultValue(0)
    p.abilityflag=Kernel.pbMessageChooseNumber(_INTL("Set ability flag."),params)
    fn=Kernel.pbMessageFreeText(_INTL("Enter a Filename"), "", false, 256)
    fn=fn.split("\r")[0]
    fn = "Mysterygift.txt" if fn == ""
    if fn != ""
      File.open(fn, "wb"){|f|
      f.write(p.to_s.crypt(ENCRYPTION_KEY))
      f.write("\npokemon")
      }
      Kernel.pbMessage(_INTL("Your mystery gift code has been saved in: {1}.", fn))
    end
  end
  
  # Creates a file (of what you want to name it) with a code for a mystery gift pokemon
  def create_pokemon
    species=pbChooseSpeciesOrdered(1)
    return if species < 1
    p=PokeBattle_Pokemon.new(species,1)
    params=ChooseNumberParams.new
    params.setRange(1,PBExperience::MAXLEVEL)
    params.setDefaultValue(0)
    level=Kernel.pbMessageChooseNumber(_INTL("Set the level."),params)
    return if level == 0
    p.level = level
    params=ChooseNumberParams.new
    params.setRange(0,99999)
    params.setDefaultValue(0)
    p.form=Kernel.pbMessageChooseNumber(_INTL("Set the form."),params)
    p.shinyflag = 1 if Kernel.pbMessage(_INTL("Make the pokemon shiny"), ["Shiny", "Not Shiny"], 1) == 0
    p.makeShadow if Kernel.pbMessage(_INTL("Make the pokemon shadow"), ["Shadow", "Not Shadow"], 1) == 0
    p.ballused = $BallTypes[15] # Cherish ball
    p.ot = Kernel.pbMessageFreeText(_INTL("Enter an Owner"), "", false, 256)
    n=Kernel.pbMessageFreeText(_INTL("Enter a nickname"), "", false, 10)
    p.name = n if n != ""
    p.item = pbChooseItemList(1)
    id = Kernel.pbMessageFreeText(_INTL("Enter a numer ID"), "", false, 5)
    if id.to_i > 0
      p.trainerID = id
    end
    for i in 0..3
      move = pbChooseMoveList
      p.moves[i] = PBMove.new(move) if move != 0
      p.resetMoves if move == 0 && i == 0
      break if move == 0
    end
    commands=[]
    (PBNatures.getCount).times do |i|
      commands.push(PBNatures.getName(i))
    end
    cmdwin=pbListWindow([],200)
    command=pbCommands2(cmdwin,commands,-1,0,true)
    if command>=0
      p.setNature(command)
      p.calcStats
    end
    g = Kernel.pbMessage(_INTL("Set the pokemon's gender"), ["Male", "Female"], 0)
    p.genderflag = g if p.genderflag != 2
    params=ChooseNumberParams.new
    params.setRange(0,2)
    params.setDefaultValue(0)
    p.abilityflag=Kernel.pbMessageChooseNumber(_INTL("Set ability flag."),params)
    fn=Kernel.pbMessageFreeText(_INTL("Enter a Filename"), "", false, 256)
    fn=fn.split("\r")[0]
    fn = "Mysterygift.txt" if fn == ""
    if fn != ""
      File.open(fn, "wb"){|f|
      f.write(p.to_s.crypt(ENCRYPTION_KEY))
      f.write("\npokemon")
      }
      Kernel.pbMessage(_INTL("Your mystery gift code has been saved in: {1}.", fn))
    end
  end
  
  # Creates a file (of what you want to name it) with a code for a mystery gift item
  def create_item
    item = pbChooseItemList(1)
    return if item == 0
    fn=Kernel.pbMessageFreeText(_INTL("Enter a Filename"), "", false, 256)
    fn=fn.split("\r")[0]
    fn = "Mysterygift.txt" if fn == ""
    if fn != ""
      f=File.open("#{fn}", "wb")
      f.write([item].to_s.crypt(ENCRYPTION_KEY))
      f.write("\nitem")
      f.close
      Kernel.pbMessage(_INTL("Your mystery gift code has been saved in: {1}.", fn))
    end
  end
  
  
  # Creates a file (of what you want to name it) with a code for a mystery gift variable
  def create_variable
    params=ChooseNumberParams.new
    params.setRange(1,5000)
    params.setDefaultValue(0)
    id=Kernel.pbMessageChooseNumber(_INTL("Select a variable id."),params)
    return if id == 0
    if Kernel.pbMessage(_INTL("Set as a string or an integer"), ["String", "Integer"], 0) == 0
      val = Kernel.pbMessageFreeText(_INTL("Set the variable's value"), "", false, 9999)
    else
      params=ChooseNumberParams.new
      params.setRange(1,999999999)
      params.setDefaultValue(0)
      val=Kernel.pbMessageChooseNumber(_INTL("Set the variable's value."),params)
    end
    fn=Kernel.pbMessageFreeText(_INTL("Enter a Filename"), "", false, 256)
    fn=fn.split("\r")[0]
    fn = "Mysterygift.txt" if fn == ""
    if fn != ""
      f=File.open("#{fn}", "wb")
      v=""
      v="i" if val.is_a?(Numeric)
      f.write("#{id},#{val},#{v}".crypt(ENCRYPTION_KEY))
      f.write("\nvar")
      f.close
      Kernel.pbMessage(_INTL("Your mystery gift code has been saved in: {1}.", fn))
    end
  end
  
  
  # Creates a file (of what you want to name it) with a code for a mystery gift switch
  def create_switch
    params=ChooseNumberParams.new
    params.setRange(1,5000)
    params.setDefaultValue(0)
    id=Kernel.pbMessageChooseNumber(_INTL("Select a switch id."),params)
    val = Kernel.pbConfirmMessage(_INTL("Set the switch's value"), ["True", "False"], 0).to_b
    fn=Kernel.pbMessageFreeText(_INTL("Enter a Filename"), "", false, 256)
    fn=fn.split("\r")[0]
    fn = "Mysterygift.txt" if fn == ""
    if fn != ""
      f=File.open("#{fn}", "wb")
      f.write("#{id},#{val}".crypt(ENCRYPTION_KEY))
      f.write("\swt")
      f.close
      Kernel.pbMessage(_INTL("Your mystery gift code has been saved in: {1}.", fn))
    end
  end
  
  # Actual mystery gift function to call for
  def get_gift(url=GIFT_DEFAULT_URL)
    $PokemonGlobal.init_mysterygift if $PokemonGlobal.last_gift == nil
    string = pbDownloadToString(url)
    if string == ""
      Kernel.pbMessage(_INTL("Unable to connect to the server, cannot get the gift."))
      return false
    end
    if string == $PokemonGlobal.last_gift
      Kernel.pbMessage(_INTL("You have already received this gift!"))
      return false
    end
    data = string.split("\n")
    if data.length > 2
      for i in 0..data.length-2
        data[0]+="\n"+data[i+1]
      end
      data[1]=data[data.length-1]
    end
    if data[1].include?("item")
      #Kernel.pbReceiveItem(data[0].crypt(ENCRYPTION_KEY).to_i)
      $PokemonGlobal.mystery_items.push(data[0].crpyt(ENCRYPTION_KEY).to_i)
    elsif data[1].include?("pokemon")
      poke=data[0].crypt(ENCRYPTION_KEY).to_mpokemon
      if pbAddPokemonSilent(poke)
        name=PBSpecies.getName(poke.species)
        if poke.eggsteps > 0
          name = "Egg"
        end
        x = "a"
        # this small snippet determines if we must say a or an
        vowels = ["a", "e", "i", "o", "u", "A", "E", "I", "O", "U"]
        for i in vowels
          if name[0] == i[0]
            x = "an"
            break
          end
        end
        Kernel.pbMessage(_INTL("You have received {3} {1} from {2}!", name,poke.ot,x))
      end
    elsif data[1].include?("var")
      dat=data[0].crypt(ENCRYPTION_KEY).split(",")
      dat[1]=dat[1].to_i if dat[2]=="i"
      $game_variables[dat[0].to_i]=dat[1]
    elsif data[1].include?("swt")
      dat=data[0].crypt(ENCRYPTION_KEY).split(",")
      $game_switches[dat[0].to_i]=dat[1].to_i.to_b
    elsif data[1].include?("eval")
      eval(data[0].crypt(ENCRYPTION_KEY))
    end
    return true
  end
  
  def has_gifts?
    $PokemonGlobal.init_mysterygift if $PokemonGlobal.mystery_items == nil
    return $PokemonGlobal.mystery_items.length > 0
  end
  
  def give_items
    for i in 0..$PokemonGlobal.mystery_items.length-1
      Kernel.pbReceiveItem($PokemonGlobal.mystery_items[i])
      if i < $PokemonGlobal.mystery_items.length-1
        Kernel.pbMessage(_INTL("Oh it seems as if I still have some packages for you."))
      end
    end
  end
  
end
# initializes the mystery gift class as MysteryGift
MysteryGift = Mysterygift.new

Also, I made this in a class form and made it as different as possible to raptor's trade system so I don't need to go down that road again.


Finally, I am open to suggestions as long as they are worth it.

Please before complaining of an error, be sure that you try this on a clean version of essentials, as all the functions (except the pokemon global function) has been tested and succeeded, or you may just be using this wrong. I did not setup a test gift like last time so there is no actual example.

Also, there is a description of every function and what it does and how to call them normally.
 
Last edited:

Maruno

Lead Dev of Pokémon Essentials
5,285
Posts
16
Years
I haven't tried this out, but here's a few things I noticed when reading through the code:

You have a very wordy way of saving a Pokémon's details to a string and back. It's also not future-proof, as it would need to be changed if any property of a Pokémon was to change/be added.

When creating a Mystery Gift file, there's no confirmation message that the file was in fact created (nor error message if it wasn't). If there's an error, you have to type in everything again from the start (which is an utter pain for Pokémon, which most Mystery Gifts will be).

Speaking of Pokémon, eggs should be allowed to be customised in (almost) every way that Pokémon can be. Pichu with Volt Tackle, for instance.

I don't think it's useful to include a PokemonGlobal option, since anything it might be used for can just as easily be done with a Global Variable. Your code also implies that the Mystery Gift itself creates the scripts required to use the PokemonGlobal variable... which should already exist, otherwise there would be crashes when the game tries to check that variable but can't because it doesn't exist (and if the game doesn't check it at all, what's the point of creating it halfway through the game? It still won't be used).

It would be nice if the url of the Mystery Gift file was a string variable in the scripts (like a Setting). It would be more convenient than using it as an argument in the method's call.
 
1,748
Posts
14
Years
I haven't tried this out, but here's a few things I noticed when reading through the code:

You have a very wordy way of saving a Pokémon's details to a string and back. It's also not future-proof, as it would need to be changed if any property of a Pokémon was to change/be added.

When creating a Mystery Gift file, there's no confirmation message that the file was in fact created (nor error message if it wasn't). If there's an error, you have to type in everything again from the start (which is an utter pain for Pokémon, which most Mystery Gifts will be).

Speaking of Pokémon, eggs should be allowed to be customised in (almost) every way that Pokémon can be. Pichu with Volt Tackle, for instance.

I don't think it's useful to include a PokemonGlobal option, since anything it might be used for can just as easily be done with a Global Variable. Your code also implies that the Mystery Gift itself creates the scripts required to use the PokemonGlobal variable... which should already exist, otherwise there would be crashes when the game tries to check that variable but can't because it doesn't exist (and if the game doesn't check it at all, what's the point of creating it halfway through the game? It still won't be used).

It would be nice if the url of the Mystery Gift file was a string variable in the scripts (like a Setting). It would be more convenient than using it as an argument in the method's call.


Alright then, I'll get to adding these improvements in.
 
1,748
Posts
14
Years
Can do a tutorial to create the gift and how to get it?

after you create a gift (as stated above) upload the file you've just created (usually you save it into a text file) to a website where you can view the file as a webpage (like stated in my previous system where I used webs.com) afterwards take the link there and put it into my link I used for testing (localhost://MysteryGift.txt) and test it.
 

Rayquaza.

Lead Dev in Pokémon Order and Chaos
702
Posts
12
Years
Could you provide some sort of a template on eggs, pokemon and so on? I'm completely clueless to what you were trying to say in the last tutorial.
 
1,748
Posts
14
Years
Code:
Mysterygift.create_egg # creates an egg (inside the file of choosing)
Mysterygift.create_pokemon # creates a pokemon (inside the file of choosing)
Mysterygift.create_item # creates an item (inside the file of choosing)
# continue on to things like switchs/variables/ect.

Upload the file (created with one of the above functions) to a place where you can download it (the direct download link, rapidshare, mediafire, ect. won't work) again you may use webs.com stated in my other one

Then finally grab the link of the file and paste it into the "" on the GIFT_DEFAULT_URL line. Finally test it and report errors.
 
Back
Top