Neopets system includes: Difference between revisions

From Computers Wiki
Jump to navigationJump to search
(→‎Old versions: Add dictionary)
(Add dictionary)
Line 63: Line 63:
This is in the same object and frame, but DoAction [7].
This is in the same object and frame, but DoAction [7].


It loads "http://images50.neopets.com/games/utilities/flash_dictionary/flash_dictionary_en_vVERSION.swf", where VERSION is the value of _level0.game_dict_ver. Live site games use dict_ver 62. The images50 URL doesn't work; instead use https://images.neopets.com/games/utilities/flash_dictionary/flash_dictionary_en_v62.swf. However, the dictionary can check if something is a word, a bad word, dictionary word, and/or Neopian word. Words can also be scrambled and selected randomly.
It loads "http://images50.neopets.com/games/utilities/flash_dictionary/flash_dictionary_en_vVERSION.swf", where VERSION is the value of _level0.game_dict_ver. Live site games use dict_ver 62. The images50 URL doesn't work; instead use https://images.neopets.com/games/utilities/flash_dictionary/flash_dictionary_en_v62.swf. The dictionary can check if something is a word, a bad word, dictionary word, and/or Neopian word. Words can also be scrambled and selected randomly.


=== NeoStatus ===
=== NeoStatus ===
Line 205: Line 205:


This file is set to SWF version 8 (Flash 8). It seems really similar to the NP6 loader, at least when comparing both v7 versions. The difference is that the NP8 loader appears to decompile to more object-oriented code.
This file is set to SWF version 8 (Flash 8). It seems really similar to the NP6 loader, at least when comparing both v7 versions. The difference is that the NP8 loader appears to decompile to more object-oriented code.

== Dictionary ==

This analysis is done with the v62 version. I couldn't find an old dictionary on the promotional disc.

SWF version is 6 (Flash 6). There is one script, DoAction for frame 1, and this script is 55218 lines long when disassembled. The data structure, in Python-esque terms, is <code>list[dict[str, dict[str, int]]]</code>. The list is indexed using word length. The key of the outer mapping is the first letter of the word. The value of the outer mapping is another mapping. The key of the inner mapping is the word itself. The value is the category of the word:
* 1: Dictionary word
* 2: Neopian word, such as "edna", but this also includes others like "dont" and "mega"
An actual word is greater than 0. Bad words are not included, but are treated as -1 by consuming code using the NP6/8 dictionary methods.


== References ==
== References ==

Revision as of 07:33, 18 May 2023

The Neopets system includes are a set of Flash SWFs that are included and used by the Flash games.

This page is going to suck until I better understand Flash development and reverse engineering.

Old versions

The promotional disc[1] has the following old versions of the system includes:

  • /system/bios.swf, 6441 bytes, modified 2007-06-04
  • /system/np6_include_v7.swf, 49408 bytes, modified 2007-03-06
  • /system/np8_include_v7.swf, 54949 bytes, modified 2007-03-06

The following loaders seem to download the following versions:

Game Game ID Loader Loader Bytes Loader Modified Include Include Bytes Loader Modified
Kass Basher 381 https://images.neopets.com/games/gaming_system/np6_loader_v2_24.swf 3200 2010-01-20 https://images.neopets.com/games/gaming_system/np6_include_v1.swf 47251 2006-10-26

There seems to be only one accessible Flash dictionary version.

BIOS

This file is set to SWF version 6 (Flash 6 minimum). Based on my not-good understanding of ActionScript, it appears to do the following things:

On frame 1

  • Check how the BIOS is loaded
    • Check if String(this) == "_level0"; if so, trace "Bios: Error, load this externally!" and stop the movie
    • Check if String(this).split(".")[0] == "_level0"; if not, set a local flag to false, which appears to change some sort of progress meter display slightly and set a translation string path to use non-local paths
    • Else, set the local flag to true and set a separate offline flag to 1
  • Set up the loading fade-in effect for the "NEO*BIOS 330-MEGA" chip
  • Wait for itself to finish loading
  • If the local flag is true, open system/np6_include_v7.swf onto the target "_level100" and wait for it to finish loading
  • Play this movie's parent's parent

On the "bios" sprite

  • If the parent is _level0, print "BIOS must be loaded by another file!" and stop the movie
  • copyInProps, which seems to copy the properties of the BIOS child of either _level10 (if loaded) (not 100) or _level0 (if _level10 not loaded) onto this object
  • addProtoCode, which seems to change Object.toString to be a serialization system like {key1:value1,key2:{k3:v3,k4:v4}}, but with a new line for each level, and adjustable indentation for each level
  • If fully loaded, make the parent invisible, and finish
  • If not fully loaded, load "http://images.neopets.com/games/high_scores/include_movie.swf" onto the target _level100 and wait for it to finish loading

Other notes

The circuit background appears to actually be stored in the game resources instead of in the BIOS movie itself.

NP6

This file is set to SWF version 6 (Flash 6). This analysis was done with the v7 version.

Reporting cheaters

This is in DefineSprite (51) -> frame 1 (wait) -> DoAction.

There are two mechanisms, called gameMsg and msg. They take two parameters: index and append. They create a "body" string of the format "game_id - game_filename - game_username", then append "append" if it isn't undefined. This is then POSTed to "http://www.neopets.com/games/dgs/dgs_protocol.phtml?id=index&subject=game_id&body=body" in obfuscated fashion, and the variables from the response loaded to _level0.

gameMsg is similar, except that " - old call -" is appended to "append" before anything happens, and the game then opens http://www.neopets.com/games/cheatmonster.phtml in a new window.

Dictionary support

This is in the same object and frame, but DoAction [7].

It loads "http://images50.neopets.com/games/utilities/flash_dictionary/flash_dictionary_en_vVERSION.swf", where VERSION is the value of _level0.game_dict_ver. Live site games use dict_ver 62. The images50 URL doesn't work; instead use https://images.neopets.com/games/utilities/flash_dictionary/flash_dictionary_en_v62.swf. The dictionary can check if something is a word, a bad word, dictionary word, and/or Neopian word. Words can also be scrambled and selected randomly.

NeoStatus

DoAction [9]. These URLs are hit:

Events information

There is an idea of events, which have a tag name, status code, and offset. When creating an event, a base_multiple is also needed. This sets "multiple" to base_multiple * 2 and "active" to random(offset) + 1 == 1.

Tag Name Status Code Offset
Game Started 900 1
Multiplayer Game Started 1 901 1
Multiplayer Game Started 2 902 1
Multiplayer Game Started 3 903 1
Multiplayer Game Started 4 904 1
Game Finished 1000 1
Sent Score 1001 1
Reached Level n (where 1 <= n <= 100) 7000 + n 10
Sponsor Item Shown 8010 30
Sponsor Logo Shown 8020 10
Sponsor Item Collected 8030 30
Sponsor Banner Shown 8040 30

If tracking is enabled (Number(_level0.game_tracking) == 1), Game Started and Game Finished events hit the tracking URL base with the following parameters added to the query string:

  • dowhat=game_starts if Game Started, or game_ends if Game Finished
  • multiple= followed by _level0.game_multiple
  • r= followed by random(999999999)

The variables from this call to the tracking URL are then loaded. When I try URLs like https://www.neopets.com/track_plays.phtml?game_id=987&dowhat=game_ends&multiple=0&r=8309101 using the values from 200m Peanut Dash, nothing is in the response, so I'm not sure what the NP6 loader was trying to find.

Then, for the main NeoStatus URL, this gets hit once for each event:

  • item_id= followed by item_id, which seems to be -1 if _level0.nsid is undefined and debug not -1, 1 if undefined and 1, or _level0.nsid
  • multiple= value of multiple for this event, which is that base_multiplier * 2 from earlier
  • status= value of statusCode for this event
  • If URLSuffix is undefined for the call: nc_value= followed by _level0.nc_referer. Note that nc_referer doesn't seem to be set to anything other than a blank string on the live website, though that's with NP8 games and not NP6.
  • r= value of random(999999999)

There is client-side logic to prevent sending an event if item_id is set to -1, which happens when _level0.nsid is undefined. Sending is also prevented if the "active" flag for the event is not 1. I am going to assume the random() call is exclusive, so events will be sent with probability 1 / offset. In other words, if offset is 1, then it will always be sent; otherwise, only sometimes.

Process click

Then, for process click, which seems to be unrelated to the main NeoStatus system, these are the query parameters:

  • item_id= passed item_id
  • random= value of Math.random() * 999999999

If the requested method is POST (the default), open it in the passed windowName window if called via processClickGetURL. Else, if called by processClickLoadVariables, a "type_id" and "nc_value" need to be present too, and the variables from the body are loaded into this object.

Membership stuff

If a signup or login is gotten from the game, hit the nc_track URL base with the following parameters:

  • type_id=12
  • item_id=3187 if signup, else 3188
  • nc_value= if undefined nc_referer, treat it as 0, then concatenate game_id, a hyphen, and nc_referer
  • r= value of Math.random(999999)

User Profile

DoAction [11]. You pass an array with any of the following items:

  • 1: scores_sent
  • 2: high_score
  • 3: user_age
  • 4: user_gender
  • 5: pet1_name
  • 6: pet1_color
  • 7: pet1_species
  • 8: user_full_name
  • 9: user_email
  • 10: user_country
  • 11: user_dob
  • 12: pet2_name
  • 13: pet3_name
  • 14: pet4_name

Slap a semicolon at the end of the numbers of each one you want, concatenate them together, call it typestring, then hit http://www.neopets.com/high_scores/fg_get_info.phtml?game_id=game_id&type=typestring. The response is then read using loadVariables().

Note that the pet names appear to be buggy. If you specify 12, 13, or 14, you only get pet1_name and pet2_name, regardless of which number you enter. If you specify two of them, you also get pet3_name. If you specify all three, you also get pet4_name. Yes, you can get the four pet names without actually specifying 5. Also, if you specify enough other numbers, you get access to the following numbers too:

  • 15: active_pet_mood=hardcoded_as_happy
  • 17: user_full_name (note that the one under number 8 doesn't seem to work anymore sometime after NP6 v7)
  • 18: is_admin
  • 19: is_sponsor
  • 20: neopoints
  • 21: lang

Scoring

DoAction [13]. TODO: document this better

http://www.neopets.com/high_scores/process_flash_score.phtml with params:

  • cn= value of 300 * _level0.game_id
  • gd= value of getTimer() - _level0.game_isLoaded
  • asp_cName=val for every pair of cName, val passed to addScoreParameter(cName, val) ahead of time
  • r= value of Math.random(999999999)
  • gmd_g= value of _level0.game_hash
  • mltpl_g= value of _level0.game_multiple
  • gmdt_g= value of sSlashed, see below
  • sh_g= value of _level0.game_hash
  • sk_g= value of _level0.game_sk
  • usrnm_g= value of _level0.game_username
  • dc_g= value of _level0.game_dailyChallenge

Where sSlashed is the following stuff in query string (minus the question mark) format, encoded in some crazy algorithm defined in np.projects.include.Strings:

  • ssnhsh= value of _level0.game_hash
  • ssnky= value of _level0.game_sk
  • gmd= value of _level0.game_id
  • scr= value of _SCORE.show()
  • frmrt= value of _level0.average_real_framerate
  • chllng= value of _level0.game_challenge
  • gmdrtn= value of getTimer() - _level0.game_isLoaded

Flash Challenge Email

DoAction [15]. Hit http://www.neopets.com/games/email_flash_challenge.phtml with the following query params:

  • flash=1
  • game_id= value of _level0.game_id
  • score= value of _SCORE.show()
  • sender_name= value of fromName
  • sender_email= value of fromEmail
  • recipient_name= value of toName
  • recipient_email= value of toEmail

This gets loaded into a special LoadVars() object, and it looks like "error_str" and "msg" are checked for to get an error message and success message.

NP8

This file is set to SWF version 8 (Flash 8). It seems really similar to the NP6 loader, at least when comparing both v7 versions. The difference is that the NP8 loader appears to decompile to more object-oriented code.

Dictionary

This analysis is done with the v62 version. I couldn't find an old dictionary on the promotional disc.

SWF version is 6 (Flash 6). There is one script, DoAction for frame 1, and this script is 55218 lines long when disassembled. The data structure, in Python-esque terms, is list[dict[str, dict[str, int]]]. The list is indexed using word length. The key of the outer mapping is the first letter of the word. The value of the outer mapping is another mapping. The key of the inner mapping is the word itself. The value is the category of the word:

  • 1: Dictionary word
  • 2: Neopian word, such as "edna", but this also includes others like "dont" and "mega"

An actual word is greater than 0. Bad words are not included, but are treated as -1 by consuming code using the NP6/8 dictionary methods.

References