From 34c83d94959912d9cd3752d171ad1bcbdcf385ba Mon Sep 17 00:00:00 2001 From: Andrea Faulds Date: Sun, 19 Jan 2014 16:27:47 +0000 Subject: [PATCH] Added JSOnion and Spelunky samples to GML corpus --- lib/linguist/samples.json | 715 ++++++- .../characterDrawEvent.gml | 80 + .../characterStepEvent.gml | 1050 ++++++++++ samples/Game Maker Language/jsonion.gml | 1861 +++++++++++++++++ samples/Game Maker Language/jsonion_test.gml | 1169 +++++++++++ samples/Game Maker Language/scrInitLevel.gml | 298 +++ 6 files changed, 5068 insertions(+), 105 deletions(-) create mode 100644 samples/Game Maker Language/characterDrawEvent.gml create mode 100644 samples/Game Maker Language/characterStepEvent.gml create mode 100644 samples/Game Maker Language/jsonion.gml create mode 100644 samples/Game Maker Language/jsonion_test.gml create mode 100644 samples/Game Maker Language/scrInitLevel.gml diff --git a/lib/linguist/samples.json b/lib/linguist/samples.json index 7dccfe60..2d3a6cfe 100644 --- a/lib/linguist/samples.json +++ b/lib/linguist/samples.json @@ -538,8 +538,8 @@ ".gemrc" ] }, - "tokens_total": 453362, - "languages_total": 531, + "tokens_total": 458739, + "languages_total": 536, "tokens": { "ABAP": { "*/**": 1, @@ -17367,8 +17367,315 @@ "cell": 2 }, "Game Maker Language": { - "var": 77, - "i": 72, + "//draws": 1, + "the": 62, + "sprite": 12, + "draw": 3, + "true": 73, + ";": 1282, + "if": 397, + "(": 1501, + "facing": 17, + "RIGHT": 10, + ")": 1502, + "image_xscale": 17, + "-": 212, + "else": 151, + "blinkToggle": 1, + "{": 300, + "state": 50, + "CLIMBING": 5, + "or": 78, + "sprite_index": 14, + "sPExit": 1, + "sDamselExit": 1, + "sTunnelExit": 1, + "and": 155, + "global.hasJetpack": 4, + "not": 63, + "whipping": 5, + "draw_sprite_ext": 10, + "x": 76, + "y": 85, + "image_yscale": 14, + "image_angle": 14, + "image_blend": 2, + "image_alpha": 10, + "//draw_sprite": 1, + "draw_sprite": 9, + "sJetpackBack": 1, + "false": 85, + "}": 307, + "sJetpackRight": 1, + "sJetpackLeft": 1, + "+": 206, + "redColor": 2, + "make_color_rgb": 1, + "holdArrow": 4, + "ARROW_NORM": 2, + "sArrowRight": 1, + "ARROW_BOMB": 2, + "holdArrowToggle": 2, + "sBombArrowRight": 2, + "LEFT": 7, + "sArrowLeft": 1, + "sBombArrowLeft": 2, + "hangCountMax": 2, + "//////////////////////////////////////": 2, + "kLeft": 12, + "checkLeft": 1, + "kLeftPushedSteps": 3, + "kLeftPressed": 2, + "checkLeftPressed": 1, + "kLeftReleased": 3, + "checkLeftReleased": 1, + "kRight": 12, + "checkRight": 1, + "kRightPushedSteps": 3, + "kRightPressed": 2, + "checkRightPressed": 1, + "kRightReleased": 3, + "checkRightReleased": 1, + "kUp": 5, + "checkUp": 1, + "kDown": 5, + "checkDown": 1, + "//key": 1, + "canRun": 1, + "kRun": 2, + "kJump": 6, + "checkJump": 1, + "kJumpPressed": 11, + "checkJumpPressed": 1, + "kJumpReleased": 5, + "checkJumpReleased": 1, + "cantJump": 3, + "global.isTunnelMan": 1, + "sTunnelAttackL": 1, + "holdItem": 1, + "kAttack": 2, + "checkAttack": 2, + "kAttackPressed": 2, + "checkAttackPressed": 1, + "kAttackReleased": 2, + "checkAttackReleased": 1, + "kItemPressed": 2, + "checkItemPressed": 1, + "xPrev": 1, + "yPrev": 1, + "stunned": 3, + "dead": 3, + "//////////////////////////////////////////": 2, + "colSolidLeft": 4, + "colSolidRight": 3, + "colLeft": 6, + "colRight": 6, + "colTop": 4, + "colBot": 11, + "colLadder": 3, + "colPlatBot": 6, + "colPlat": 5, + "colWaterTop": 3, + "colIceBot": 2, + "runKey": 4, + "isCollisionMoveableSolidLeft": 1, + "isCollisionMoveableSolidRight": 1, + "isCollisionLeft": 2, + "isCollisionRight": 2, + "isCollisionTop": 1, + "isCollisionBottom": 1, + "isCollisionLadder": 1, + "isCollisionPlatformBottom": 1, + "isCollisionPlatform": 1, + "isCollisionWaterTop": 1, + "collision_point": 30, + "oIce": 1, + "checkRun": 1, + "runHeld": 3, + "HANGING": 10, + "approximatelyZero": 4, + "xVel": 24, + "xAcc": 12, + "platformCharacterIs": 23, + "ON_GROUND": 18, + "DUCKING": 4, + "pushTimer": 3, + "//if": 5, + "SS_IsSoundPlaying": 2, + "global.sndPush": 4, + "playSound": 3, + "runAcc": 2, + "abs": 9, + "alarm": 13, + "[": 99, + "]": 103, + "<": 39, + "floor": 11, + "/": 5, + "/xVel": 1, + "instance_exists": 8, + "oCape": 2, + "oCape.open": 6, + "kJumped": 7, + "ladderTimer": 4, + "ladder": 5, + "oLadder": 4, + "ladder.x": 3, + "oLadderTop": 2, + "yAcc": 26, + "climbAcc": 2, + "FALLING": 8, + "STANDING": 2, + "departLadderXVel": 2, + "departLadderYVel": 1, + "JUMPING": 6, + "jumpButtonReleased": 7, + "jumpTime": 8, + "IN_AIR": 5, + "gravityIntensity": 2, + "yVel": 20, + "RUNNING": 3, + "jumps": 3, + "//playSound": 1, + "global.sndLand": 1, + "grav": 22, + "global.hasGloves": 3, + "hangCount": 14, + "*": 18, + "yVel*0.3": 1, + "oWeb": 2, + "obj": 14, + "instance_place": 3, + "obj.life": 1, + "initialJumpAcc": 6, + "xVel/2": 3, + "gravNorm": 7, + "global.hasCape": 1, + "jetpackFuel": 2, + "fallTimer": 2, + "global.hasJordans": 1, + "yAccLimit": 2, + "global.hasSpringShoes": 1, + "global.sndJump": 1, + "jumpTimeTotal": 2, + "//let": 1, + "character": 20, + "continue": 4, + "to": 62, + "jump": 1, + "jumpTime/jumpTimeTotal": 1, + "looking": 2, + "UP": 1, + "LOOKING_UP": 4, + "oSolid": 14, + "move_snap": 6, + "oTree": 4, + "oArrow": 5, + "instance_nearest": 1, + "obj.stuck": 1, + "//the": 2, + "can": 1, + "t": 23, + "want": 1, + "use": 4, + "because": 2, + "is": 9, + "too": 2, + "high": 1, + "yPrevHigh": 1, + "//": 11, + "we": 5, + "ll": 1, + "move": 2, + "correct": 1, + "distance": 1, + "but": 2, + "need": 1, + "shorten": 1, + "out": 4, + "a": 55, + "little": 1, + "ratio": 1, + "xVelInteger": 2, + "/dist*0.9": 1, + "//can": 1, + "be": 4, + "changed": 1, + "moveTo": 2, + "round": 6, + "xVelInteger*ratio": 1, + "yVelInteger*ratio": 1, + "slopeChangeInY": 1, + "maxDownSlope": 1, + "floating": 1, + "just": 1, + "above": 1, + "slope": 1, + "so": 2, + "down": 1, + "upYPrev": 1, + "for": 26, + "<=upYPrev+maxDownSlope;y+=1)>": 1, + "hit": 1, + "solid": 1, + "below": 1, + "upYPrev=": 1, + "I": 1, + "know": 1, + "that": 2, + "this": 2, + "doesn": 1, + "seem": 1, + "make": 1, + "sense": 1, + "of": 25, + "name": 9, + "variable": 1, + "it": 6, + "all": 3, + "works": 1, + "correctly": 1, + "after": 1, + "break": 58, + "loop": 1, + "y=": 1, + "figures": 1, + "what": 1, + "index": 11, + "should": 25, + "characterSprite": 1, + "sets": 1, + "previous": 2, + "previously": 1, + "statePrevPrev": 1, + "statePrev": 2, + "calculates": 1, + "image_speed": 9, + "based": 1, + "on": 4, + "s": 6, + "velocity": 1, + "runAnimSpeed": 1, + "0": 21, + "1": 32, + "sqrt": 1, + "sqr": 2, + "climbAnimSpeed": 1, + "<=>": 3, + "4": 2, + "setCollisionBounds": 3, + "8": 9, + "5": 5, + "DUCKTOHANG": 1, + "image_index": 1, + "limit": 5, + "at": 23, + "animation": 1, + "always": 1, + "looks": 1, + "good": 1, + "var": 79, + "i": 95, "playerObject": 1, "playerID": 1, "player": 36, @@ -17379,22 +17686,14 @@ "plugins": 4, "pluginsRequired": 2, "usePlugins": 1, - ";": 923, - "if": 213, - "(": 957, "tcp_eof": 3, "global.serverSocket": 10, - ")": 956, - "{": 177, "gotServerHello": 2, - "show_message": 6, - "else": 78, - "instance_destroy": 6, + "show_message": 7, + "instance_destroy": 7, "exit": 10, - "}": 179, "room": 1, "DownloadRoom": 1, - "and": 31, "keyboard_check": 1, "vk_escape": 1, "downloadingMap": 2, @@ -17402,14 +17701,11 @@ "tcp_receive": 3, "min": 4, "downloadMapBytes": 2, - "-": 110, "buffer_size": 2, "downloadMapBuffer": 6, "write_buffer": 2, "write_buffer_to_file": 1, - "+": 126, "downloadMapName": 3, - "false": 40, "buffer_destroy": 8, "roomchange": 2, "do": 1, @@ -17417,28 +17713,21 @@ "read_ubyte": 10, "case": 50, "HELLO": 1, - "true": 37, "global.joinedServerName": 2, "receivestring": 4, "advertisedMapMd5": 1, "receiveCompleteMessage": 1, "global.tempBuffer": 3, "string_pos": 20, - "or": 21, "Server": 3, "sent": 7, "illegal": 2, - "map": 23, - "name": 8, + "map": 47, "This": 2, "server": 10, "requires": 1, - "the": 19, "following": 2, - "to": 6, "play": 2, - "on": 2, - "it": 5, "#": 3, "suggests": 1, "optional": 1, @@ -17448,10 +17737,8 @@ "plugins.": 1, "Maps/": 2, ".png": 2, - "The": 4, - "s": 5, + "The": 6, "version": 4, - "of": 12, "Enter": 1, "Password": 1, "Incorrect": 1, @@ -17461,13 +17748,12 @@ "version.": 1, "Name": 1, "Exploit": 1, - "Invalid": 1, + "Invalid": 2, "plugin": 6, "packet": 3, "ID": 2, "There": 1, "are": 1, - "too": 1, "many": 1, "connections": 1, "from": 5, @@ -17478,14 +17764,12 @@ "been": 1, "kicked": 1, "server.": 1, - ".": 1, + ".": 12, "#Server": 1, "went": 1, "invalid": 1, "internal": 1, "#Exiting.": 1, - "/": 4, - "is": 7, "full.": 1, "noone": 7, "ERROR": 1, @@ -17495,7 +17779,6 @@ "such": 1, "unexpected": 1, "data.": 1, - "break": 56, "until": 1, "downloadHandle": 3, "url": 62, @@ -17515,7 +17798,6 @@ "temp_directory": 1, "httpGet": 1, "httpRequestStatus": 1, - "//": 7, "download": 1, "isn": 1, "extract": 1, @@ -17530,11 +17812,10 @@ "killer": 11, "assistant": 16, "damageSource": 18, - "argument0": 22, - "argument1": 8, + "argument0": 28, + "argument1": 10, "argument2": 3, "argument3": 1, - "instance_exists": 4, "//*************************************": 6, "//*": 3, "Scoring": 1, @@ -17542,9 +17823,7 @@ "log": 1, "recordKillInLog": 1, "victim.stats": 1, - "[": 84, "DEATHS": 1, - "]": 84, "WEAPON_KNIFE": 1, "||": 16, "WEAPON_BACKSTAB": 1, @@ -17568,7 +17847,7 @@ "assistant.roundStats": 2, ".5": 2, "//SPEC": 1, - "instance_create": 12, + "instance_create": 20, "victim.object.x": 3, "victim.object.y": 3, "Spectator": 1, @@ -17582,7 +17861,7 @@ "view_wview": 2, "view_hview": 2, "randomize": 1, - "with": 18, + "with": 47, "victim.object": 2, "WEAPON_ROCKETLAUNCHER": 1, "WEAPON_MINEGUN": 1, @@ -17597,13 +17876,9 @@ "distance_to_point": 3, "xsize/2": 2, "ysize/2": 2, - "<": 19, "hasReward": 4, - "repeat": 6, - "*": 7, + "repeat": 7, "createGib": 14, - "x": 24, - "y": 23, "PumpkinGib": 1, "hspeed": 14, "vspeed": 13, @@ -17651,7 +17926,6 @@ "deadbody.sprite_index": 2, "haxxyStatue": 1, "deadbody.image_index": 2, - "sprite_index": 2, "CHARACTER_ANIMATION_DEAD": 1, "deadbody.hspeed": 1, "deadbody.vspeed": 1, @@ -17677,8 +17951,6 @@ "global.myself.team": 3, "xr": 19, "yr": 19, - "round": 4, - "image_alpha": 7, "cloakAlpha": 1, "team": 13, "canCloak": 1, @@ -17699,9 +17971,8 @@ "mouse_y": 1, "<25)>": 1, "cloak": 2, - "global": 4, + "global": 8, "myself": 2, - "1": 27, "draw_set_halign": 1, "fa_center": 1, "draw_set_valign": 1, @@ -17713,10 +17984,9 @@ "35": 1, "showTeammateStats": 1, "weapons": 3, - "0": 12, "50": 3, "Superburst": 1, - "string": 5, + "string": 13, "currentWeapon": 2, "uberCharge": 1, "20": 1, @@ -17730,7 +18000,6 @@ "Mines": 1, "lobbed": 1, "ubercolour": 6, - "sprite": 10, "overlaySprite": 6, "zoomed": 1, "SniperCrouchRedS": 1, @@ -17742,9 +18011,6 @@ "omnomnomnomSprite": 2, "omnomnomnomOverlay": 2, "omnomnomnomindex": 4, - "image_xscale": 12, - "image_yscale": 11, - "image_angle": 11, "c_white": 13, "ubered": 7, "7": 4, @@ -17753,19 +18019,15 @@ "tauntOverlay": 2, "tauntindex": 2, "humiliated": 1, - "draw_sprite_ext": 7, "humiliationPoses": 1, - "floor": 9, "animationImage": 9, "humiliationOffset": 1, "animationOffset": 6, "burnDuration": 2, "burnIntensity": 2, - "for": 17, "numFlames": 1, "maxIntensity": 1, "FlameS": 1, - "alarm": 2, "flameArray_x": 1, "flameArray_y": 1, "maxDuration": 1, @@ -17775,13 +18037,12 @@ "demonY": 4, "demonOffset": 4, "demonDir": 2, - "abs": 1, "dir": 3, "demonFrame": 5, "sprite_get_number": 1, "*player.team": 2, "dir*1": 2, - "#define": 21, + "#define": 26, "__http_init": 3, "global.__HttpClient": 4, "object_add": 1, @@ -17789,21 +18050,20 @@ "__http_split": 3, "text": 19, "delimeter": 7, - "limit": 4, - "list": 17, + "list": 36, "count": 4, "ds_list_create": 5, "ds_list_add": 23, "string_copy": 32, "string_length": 25, - "return": 53, + "return": 56, "__http_parse_url": 4, "ds_map_create": 4, "ds_map_add": 15, "colonPos": 22, "string_char_at": 13, "slashPos": 13, - "real": 6, + "real": 14, "queryPos": 12, "ds_map_destroy": 6, "__http_resolve_url": 2, @@ -17833,7 +18093,6 @@ "ds_list_destroy": 4, "part": 6, "ds_list_replace": 3, - "continue": 3, "__http_parse_hex": 2, "hexString": 4, "hexValues": 3, @@ -17842,7 +18101,7 @@ "client": 33, "headers": 11, "parsed": 18, - "show_error": 1, + "show_error": 2, "destroyed": 3, "CR": 10, "chr": 3, @@ -17850,7 +18109,6 @@ "CRLF": 17, "socket": 40, "tcp_connect": 1, - "state": 4, "errored": 19, "error": 18, "linebuf": 33, @@ -17865,9 +18123,9 @@ "requestUrl": 2, "requestHeaders": 2, "write_string": 9, - "key": 7, + "key": 17, "ds_map_find_first": 1, - "is_string": 1, + "is_string": 2, "ds_map_find_next": 1, "socket_send": 1, "__http_parse_header": 3, @@ -17883,16 +18141,14 @@ "tcp_receive_available": 1, "bytesRead": 6, "c": 20, - "<=>": 1, "read_string": 9, "Reached": 2, - "end": 6, + "end": 11, "HTTP": 1, "defines": 1, "sequence": 2, "as": 1, "marker": 1, - "all": 2, "elements": 1, "except": 2, "entity": 1, @@ -17909,27 +18165,26 @@ "status": 2, "code": 2, "first": 3, - "a": 20, "Response": 1, "message": 1, "Status": 1, "Line": 1, "consisting": 1, "followed": 1, - "by": 4, + "by": 5, "numeric": 1, "its": 1, "associated": 1, "textual": 1, "phrase": 1, - "each": 2, - "element": 1, + "each": 18, + "element": 8, "separated": 1, "SP": 1, - "characters": 1, + "characters": 3, "No": 3, "allowed": 1, - "in": 8, + "in": 21, "final": 1, "httpVer": 2, "spacePos": 11, @@ -17948,7 +18203,7 @@ "chunked": 4, "Chunked": 1, "let": 1, - "decode": 1, + "decode": 36, "actualResponseBody": 8, "actualResponseSize": 1, "actualResponseBodySize": 3, @@ -17957,36 +18212,34 @@ "chunk": 12, "size": 7, "extension": 3, - "data": 1, + "data": 4, "HEX": 1, "buffer_bytes_left": 6, "chunkSize": 11, "Read": 1, "byte": 2, "We": 1, - "found": 1, + "found": 21, "semicolon": 1, "beginning": 1, "skip": 1, "stuff": 2, "header": 2, "Doesn": 1, - "t": 1, "did": 1, - "not": 5, - "empty": 2, + "empty": 13, "something": 1, - "up": 2, + "up": 6, "Parsing": 1, - "failed": 4, - "hex": 1, + "failed": 56, + "hex": 2, "was": 1, "hexadecimal": 1, "Is": 1, "bigger": 2, "than": 1, "remaining": 1, - "2": 1, + "2": 2, "responseHaders": 1, "location": 4, "resolved": 5, @@ -18112,12 +18365,10 @@ "CLASS_DEMOMAN": 1, "CLASS_SPY": 1, "//screw": 1, - "index": 1, - "we": 1, "will": 1, "start": 1, "//map_truefort": 1, - "maps": 33, + "maps": 37, "//map_2dfort": 1, "//map_conflict": 1, "//map_classicwell": 1, @@ -18171,14 +18422,13 @@ "tab": 2, "string_delete": 1, "delete": 1, - "that": 1, "comment": 1, "starting": 1, "file_text_readln": 1, "file_text_close": 1, "load": 1, "ini": 1, - "Maps": 1, + "Maps": 9, "section": 1, "//Set": 1, "rotation": 1, @@ -18241,6 +18491,168 @@ "AudioControlToggleMute": 1, "room_goto_fix": 2, "Menu": 2, + "__jso_gmt_tuple": 1, + "//Position": 1, + "address": 1, + "table": 1, + "pos": 2, + "addr_table": 2, + "*argument_count": 1, + "//Build": 1, + "tuple": 1, + "ca": 1, + "isstr": 1, + "datastr": 1, + "argument_count": 1, + "//Check": 1, + "argument": 10, + "Unexpected": 18, + "position": 16, + "f": 5, + "JSON": 5, + "string.": 5, + "Cannot": 5, + "parse": 3, + "boolean": 3, + "value": 13, + "expecting": 9, + "digit.": 9, + "e": 4, + "E": 4, + "dot": 1, + "an": 24, + "integer": 6, + "Expected": 6, + "least": 6, + "arguments": 26, + "got": 6, + "find": 10, + "lookup.": 4, + "indices": 1, + "nested": 27, + "lists": 6, + "Index": 1, + "overflow": 4, + "Recursive": 1, + "abcdef": 1, + "number": 7, + "num": 1, + "assert_true": 1, + "_assert_error_popup": 2, + "string_repeat": 2, + "_assert_newline": 2, + "assert_false": 1, + "assert_equal": 1, + "//Safe": 1, + "equality": 1, + "check": 1, + "won": 1, + "support": 1, + "instead": 1, + "_assert_debug_value": 1, + "//String": 1, + "os_browser": 1, + "browser_not_a_browser": 1, + "string_replace_all": 1, + "//Numeric": 1, + "GMTuple": 1, + "jso_encode_string": 1, + "encode": 8, + "escape": 2, + "jso_encode_map": 4, + "one": 42, + "key1": 3, + "key2": 3, + "multi": 7, + "jso_encode_list": 3, + "three": 36, + "_jso_decode_string": 5, + "small": 1, + "quick": 2, + "brown": 2, + "fox": 2, + "over": 2, + "lazy": 2, + "dog.": 2, + "simple": 1, + "Waahoo": 1, + "negg": 1, + "mixed": 1, + "_jso_decode_boolean": 2, + "_jso_decode_real": 11, + "standard": 1, + "zero": 4, + "signed": 2, + "decimal": 1, + "digits": 1, + "positive": 7, + "negative": 7, + "exponent": 4, + "_jso_decode_integer": 3, + "_jso_decode_map": 14, + "didn": 14, + "include": 14, + "right": 14, + "prefix": 14, + "#1": 14, + "#2": 14, + "entry": 29, + "pi": 2, + "bool": 2, + "waahoo": 10, + "woohah": 8, + "mix": 4, + "_jso_decode_list": 14, + "woo": 2, + "Empty": 4, + "equal": 20, + "other.": 12, + "junk": 2, + "info": 1, + "taxi": 1, + "An": 4, + "filled": 4, + "map.": 2, + "A": 24, + "B": 18, + "C": 8, + "same": 6, + "content": 4, + "entered": 4, + "different": 12, + "orders": 4, + "D": 1, + "keys": 2, + "values": 4, + "six": 1, + "corresponding": 4, + "types": 4, + "other": 4, + "crash.": 4, + "list.": 2, + "Lists": 4, + "two": 16, + "entries": 2, + "also": 2, + "jso_map_check": 9, + "existing": 9, + "single": 11, + "jso_map_lookup": 3, + "wrong": 10, + "trap": 2, + "jso_map_lookup_type": 3, + "type": 8, + "four": 21, + "inexistent": 11, + "multiple": 20, + "jso_list_check": 8, + "jso_list_lookup": 3, + "jso_list_lookup_type": 3, + "inner": 1, + "indexing": 1, + "bad": 1, + "jso_cleanup_map": 1, + "one_map": 1, "hashList": 5, "pluginname": 9, "pluginhash": 4, @@ -18269,10 +18681,8 @@ "Make": 2, "sure": 2, "clients": 1, - "same": 2, "they": 1, "may": 2, - "be": 2, "unable": 2, "connect.": 2, "you": 1, @@ -18300,7 +18710,6 @@ "class": 8, "getCharacterObject": 2, "player.object": 12, - "collision_point": 2, "SpawnRoom": 2, "lastDamageDealer": 8, "sendEventPlayerDeath": 4, @@ -18311,7 +18720,6 @@ "lastDamageDealer.object.healer": 4, "player.alarm": 4, "<=0)>": 1, - "5": 1, "checkClasslimits": 2, "ServerPlayerChangeclass": 2, "sendBuffer": 1, @@ -18394,7 +18802,104 @@ "KICK_BAD_PLUGIN_PACKET": 1, "CLIENT_SETTINGS": 2, "mirror": 4, - "player.queueJump": 1 + "player.queueJump": 1, + "global.levelType": 22, + "//global.currLevel": 1, + "global.currLevel": 22, + "global.hadDarkLevel": 4, + "global.startRoomX": 1, + "global.startRoomY": 1, + "global.endRoomX": 1, + "global.endRoomY": 1, + "oGame.levelGen": 2, + "j": 14, + "global.roomPath": 1, + "k": 5, + "global.lake": 3, + "isLevel": 1, + "999": 2, + "levelType": 2, + "16": 14, + "656": 3, + "oDark": 2, + "invincible": 2, + "sDark": 1, + "oTemple": 2, + "cityOfGold": 1, + "sTemple": 2, + "lake": 1, + "i*16": 8, + "j*16": 6, + "oLush": 2, + "obj.sprite_index": 4, + "sLush": 2, + "obj.invincible": 3, + "oBrick": 1, + "sBrick": 1, + "global.cityOfGold": 2, + "*16": 2, + "//instance_create": 2, + "oSpikes": 1, + "background_index": 1, + "bgTemple": 1, + "global.temp1": 1, + "global.gameStart": 3, + "scrLevelGen": 1, + "global.cemetary": 3, + "rand": 10, + "global.probCemetary": 1, + "oRoom": 1, + "scrRoomGen": 1, + "global.blackMarket": 3, + "scrRoomGenMarket": 1, + "scrRoomGen2": 1, + "global.yetiLair": 2, + "scrRoomGenYeti": 1, + "scrRoomGen3": 1, + "scrRoomGen4": 1, + "scrRoomGen5": 1, + "global.darkLevel": 4, + "global.noDarkLevel": 1, + "global.probDarkLevel": 1, + "oPlayer1.x": 2, + "oPlayer1.y": 2, + "oFlare": 1, + "global.genUdjatEye": 4, + "global.madeUdjatEye": 1, + "global.genMarketEntrance": 4, + "global.madeMarketEntrance": 1, + "////////////////////////////": 2, + "global.temp2": 1, + "isRoom": 3, + "scrEntityGen": 1, + "oEntrance": 1, + "global.customLevel": 1, + "oEntrance.x": 1, + "oEntrance.y": 1, + "global.snakePit": 1, + "global.alienCraft": 1, + "global.sacrificePit": 1, + "oPlayer1": 1, + "scrSetupWalls": 3, + "global.graphicsHigh": 1, + "tile_add": 4, + "bgExtrasLush": 1, + "*rand": 12, + "bgExtrasIce": 1, + "bgExtrasTemple": 1, + "bgExtras": 1, + "global.murderer": 1, + "global.thiefLevel": 1, + "isRealLevel": 1, + "oExit": 1, + "oShopkeeper": 1, + "obj.status": 1, + "oTreasure": 1, + "oWater": 1, + "sWaterTop": 1, + "sLavaTop": 1, + "scrCheckWaterTop": 1, + "global.temp3": 1 }, "GAS": { ".cstring": 1, @@ -48849,7 +49354,7 @@ "Erlang": 2928, "fish": 636, "Forth": 1516, - "Game Maker Language": 7933, + "Game Maker Language": 13310, "GAS": 133, "GLSL": 3766, "Gosu": 410, @@ -48992,7 +49497,7 @@ "Erlang": 5, "fish": 3, "Forth": 7, - "Game Maker Language": 8, + "Game Maker Language": 13, "GAS": 1, "GLSL": 3, "Gosu": 4, @@ -49101,5 +49606,5 @@ "Oxygene": 1, "RMarkdown": 1 }, - "md5": "d553eccf00cb7981cddf40658c0f42ae" + "md5": "f41f28c5524157cbfbdd2e09957d3d78" } \ No newline at end of file diff --git a/samples/Game Maker Language/characterDrawEvent.gml b/samples/Game Maker Language/characterDrawEvent.gml new file mode 100644 index 00000000..6dcd8fcc --- /dev/null +++ b/samples/Game Maker Language/characterDrawEvent.gml @@ -0,0 +1,80 @@ +// Originally from /spelunky/Scripts/Platform Engine/characterDrawEvent.gml in the Spelunky Community Update Project + +/********************************************************************************** + Copyright (c) 2008, 2009 Derek Yu and Mossmouth, LLC + + This file is part of Spelunky. + + You can redistribute and/or modify Spelunky, including its source code, under + the terms of the Spelunky User License. + + Spelunky is distributed in the hope that it will be entertaining and useful, + but WITHOUT WARRANTY. Please see the Spelunky User License for more details. + + The Spelunky User License should be available in "Game Information", which + can be found in the Resource Explorer, or as an external file called COPYING. + If not, please obtain a new copy of Spelunky from + +***********************************************************************************/ + +/* +This event should be placed in the draw event of the platform character. +*/ +//draws the sprite +draw = true; +if (facing == RIGHT) image_xscale = -1; +else image_xscale = 1; + +if (blinkToggle != 1) +{ + if ((state == CLIMBING or (sprite_index == sPExit or sprite_index == sDamselExit or sprite_index == sTunnelExit)) and global.hasJetpack and not whipping) + { + draw_sprite_ext(sprite_index, -1, x, y, image_xscale, image_yscale, image_angle, image_blend, image_alpha); + //draw_sprite(sprite_index,-1,x,y); + draw_sprite(sJetpackBack,-1,x,y); + draw = false; + } + else if (global.hasJetpack and facing == RIGHT) draw_sprite(sJetpackRight,-1,x-4,y-1); + else if (global.hasJetpack) draw_sprite(sJetpackLeft,-1,x+4,y-1); + if (draw) + { + if (redColor > 0) draw_sprite_ext(sprite_index, -1, x, y, image_xscale, image_yscale, image_angle, make_color_rgb(200 + redColor,0,0), image_alpha); + else draw_sprite_ext(sprite_index, -1, x, y, image_xscale, image_yscale, image_angle, image_blend, image_alpha); + } + if (facing == RIGHT) + { + if (holdArrow == ARROW_NORM) + { + draw_sprite(sArrowRight, -1, x+4, y+1); + } + else if (holdArrow == ARROW_BOMB) + { + if (holdArrowToggle) draw_sprite(sBombArrowRight, 0, x+4, y+2); + else draw_sprite(sBombArrowRight, 1, x+4, y+2); + } + } + else if (facing == LEFT) + { + if (holdArrow == ARROW_NORM) + { + draw_sprite(sArrowLeft, -1, x-4, y+1); + } + else if (holdArrow == ARROW_BOMB) + { + if (holdArrowToggle) draw_sprite(sBombArrowLeft, 0, x-4, y+2); + else draw_sprite(sBombArrowLeft, 1, x-4, y+2); + } + } +} +/* +if canRun +{ + xOffset=80 + if player=1 + yOffset=120 + else + yOffset=143 + //draw the "flySpeed" bar, which shows how much speed the character has acquired while holding the "run" button + //draw_healthbar(view_xview[0]+224+xOffset,view_yview[0]+432+yOffset,view_xview[0]+400+xOffset,view_yview[0]+450+yOffset,flySpeed,make_color_rgb(0,64,128),c_blue,c_aqua,0,1,1) +} +*/ diff --git a/samples/Game Maker Language/characterStepEvent.gml b/samples/Game Maker Language/characterStepEvent.gml new file mode 100644 index 00000000..7416df80 --- /dev/null +++ b/samples/Game Maker Language/characterStepEvent.gml @@ -0,0 +1,1050 @@ +// Originally from /spelunky/Scripts/Platform Engine/characterStepEvent.gml in the Spelunky Community Update Project + +/********************************************************************************** + Copyright (c) 2008, 2009 Derek Yu and Mossmouth, LLC + + This file is part of Spelunky. + + You can redistribute and/or modify Spelunky, including its source code, under + the terms of the Spelunky User License. + + Spelunky is distributed in the hope that it will be entertaining and useful, + but WITHOUT WARRANTY. Please see the Spelunky User License for more details. + + The Spelunky User License should be available in "Game Information", which + can be found in the Resource Explorer, or as an external file called COPYING. + If not, please obtain a new copy of Spelunky from + +***********************************************************************************/ + +/* +This script should be placed in the step event for the platform character. +It updates the keys used by the character, moves all of the solids, moves the +character, sets the sprite index, and sets the animation speed for the sprite. +*/ +hangCountMax = 3; + +////////////////////////////////////// +// KEYS +////////////////////////////////////// + +kLeft = checkLeft(); + +if (kLeft) kLeftPushedSteps += 1; +else kLeftPushedSteps = 0; + +kLeftPressed = checkLeftPressed(); +kLeftReleased = checkLeftReleased(); + +kRight = checkRight(); + +if (kRight) kRightPushedSteps += 1; +else kRightPushedSteps = 0; + +kRightPressed = checkRightPressed(); +kRightReleased = checkRightReleased(); + +kUp = checkUp(); +kDown = checkDown(); + +//key "run" +if canRun + kRun = 0; +// kRun=runKey +else + kRun=0 + +kJump = checkJump(); +kJumpPressed = checkJumpPressed(); +kJumpReleased = checkJumpReleased(); + +if (cantJump > 0) +{ + kJump = 0; + kJumpPressed = 0; + kJumpReleased = 0; + cantJump -= 1; +} +else +{ + if (global.isTunnelMan and + sprite_index == sTunnelAttackL and + !holdItem) + { + kJump = 0; + kJumpPressed = 0; + kJumpReleased = 0; + cantJump -= 1; + } +} + +kAttack = checkAttack(); +kAttackPressed = checkAttackPressed(); +kAttackReleased = checkAttackReleased(); + +kItemPressed = checkItemPressed(); + +xPrev = x; +yPrev = y; + +if (stunned or dead) +{ + kLeft = false; + kLeftPressed = false; + kLeftReleased = false; + kRight = false; + kRightPressed = false; + kRightReleased = false; + kUp = false; + kDown = false; + kJump = false; + kJumpPressed = false; + kJumpReleased = false; + kAttack = false; + kAttackPressed = false; + kAttackReleased = false; + kItemPressed = false; +} + +////////////////////////////////////////// +// Collisions +////////////////////////////////////////// + +colSolidLeft = false; +colSolidRight = false; +colLeft = false; +colRight = false; +colTop = false; +colBot = false; +colLadder = false; +colPlatBot = false; +colPlat = false; +colWaterTop = false; +colIceBot = false; +runKey = false; +if (isCollisionMoveableSolidLeft(1)) colSolidLeft = true; +if (isCollisionMoveableSolidRight(1)) colSolidRight = true; +if (isCollisionLeft(1)) colLeft = true; +if (isCollisionRight(1)) colRight = true; +if (isCollisionTop(1)) colTop = true; +if (isCollisionBottom(1)) colBot = true; +if (isCollisionLadder()) colLadder = true; +if (isCollisionPlatformBottom(1)) colPlatBot = true; +if (isCollisionPlatform()) colPlat = true; +if (isCollisionWaterTop(1)) colWaterTop = true; +if (collision_point(x, y+8, oIce, 0, 0)) colIceBot = true; +if (checkRun()) +{ + runHeld = 100; + runKey = true; +} + +if (checkAttack() and not whipping) +{ + runHeld += 1; + runKey = true; +} + +if (not runKey or (not kLeft and not kRight)) runHeld = 0; + +// allows the character to run left and right +// if state!=DUCKING and state!=LOOKING_UP and state!=CLIMBING +if (state != CLIMBING and state != HANGING) +{ + if (kLeftReleased and approximatelyZero(xVel)) xAcc -= 0.5 + if (kRightReleased and approximatelyZero(xVel)) xAcc += 0.5 + + if (kLeft and not kRight) + { + if (colSolidLeft) + { + // xVel = 3; + if (platformCharacterIs(ON_GROUND) and state != DUCKING) + { + xAcc -= 1; + pushTimer += 10; + //if (not SS_IsSoundPlaying(global.sndPush)) playSound(global.sndPush); + } + } + else if (kLeftPushedSteps > 2) and (facing=LEFT or approximatelyZero(xVel)) + { + xAcc -= runAcc; + } + facing = LEFT; + //if (platformCharacterIs(ON_GROUND) and abs(xVel) > 0 and alarm[3] < 1) alarm[3] = floor(16/-xVel); + } + + if (kRight and not kLeft) + { + if (colSolidRight) + { + // xVel = 3; + if (platformCharacterIs(ON_GROUND) and state != DUCKING) + { + xAcc += 1; + pushTimer += 10; + //if (not SS_IsSoundPlaying(global.sndPush)) playSound(global.sndPush); + } + } + else if (kRightPushedSteps > 2 or colSolidLeft) and (facing=RIGHT or approximatelyZero(xVel)) + { + xAcc += runAcc; + } + facing = RIGHT; + //if (platformCharacterIs(ON_GROUND) and abs(xVel) > 0 and alarm[3] < 1) alarm[3] = floor(16/xVel); + } +} + +/****************************************** + + LADDERS + +*******************************************/ + +if (state == CLIMBING) +{ + if (instance_exists(oCape)) + { + oCape.open = false; + } + kJumped = false; + ladderTimer = 10; + ladder = collision_point(x, y, oLadder, 0, 0); + if (ladder) x = ladder.x + 8; + + if (kLeft) facing = LEFT; + else if (kRight) facing = RIGHT; + if (kUp) + { + if (collision_point(x, y-8, oLadder, 0, 0) or collision_point(x, y-8, oLadderTop, 0, 0)) + { + yAcc -= climbAcc; + if (alarm[2] < 1) alarm[2] = 8; + } + } + else if (kDown) + { + if (collision_point(x, y+8, oLadder, 0, 0) or collision_point(x, y+8, oLadderTop, 0, 0)) + { + yAcc += climbAcc; + if (alarm[2] < 1) alarm[2] = 8; + } + else + state = FALLING; + if (colBot) state = STANDING; + } + + if (kJumpPressed and not whipping) + { + if (kLeft) + xVel = -departLadderXVel; + else if (kRight) + xVel = departLadderXVel; + else + xVel = 0; + yAcc += departLadderYVel; + state = JUMPING; + jumpButtonReleased = 0; + jumpTime = 0; + ladderTimer = 5; + } +} +else +{ + if (ladderTimer > 0) ladderTimer -= 1; +} + +if (platformCharacterIs(IN_AIR) and state != HANGING) +{ + yAcc += gravityIntensity; +} + +// Player has landed +if ((colBot or colPlatBot) and platformCharacterIs(IN_AIR) and yVel >= 0) +{ + if (not colPlat or colBot) + { + yVel = 0; + yAcc = 0; + state = RUNNING; + jumps = 0; + } + //playSound(global.sndLand); +} +if ((colBot or colPlatBot) and not colPlat) yVel = 0; + +// Player has just walked off of the edge of a solid +if (colBot == 0 and (not colPlatBot or colPlat) and platformCharacterIs(ON_GROUND)) +{ + state = FALLING; + yAcc += grav; + kJumped = true; + if (global.hasGloves) hangCount = 5; +} + +if (colTop) +{ + if (dead or stunned) yVel = -yVel * 0.8; + else if (state == JUMPING) yVel = abs(yVel*0.3) +} + +if (colLeft and facing == LEFT) or (colRight and facing == RIGHT) +{ + if (dead or stunned) xVel = -xVel * 0.5; + else xVel = 0; +} + +/****************************************** + + JUMPING + +*******************************************/ + +if (kJumpReleased and platformCharacterIs(IN_AIR)) +{ + kJumped = true; +} +else if (platformCharacterIs(ON_GROUND)) +{ + oCape.open = false; + kJumped = false; +} + +if (kJumpPressed and collision_point(x, y, oWeb, 0, 0)) +{ + obj = instance_place(x, y, oWeb); + obj.life -= 1; + yAcc += initialJumpAcc * 2; + yVel -= 3; + xAcc += xVel/2; + + state = JUMPING; + jumpButtonReleased = 0; + jumpTime = 0; + + grav = gravNorm; +} +else if (kJumpPressed and colWaterTop) +{ + yAcc += initialJumpAcc * 2; + yVel -= 3; + xAcc += xVel/2; + + state = JUMPING; + jumpButtonReleased = 0; + jumpTime = 0; + + grav = gravNorm; +} +else if (global.hasCape and kJumpPressed and kJumped and platformCharacterIs(IN_AIR)) +{ + if (not oCape.open) oCape.open = true; + else oCape.open = false; +} +else if (global.hasJetpack and kJump and kJumped and platformCharacterIs(IN_AIR) and jetpackFuel > 0) +{ + yAcc += initialJumpAcc; + yVel = -1; + jetpackFuel -= 1; + if (alarm[10] < 1) alarm[10] = 3; + + state = JUMPING; + jumpButtonReleased = 0; + jumpTime = 0; + + grav = 0; +} +else if (platformCharacterIs(ON_GROUND) and kJumpPressed and fallTimer == 0) +{ + if (xVel > 3 or xVel < -3) + { + yAcc += initialJumpAcc * 2; + xAcc += xVel * 2; + } + else + { + yAcc += initialJumpAcc * 2; + xAcc += xVel/2; + } + + if (global.hasJordans) + { + yAcc *= 3; + yAccLimit = 12; + grav = 0.5; + } + else if (global.hasSpringShoes) yAcc *= 1.5; + else + { + yAccLimit = 6; + grav = gravNorm; + } + + playSound(global.sndJump); + + pushTimer = 0; + + // the "state" gets changed to JUMPING later on in the code + state = FALLING; + // "variable jumping" states + jumpButtonReleased = 0; + jumpTime = 0; +} + +if (jumpTime < jumpTimeTotal) jumpTime += 1; +//let the character continue to jump +if (kJump == 0) jumpButtonReleased = 1; +if (jumpButtonReleased) jumpTime = jumpTimeTotal; + +gravityIntensity = (jumpTime/jumpTimeTotal) * grav; + +if (kUp and platformCharacterIs(ON_GROUND) and not colLadder) +{ + looking = UP; + if (xVel == 0 and xAcc == 0) state = LOOKING_UP; +} +else looking = 0; + +if (not kUp and state == LOOKING_UP) +{ + state=STANDING +} + +/****************************************** + + HANGING + +*******************************************/ + +if (not colTop) +{ +if (global.hasGloves and yVel > 0) +{ + if (hangCount == 0 and y > 16 and !platformCharacterIs(ON_GROUND) and kRight and colRight and + (collision_point(x+9, y-5, oSolid, 0, 0) or collision_point(x+9, y-6, oSolid, 0, 0))) + { + state = HANGING; + move_snap(1, 8); + yVel = 0; + yAcc = 0; + grav = 0; + } + else if (hangCount == 0 and y > 16 and !platformCharacterIs(ON_GROUND) and kLeft and colLeft and + (collision_point(x-9, y-5, oSolid, 0, 0) or collision_point(x-9, y-6, oSolid, 0, 0))) + { + state = HANGING; + move_snap(1, 8); + yVel = 0; + yAcc = 0; + grav = 0; + } +} +else if (hangCount == 0 and y > 16 and !platformCharacterIs(ON_GROUND) and kRight and colRight and + (collision_point(x+9, y-5, oTree, 0, 0) or collision_point(x+9, y-6, oTree, 0, 0))) +{ + state = HANGING; + move_snap(1, 8); + yVel = 0; + yAcc = 0; + grav = 0; +} +else if (hangCount == 0 and y > 16 and !platformCharacterIs(ON_GROUND) and kLeft and colLeft and + (collision_point(x-9, y-5, oTree, 0, 0) or collision_point(x-9, y-6, oTree, 0, 0))) +{ + state = HANGING; + move_snap(1, 8); + yVel = 0; + yAcc = 0; + grav = 0; +} +else if (hangCount == 0 and y > 16 and !platformCharacterIs(ON_GROUND) and kRight and colRight and + (collision_point(x+9, y-5, oSolid, 0, 0) or collision_point(x+9, y-6, oSolid, 0, 0)) and + not collision_point(x+9, y-9, oSolid, 0, 0) and not collision_point(x, y+9, oSolid, 0, 0)) +{ + state = HANGING; + move_snap(1, 8); + yVel = 0; + yAcc = 0; + grav = 0; +} +else if (hangCount == 0 and y > 16 and !platformCharacterIs(ON_GROUND) and kLeft and colLeft and + (collision_point(x-9, y-5, oSolid, 0, 0) or collision_point(x-9, y-6, oSolid, 0, 0)) and + not collision_point(x-9, y-9, oSolid, 0, 0) and not collision_point(x, y+9, oSolid, 0, 0)) +{ + state = HANGING; + move_snap(1, 8); + yVel = 0; + yAcc = 0; + grav = 0; +} + +if (hangCount == 0 and y > 16 and !platformCharacterIs(ON_GROUND) and state == FALLING and + (collision_point(x, y-5, oArrow, 0, 0) or collision_point(x, y-6, oArrow, 0, 0)) and + not collision_point(x, y-9, oArrow, 0, 0) and not collision_point(x, y+9, oArrow, 0, 0)) +{ + obj = instance_nearest(x, y-5, oArrow); + if (obj.stuck) + { + state = HANGING; + // move_snap(1, 8); + yVel = 0; + yAcc = 0; + grav = 0; + } +} + +/* +if (hangCount == 0 and y > 16 and !platformCharacterIs(ON_GROUND) and state == FALLING and + (collision_point(x, y-5, oTreeBranch, 0, 0) or collision_point(x, y-6, oTreeBranch, 0, 0)) and + not collision_point(x, y-9, oTreeBranch, 0, 0) and not collision_point(x, y+9, oTreeBranch, 0, 0)) +{ + state = HANGING; + // move_snap(1, 8); + yVel = 0; + yAcc = 0; + grav = 0; +} +*/ + +} + +if (hangCount > 0) hangCount -= 1; + +if (state == HANGING) +{ + if (instance_exists(oCape)) oCape.open = false; + kJumped = false; + + if (kDown and kJumpPressed) + { + grav = gravNorm; + state = FALLING; + yAcc -= grav; + hangCount = 5; + if (global.hasGloves) hangCount = 10; + } + else if (kJumpPressed) + { + grav = gravNorm; + if ((facing == RIGHT and kLeft) or (facing == LEFT and kRight)) + { + state = FALLING; + yAcc -= grav; + } + else + { + state = JUMPING; + yAcc += initialJumpAcc * 2; + if (facing == RIGHT) x -= 2; + else x += 2; + } + hangCount = hangCountMax; + } + + if ((facing == LEFT and not isCollisionLeft(2)) or + (facing == RIGHT and not isCollisionRight(2))) + { + grav = gravNorm; + state = FALLING; + yAcc -= grav; + hangCount = 4; + } +} +else +{ + grav = gravNorm; +} + +// pressing down while standing +if (kDown and platformCharacterIs(ON_GROUND) and not whipping) +{ + if (colBot) + { + state = DUCKING; + } + else if colPlatBot + { + // climb down ladder if possible, else jump down + fallTimer = 0; + if (not colBot) + { + ladder = 0; + ladder = instance_place(x, y+16, oLadder); + if (instance_exists(ladder)) + { + if (abs(x-(ladder.x+8)) < 4) + { + x = ladder.x + 8; + + xVel = 0; + yVel = 0; + xAcc = 0; + yAcc = 0; + state = CLIMBING; + } + } + else + { + y += 1; + state = FALLING; + yAcc += grav; + } + } + else + { + //the character can't move down because there is a solid in the way + state = RUNNING; + } + } +} +if (not kDown and state == DUCKING) +{ + state = STANDING; + xVel = 0; + xAcc = 0; +} +if (xVel == 0 and xAcc == 0 and state == RUNNING) +{ + state = STANDING; +} +if (xAcc != 0 and state == STANDING) +{ + state = RUNNING; +} +if (yVel < 0 and platformCharacterIs(IN_AIR) and state != HANGING) +{ + state = JUMPING; +} +if (yVel > 0 and platformCharacterIs(IN_AIR) and state != HANGING) +{ + state = FALLING; + setCollisionBounds(-5, -6, 5, 8); +} +else setCollisionBounds(-5, -8, 5, 8); + +// CLIMB LADDER +colPointLadder = collision_point(x, y, oLadder, 0, 0) or collision_point(x, y, oLadderTop, 0, 0); + +if ((kUp and platformCharacterIs(IN_AIR) and collision_point(x, y-8, oLadder, 0, 0) and ladderTimer == 0) or + (kUp and colPointLadder and ladderTimer == 0) or + (kDown and colPointLadder and ladderTimer == 0 and platformCharacterIs(ON_GROUND) and collision_point(x, y+9, oLadderTop, 0, 0) and xVel == 0)) +{ + ladder = 0; + ladder = instance_place(x, y-8, oLadder); + if (instance_exists(ladder)) + { + if (abs(x-(ladder.x+8)) < 4) + { + x = ladder.x + 8; + if (not collision_point(x, y, oLadder, 0, 0) and + not collision_point(x, y, oLadderTop, 0, 0)) + { + y = ladder.y + 14; + } + + xVel = 0; + yVel = 0; + xAcc = 0; + yAcc = 0; + state = CLIMBING; + } + } +} + +/* +if (sprite_index == sDuckToHangL or sprite_index == sDamselDtHL) +{ + ladder = 0; + if (facing == LEFT and collision_rectangle(x-8, y, x, y+16, oLadder, 0, 0) and not collision_point(x-4, y+16, oSolid, 0, 0)) + { + ladder = instance_nearest(x-4, y+16, oLadder); + } + else if (facing == RIGHT and collision_rectangle(x, y, x+8, y+16, oLadder, 0, 0) and not collision_point(x+4, y+16, oSolid, 0, 0)) + { + ladder = instance_nearest(x+4, y+16, oLadder); + } + + if (ladder) + { + x = ladder.x + 8; + + xVel = 0; + yVel = 0; + xAcc = 0; + yAcc = 0; + state = CLIMBING; + } +} +*/ +/* +if (colLadder and state == CLIMBING and kJumpPressed and not whipping) +{ + if (kLeft) + xVel = -departLadderXVel; + else if (kRight) + xVel = departLadderXVel; + else + xVel = 0; + yAcc += departLadderYVel; + state = JUMPING; + jumpButtonReleased = 0; + jumpTime = 0; + ladderTimer = 5; +} +*/ + +// Calculate horizontal/vertical friction +if (state == CLIMBING) +{ + xFric = frictionClimbingX; + yFric = frictionClimbingY; +} +else +{ + if (runKey and platformCharacterIs(ON_GROUND) and runHeld >= 10) + { + if (kLeft) // run + { + xVel -= 0.1; + xVelLimit = 6; + xFric = frictionRunningFastX; + } + else if (kRight) + { + xVel += 0.1; + xVelLimit = 6; + xFric = frictionRunningFastX; + } + } + else if (state == DUCKING) + { + if (xVel<2 and xVel>-2) + { + xFric = 0.2 + xVelLimit = 3; + image_speed = 0.8; + } + else if (kLeft and global.downToRun) // run + { + xVel -= 0.1; + xVelLimit = 6; + xFric = frictionRunningFastX; + } + else if (kRight and global.downToRun) + { + xVel += 0.1; + xVelLimit = 6; + xFric = frictionRunningFastX; + } + else + { + xVel *= 0.8; + if (xVel < 0.5) xVel = 0; + xFric = 0.2 + xVelLimit = 3; + image_speed = 0.8; + } + } + else + { + //decrease the friction when the character is "flying" + if (platformCharacterIs(IN_AIR)) + { + if (dead or stunned) xFric = 1.0; + else xFric = 0.8; + } + else + { + xFric = frictionRunningX; + } + } + + // Stuck on web or underwater + if (collision_point(x, y, oWeb, 0, 0)) + { + xFric = 0.2; + yFric = 0.2; + fallTimer = 0; + } + else if (collision_point(x, y, oWater, -1, -1)) + { + if (instance_exists(oCape)) oCape.open = false; + + if (state == FALLING and yVel > 0) + { + yFric = 0.5; + } + else if (not collision_point(x, y-9, oWater, -1, -1)) + { + yFric = 1; + } + else + { + yFric = 0.9; + } + } + else + { + swimming = false; + yFric = 1; + } +} + +if (colIceBot and state != DUCKING and not global.hasSpikeShoes) +{ + xFric = 0.98; + yFric = 1; +} + +// RUNNING + +if (platformCharacterIs(ON_GROUND)) +{ + if (state == RUNNING and kLeft and colLeft) + { + pushTimer += 1; + } + else if (state == RUNNING and kRight and colRight) + { + pushTimer += 1; + } + else + { + pushTimer = 0; + } + + if (platformCharacterIs(ON_GROUND) and not kJump and not kDown and not runKey) + { + xVelLimit = 3; + } + + + // ledge flip + if (state == DUCKING and abs(xVel) < 3 and facing == LEFT and + collision_point(x, y+9, oSolid, 0, 0) and not collision_line(x-1, y+9, x-10, y+9, oSolid, 0, 0) and kLeft) + { + state = DUCKTOHANG; + + if (holdItem) + { + holdItem.held = false; + if (holdItem.type == "Gold Idol") holdItem.y -= 8; + scrDropItem(-1, -4); + } + + with oMonkey + { + // knock off monkeys that grabbed you + if (status == 7) + { + xVel = -1; + yVel = -4; + status = 1; + vineCounter = 20; + grabCounter = 60; + } + } + } + else if (state == DUCKING and abs(xVel) < 3 and facing == RIGHT and + collision_point(x, y+9, oSolid, 0, 0) and not collision_line(x+1, y+9, x+10, y+9, oSolid, 0, 0) and kRight) + { + state = DUCKTOHANG; + + if (holdItem) + { + // holdItem.held = false; + if (holdItem.type == "Gold Idol") holdItem.y -= 8; + scrDropItem(1, -4); + } + + with oMonkey + { + // knock off monkeys that grabbed you + if (status == 7) + { + xVel = 1; + yVel = -4; + status = 1; + vineCounter = 20; + grabCounter = 60; + } + } + } +} + +if (state == DUCKTOHANG) +{ + x = xPrev; + y = yPrev; + xVel = 0; + yVel = 0; + xAcc = 0; + yAcc = 0; + grav = 0; +} + +// PARACHUTE AND CAPE +if (instance_exists(oParachute)) +{ + yFric = 0.5; +} +if (instance_exists(oCape)) +{ + if (oCape.open) yFric = 0.5; +} + +if (pushTimer > 100) pushTimer = 100; + +// limits the acceleration if it is too extreme +if (xAcc > xAccLimit) xAcc = xAccLimit; +else if (xAcc < -xAccLimit) xAcc = -xAccLimit; +if (yAcc > yAccLimit) yAcc = yAccLimit; +else if (yAcc < -yAccLimit) yAcc = -yAccLimit; + +// applies the acceleration +xVel += xAcc; +if (dead or stunned) yVel += 0.6; +else yVel += yAcc; + +// nullifies the acceleration +xAcc = 0; +yAcc = 0; + +// applies the friction to the velocity, now that the velocity has been calculated +xVel *= xFric; +yVel *= yFric; + +// apply ball and chain +if (instance_exists(oBall)) +{ + if (distance_to_object(oBall) >= 24) + { + if (xVel > 0 and oBall.x < x and abs(oBall.x-x) > 24) xVel = 0; + if (xVel < 0 and oBall.x > x and abs(oBall.x-x) > 24) xVel = 0; + if (yVel > 0 and oBall.y < y and abs(oBall.y-y) > 24) + { + if (abs(oBall.x-x) < 1) + { + x = oBall.x; + } + else if (oBall.x < x and not kRight) + { + if (xVel > 0) xVel *= -0.25; + else if (xVel == 0) xVel -= 1; + } + else if (oBall.x > x and not kLeft) + { + if (xVel < 0) xVel *= -0.25; + else if (xVel == 0) xVel += 1; + } + yVel = 0; + fallTimer = 0; + } + if (yVel < 0 and oBall.y > y and abs(oBall.y-y) > 24) yVel = 0; + } +} + +// apply the limits since the velocity may be too extreme +if (not dead and not stunned) +{ + if (xVel > xVelLimit) xVel = xVelLimit; + else if (xVel < -xVelLimit) xVel = -xVelLimit; +} +if (yVel > yVelLimit) yVel = yVelLimit; +else if (yVel < -yVelLimit) yVel = -yVelLimit; + +// approximates the "active" variables +if approximatelyZero(xVel) xVel=0 +if approximatelyZero(yVel) yVel=0 +if approximatelyZero(xAcc) xAcc=0 +if approximatelyZero(yAcc) yAcc=0 + +// prepares the character to move up a hill +// we need to use the "slopeYPrev" variable later to know the "true" y previous value +// keep this condition the same +if maxSlope>0 and platformCharacterIs(ON_GROUND) and xVel!=0 +{ + slopeYPrev=y + for(y=y;y>=slopeYPrev-maxSlope;y-=1) + if colTop + break + slopeChangeInY=slopeYPrev-y +} +else + slopeChangeInY=0 + +// moves the character, and balances out the effects caused by other processes +// keep this condition the same +if maxSlope*abs(xVel)>0 and platformCharacterIs(ON_GROUND) +{ + // we need to check if we should dampen out the speed as the character runs on upward slopes + xPrev=x + yPrev=slopeYPrev // we don't want to use y, because y is too high + yPrevHigh=y // we'll use the higher previous variable later + moveTo(xVel,yVel+slopeChangeInY) + dist=point_distance(xPrev,yPrev,x,y)// overall distance that has been traveled + // we should have only ran at xVel + if dist>abs(xVelInteger) + { + // show_message(string(dist)+ " "+string(abs(xVelInteger))) + excess=dist-abs(xVelInteger) + if(xVelInteger<0) + excess*=-1 + // move back since the character moved too far + x=xPrev + y=yPrevHigh // we need the character to be high so the character can move down + // this time we'll move the correct distance, but we need to shorten out the xVel a little + // these lines can be changed for different types of slowing down when running up hills + ratio=abs(xVelInteger)/dist*0.9 //can be changed + moveTo( round(xVelInteger*ratio),round(yVelInteger*ratio+slopeChangeInY) ) + } +} +else +{ + // we simply move xVel and yVel while in the air or on a ladder + moveTo(xVel,yVel) +} +// move the character downhill if possible +// we need to multiply maxDownSlope by the absolute value of xVel since the character normally runs at an xVel larger than 1 +if not colBot and maxDownSlope>0 and xVelInteger!=0 and platformCharacterIs(ON_GROUND) +{ + //the character is floating just above the slope, so move the character down + upYPrev=y + for(y=y;y<=upYPrev+maxDownSlope;y+=1) + if colBot // we hit a solid below + { + upYPrev=y // I know that this doesn't seem to make sense, because of the name of the variable, but it all works out correctly after we break out of this loop + break + } + y=upYPrev +} + +//figures out what the sprite index of the character should be +characterSprite(); + +//sets the previous state and the previously previous state +statePrevPrev = statePrev; +statePrev = state; + +//calculates the image_speed based on the character's velocity +if (state == RUNNING or state == DUCKING or state == LOOKING_UP) +{ + if (state == RUNNING or state == LOOKING_UP) image_speed = abs(xVel) * runAnimSpeed + 0.1; +} + +if (state == CLIMBING) image_speed = sqrt(sqr(abs(xVel))+sqr(abs(yVel))) * climbAnimSpeed +if (xVel >= 4 or xVel <= -4) +{ + image_speed = 1; + if (platformCharacterIs(ON_GROUND)) setCollisionBounds(-8, -8, 8, 8); + else setCollisionBounds(-5, -8, 5, 8); +} +else setCollisionBounds(-5, -8, 5, 8); +if (whipping) image_speed = 1; +if (state == DUCKTOHANG) +{ + image_index = 0; + image_speed = 0.8; +} +//limit the image_speed at 1 so the animation always looks good +if (image_speed > 1) image_speed = 1; diff --git a/samples/Game Maker Language/jsonion.gml b/samples/Game Maker Language/jsonion.gml new file mode 100644 index 00000000..e4d2a6cb --- /dev/null +++ b/samples/Game Maker Language/jsonion.gml @@ -0,0 +1,1861 @@ +// Originally from /jsonion.gml in JSOnion +// JSOnion v1.0.0d is licensed under the MIT licence. You may freely adapt and use this library in commercial and non-commercial projects. + +#define __jso_gmt_tuple +{ + + /** + tuple(>element_0<, >element_1<, ..., >element_n<): Return an n-tuple + @author: GameGeisha + @version: 1.2 (GMTuple) + */ + + //Position, address table and data + var pos, addr_table, data; + pos = 6*argument_count+4; + addr_table = ""; + data = ""; + + //Build the tuple element-by-element + var i, ca, isstr, datastr; + for (i=0; ith element of + @author: GameGeisha + @version: 1.2 (GMTuple) + */ + + //Capture arguments + var t, n, size; + t = argument0; + n = argument1; + size = __jso_gmt_size(t); + + //Search for the bounding positions for the th element in the address table + var start, afterend, isstr; + isstr = ord(string_char_at(t, 4+6*n))-$30; + start = real(string_copy(t, 5+6*n, 5)); + if (n < size-1) { + afterend = real(string_copy(t, 11+6*n, 5)); + } else { + afterend = string_length(t)+1; + } + + //Return the th element with the correct type + if (isstr) { + return string_copy(t, start, afterend-start); + } + else { + return real(string_copy(t, start, afterend-start)); + } + +} + +#define __jso_gmt_size +{ + + /** + size(tuple_source): Return the size of + @author: GameGeisha + @version: 1.2 (GMTuple) + */ + + return real(string_copy(argument0, 1, 3)); + +} + +#define __jso_gmt_numtostr +{ + + /** + __gmt_numtostr(num): Return string representation of . Decimal numbers expressed as scientific notation + with double precision (i.e. 15 digits) + @author: GameGeisha + @version: 1.2 (edited) + */ + if (frac(argument0) == 0) { + return string(argument0); + } + + var mantissa, exponent; + exponent = floor(log10(abs(argument0))); + mantissa = string_format(argument0/power(10,exponent), 15, 14); + var i, ca; + i = string_length(mantissa); + do { + ca = string_char_at(mantissa, i); + i -= 1; + } until (ca != "0") + if (ca != ".") { + mantissa = string_copy(mantissa, 1, i+1); + } + else { + mantissa = string_copy(mantissa, 1, i); + } + if (exponent != 0) { + return mantissa + "e" + string(exponent); + } + else { + return mantissa; + } + +} + +#define __jso_gmt_test_all +{ + + /** + test_all(): Runs all test suites + @author: GameGeisha + @version: 1.2 (GMTuple) + */ + + //Automated testing sequence + __jso_gmt_test_elem(); + __jso_gmt_test_size(); + __jso_gmt_test_numtostr(); + +} + +#define __jso_gmt_test_numtostr +{ + + /** + _test_numtostr(): Runs number-to-string tests + @author: GameGeisha + @version: 1.2 (GMTuple) + */ + + var tolerance; + tolerance = 1/10000000000; + + if (real(__jso_gmt_numtostr(9)) != 9) { + show_message("Scientific notation conversion failed for 1-digit integer! Result: " + __jso_gmt_numtostr(9)); + } + if (real(__jso_gmt_numtostr(500)) != 500) { + show_message("Scientific notation conversion failed for 3-digit integer! Result: " + __jso_gmt_numtostr(500)); + } + if (abs(real(__jso_gmt_numtostr(pi))-pi) > tolerance) { + show_message("Scientific notation conversion failed for pi! Result: " + __jso_gmt_numtostr(pi)); + } + if (abs(real(__jso_gmt_numtostr(104729.903455))-104729.903455) > tolerance) { + show_message("Scientific notation conversion failed for large decimal number! Result: " + __jso_gmt_numtostr(104729.903455)); + } + if (abs(real(__jso_gmt_numtostr(-pi))+pi) > tolerance) { + show_message("Scientific notation conversion failed for -pi! Result: " + __jso_gmt_numtostr(-pi)); + } + if (abs(real(__jso_gmt_numtostr(1/pi))-1/pi) > tolerance) { + show_message("Scientific notation conversion failed for 1/pi! Result: " + __jso_gmt_numtostr(1/pi)); + } + +} + +#define __jso_gmt_test_elem +{ + + /** + _test_elem(): Runs tuple element retrieval tests + @author: GameGeisha + @version: 1.2 (GMTuple) + */ + + if (__jso_gmt_elem(__jso_gmt_tuple("Qblock", "kll"), 0) != "Qblock") { + show_message("Element retrieval failed for simple string. #Should be:Qblock#Actual:" + __jso_gmt_elem(__jso_gmt_tuple("Qblock"), 0)); + } + if (__jso_gmt_elem(__jso_gmt_tuple(9, "Q", -7), 0) != 9) { + show_message("Element retrieval failed for simple number. #Should be 9#Actual:" + string(__jso_gmt_elem(__jso_gmt_tuple(9, "Q", 7), 0))); + } + if (__jso_gmt_elem(__jso_gmt_tuple("Qblock", "", "Negg"), 1) != "") { + show_message("Element retrieval failed for empty string#Should be empty string#Actual:"+string(__jso_gmt_elem(__jso_gmt_tuple("Qblock", "", "Negg"), 0))); + } + + if (__jso_gmt_elem(__jso_gmt_elem(__jso_gmt_tuple("Not this", __jso_gmt_tuple(0, 1, 2, 3), "Waahoo"), 1), 3) != 3) { + show_message("Element retrieval failed in nested tuple. #Should be 3#Actual:" + string(__jso_gmt_elem(__jso_gmt_elem(__jso_gmt_tuple("Not this", __jso_gmt_tuple(0, 1, 2, 3), "Waahoo"), 1), 3))); + } + +} + +#define __jso_gmt_test_size +{ + + /** + _test_size(): Runs tuple size tests + @author: GameGeisha + @version: 1.2 (GMTuple) + */ + + if (__jso_gmt_size(__jso_gmt_tuple("Waahoo", "Negg", 0)) != 3) { + show_message("Bad size for 3-tuple"); + } + if (__jso_gmt_size(__jso_gmt_tuple()) != 0) { + show_message("Bad size for null tuple"); + } + if (__jso_gmt_size(__jso_gmt_tuple(7)) != 1) { + show_message("Bad size for 1-tuple"); + } + if (__jso_gmt_size(__jso_gmt_tuple(1,2,3,4,5,6,7,8,9,10)) != 10) { + show_message("Bad size for 10-tuple"); + } + +} + +#define jso_new_map +{ + /** + jso_new_map(): Create a new map. + JSOnion version: 1.0.0d + */ + return ds_map_create(); +} + +#define jso_new_list +{ + /** + jso_new_list(): Create a new list. + JSOnion version: 1.0.0d + */ + return ds_list_create(); +} + +#define jso_map_add_real +{ + /** + jso_map_add_real(map, key, val): Add the key-value pair : to , where is a real value. + JSOnion version: 1.0.0d + */ + ds_map_add(argument0, argument1, argument2); +} + +#define jso_map_add_string +{ + /** + jso_map_add_string(map, key, str): Add the key-value pair : to , where is a string value. + JSOnion version: 1.0.0d + */ + ds_map_add(argument0, argument1, "s" + argument2); +} + +#define jso_map_add_sublist +{ + /** + jso_map_add_sublist(map, key, sublist): Add the key-value pair : to , where is a list. + JSOnion version: 1.0.0d + */ + ds_map_add(argument0, argument1, "l" + string(argument2)); +} + +#define jso_map_add_submap +{ + /** + jso_map_add_submap(map, key, submap): Add the key-value pair : to , where is a map. + JSOnion version: 1.0.0d + */ + ds_map_add(argument0, argument1, "m" + string(argument2)); +} + +#define jso_map_add_integer +{ + /** + jso_map_add_integer(map, key, int): Add the key-value pair : to , where is a integer value. + JSOnion version: 1.0.0d + */ + ds_map_add(argument0, argument1, floor(argument2)); +} + +#define jso_map_add_boolean +{ + /** + jso_map_add_boolean(map, key, bool): Add the key-value pair : to , where is a boolean value. + JSOnion version: 1.0.0d + */ + if (argument2) { + ds_map_add(argument0, argument1, "btrue"); + } else { + ds_map_add(argument0, argument1, "bfalse"); + } +} + +#define jso_list_add_real +{ + /** + jso_list_add_real(list, val): Append the real value to . + JSOnion version: 1.0.0d + */ + ds_list_add(argument0, argument1); +} + +#define jso_list_add_string +{ + /** + jso_list_add_string(list, str): Append the string value to . + JSOnion version: 1.0.0d + */ + ds_list_add(argument0, "s" + argument1); +} + +#define jso_list_add_sublist +{ + /** + jso_list_add_sublist(list, sublist): Append the list to . + JSOnion version: 1.0.0d + */ + ds_list_add(argument0, "l" + string(argument1)); +} + +#define jso_list_add_submap +{ + /** + jso_list_add_submap(list, submap): Append the map to . + JSOnion version: 1.0.0d + */ + ds_list_add(argument0, "m" + string(argument1)); +} + +#define jso_list_add_integer +{ + /** + jso_list_add_integer(list, int): Append the integer to . + JSOnion version: 1.0.0d + */ + ds_list_add(argument0, floor(argument1)); +} + +#define jso_list_add_boolean +{ + /** + jso_list_add_boolean(list, bool): Append the boolean value to . + JSOnion version: 1.0.0d + */ + if (argument1) { + ds_list_add(argument0, "btrue"); + } else { + ds_list_add(argument0, "bfalse"); + } +} + +#define jso_map_get +{ + /** + jso_map_get(map, key): Retrieve the value stored in with the key value , with the correct type. + JSOnion version: 1.0.0d + */ + + //Grab the value + var v; + v = ds_map_find_value(argument0, argument1); + + //String; could be string, map or list + if (is_string(v)) { + switch (string_char_at(v, 1)) { + case "s": + return string_delete(v, 1, 1); + break; + case "l": case "m": + return real(string_delete(v, 1, 1)); + break; + case "b": + if (v == "btrue") { + return true; + } + else if (v == "bfalse") { + return false; + } + else { + show_error("Invalid boolean value.", true); + } + break; + default: show_error("Invalid map contents.", true); break; + } + } + + //Real; return real value as-is + else { + return v; + } +} + +#define jso_map_get_type +{ + /** + jso_map_get_type(map, key): Return the type of value to which the key value is mapped to in . + JSOnion version: 1.0.0d + */ + + //Grab the value + var v; + v = ds_map_find_value(argument0, argument1); + + //String; could be string, map or list + if (is_string(v)) { + switch (string_char_at(v, 1)) { + case "s": + return jso_type_string; + break; + case "l": + return jso_type_list; + break; + case "m": + return jso_type_map; + break; + case "b": + return jso_type_boolean; + break; + default: show_error("Invalid map content type.", true); break; + } + } + + //Real + else { + return jso_type_real; + } +} + +#define jso_list_get +{ + /** + jso_list_get(list, index): Retrieve the value stored in at position , with the correct type. + JSOnion version: 1.0.0d + */ + + //Grab the value + var v; + v = ds_list_find_value(argument0, argument1); + + //String; could be string, map or list + if (is_string(v)) { + switch (string_char_at(v, 1)) { + case "s": + return string_delete(v, 1, 1); + break; + case "l": case "m": + return real(string_delete(v, 1, 1)); + break; + case "b": + if (v == "btrue") { + return true; + } + else if (v == "bfalse") { + return false; + } + else { + show_error("Invalid boolean value.", true); + } + break; + default: show_error("Invalid list contents.", true); break; + } + } + + //Real; return real value as-is + else { + return v; + } +} + +#define jso_list_get_type +{ + /** + jso_list_get_type(list, index): Retrieve the type of value found at position of . + JSOnion version: 1.0.0d + */ + + //Grab the value + var v; + v = ds_list_find_value(argument0, argument1); + + //String; could be string, map or list + if (is_string(v)) { + switch (string_char_at(v, 1)) { + case "s": + return jso_type_string; + break; + case "l": + return jso_type_list; + break; + case "m": + return jso_type_map; + break; + case "b": + return jso_type_boolean; + break; + default: show_error("Invalid list content type.", true); break; + } + } + + //Real + else { + return jso_type_real; + } +} + +#define jso_cleanup_map +{ + /** + jso_cleanup_map(map): Recursively free up . + JSOnion version: 1.0.0d + */ + + //Loop through all keys + var i, l, k; + l = ds_map_size(argument0); + k = ds_map_find_first(argument0); + for (i=0; i. + JSOnion version: 1.0.0d + */ + + //Loop through all elements + var i, l, v; + l = ds_list_size(argument0); + for (i=0; i): Return a JSON-encoded version of real value . + This uses scientific notation with up to 15 significant digits for decimal values. + For integers, it just uses string(). + This is adapted from the same algorithm used in GMTuple. + JSOnion version: 1.0.0d + */ + + return __jso_gmt_numtostr(argument0); +} + +#define jso_encode_string +{ + /** + jso_encode_string(str): Return a JSON-encoded version of string . + JSOnion version: 1.0.0d + */ + + //Iteratively reconstruct the string + var i, l, s, c; + s = ""; + l = string_length(argument0); + for (i=1; i<=l; i+=1) { + //Replace escape characters + c = string_char_at(argument0, i); + switch (ord(c)) { + case 34: case 92: case 47: //Double quotes, backslashes and slashes + s += "\" + c; + break; + case 8: //Backspace + s += "\b"; + break; + case 12: //Form feed + s += "\f"; + break; + case 10: //New line + s += "\n"; + break; + case 13: //Carriage return + s += "\r"; + break; + case 9: //Horizontal tab + s += "\t"; + break; + default: //Not an escape character + s += c; + break; + } + } + + //Add quotes + return '"' + s + '"'; +} + +#define jso_encode_list +{ + /** + jso_encode_list(list): Return a JSON-encoded version of list . + JSOnion version: 1.0.0d + */ + + //Iteratively encode each element + var i, l, s; + s = ""; + l = ds_list_size(argument0); + for (i=0; i 0) { + s += ","; + } + //Select correct encoding for each element, then recursively encode each + switch (jso_list_get_type(argument0, i)) { + case jso_type_real: + s += jso_encode_real(jso_list_get(argument0, i)); + break; + case jso_type_string: + s += jso_encode_string(jso_list_get(argument0, i)); + break; + case jso_type_map: + s += jso_encode_map(jso_list_get(argument0, i)); + break; + case jso_type_list: + s += jso_encode_list(jso_list_get(argument0, i)); + break; + case jso_type_boolean: + s += jso_encode_boolean(jso_list_get(argument0, i)); + break; + } + } + + //Done, add square brackets + return "[" + s + "]"; +} + +#define jso_encode_map +{ + /** + jso_encode_map(map): Return a JSON-encoded version of map . + JSOnion version: 1.0.0d + */ + + //Go through every key-value pair + var i, l, k, s; + s = ""; + l = ds_map_size(argument0); + k = ds_map_find_first(argument0); + for (i=0; i 0) { + s += ","; + } + //Find the key and encode it + if (is_real(k)) { + s += jso_encode_real(k); + } else { + s += jso_encode_string(k); + } + //Add the : separator + s += ":"; + //Select correct encoding for each value, then recursively encode each + switch (jso_map_get_type(argument0, k)) { + case jso_type_real: + s += jso_encode_real(jso_map_get(argument0, k)); + break; + case jso_type_string: + s += jso_encode_string(jso_map_get(argument0, k)); + break; + case jso_type_map: + s += jso_encode_map(jso_map_get(argument0, k)); + break; + case jso_type_list: + s += jso_encode_list(jso_map_get(argument0, k)); + break; + case jso_type_boolean: + s += jso_encode_boolean(jso_map_get(argument0, k)); + break; + } + //Get next key + k = ds_map_find_next(argument0, k); + } + + //Done, add braces + return "{" + s + "}"; +} + +#define jso_encode_integer +{ + /** + jso_encode_integer(int): Return a JSON-encoded version of the integer value . + JSOnion version: 1.0.0d + */ + return string(floor(argument0)); +} + +#define jso_encode_boolean +{ + /** + jso_encode_boolean(bool): Return a JSON-encoded version of the boolean value . + JSOnion version: 1.0.0d + */ + if (argument0) { + return "true"; + } else { + return "false"; + } +} + +#define jso_decode_map +{ + /** + jso_decode_map(json): Return a JSOnion-compatible map representing the JSON string . + JSOnion version: 1.0.0d + */ + return __jso_gmt_elem(_jso_decode_map(argument0, 1), 0); +} + +#define jso_decode_list +{ + /** + jso_decode_list(json): Return a JSOnion-compatible list representing the JSON string . + JSOnion version: 1.0.0d + */ + return __jso_gmt_elem(_jso_decode_list(argument0, 1), 0); +} + +#define jso_decode_string +{ + /** + jso_decode_string(json): Return a string representing the JSON string . + JSOnion version: 1.0.0d + */ + return __jso_gmt_elem(_jso_decode_string(argument0, 1), 0); +} + +#define jso_decode_boolean +{ + /** + jso_decode_boolean(json): Return a boolean value representing the JSON string . + JSOnion version: 1.0.0d + */ + return __jso_gmt_elem(_jso_decode_boolean(argument0, 1), 0); +} + +#define jso_decode_real +{ + /** + jso_decode_real(json): Return a real value representing the JSON string . + JSOnion version: 1.0.0d + */ + return __jso_gmt_elem(_jso_decode_real(argument0, 1), 0); +} + +#define jso_decode_integer +{ + /** + jso_decode_integer(json): Return an integer value representing the JSON string . + JSOnion version: 1.0.0d + */ + return __jso_gmt_elem(_jso_decode_integer(argument0, 1), 0); +} + +#define _jso_decode_map +{ + /** + _jso_decode_map(json, startindex): Extract a map from JSON string starting at position . + Return a 2-tuple of the extracted map handle and the position after the ending }. + JSOnion version: 1.0.0d + */ + var i, len, map; + i = argument1; + len = string_length(argument0); + map = jso_new_map(); + + //Seek to first { + var c; + c = string_char_at(argument0, i); + if (c != "{") { + do { + i += 1; + c = string_char_at(argument0, i); + if (!_jso_is_whitespace_char(c)) && (c != "{") { + show_error("Cannot parse map at position " + string(i), true); + } + } until (c == "{") + } + i += 1; + + //Read until end of JSON or ending } + var found_end, state, found, current_key; + found_end = false; + state = 0; + for (i=i; i<=len && !found_end; i+=1) { + c = string_char_at(argument0, i); + switch (state) { + //0: Looking for a key or closing } + case 0: + switch (c) { + case "}": + found_end = true; + break; + case '"': + found = _jso_decode_string(argument0, i); + current_key = __jso_gmt_elem(found, 0); + i = __jso_gmt_elem(found, 1)-1; + state = 1; + break; + case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": case "+": case "-": + found = _jso_decode_real(argument0, i); + current_key = __jso_gmt_elem(found, 0); + i = __jso_gmt_elem(found, 1)-1; + state = 1; + break; + default: + if (!_jso_is_whitespace_char(c)) { + show_error("Unexpected character at position " + string(i) + ".", true); + } + break; + } + break; + //1: Looking for the : separator + case 1: + switch (c) { + case ":": + state = 2; + break; + default: + if (!_jso_is_whitespace_char(c)) { + show_error("Unexpected character at position " + string(i) + ".", true); + } + break; + } + break; + //2: Looking for a value + case 2: + switch (c) { + case "[": + found = _jso_decode_list(argument0, i); + jso_map_add_sublist(map, current_key, __jso_gmt_elem(found, 0)); + i = __jso_gmt_elem(found, 1)-1; + state = 3; + break; + case "{": + found = _jso_decode_map(argument0, i); + jso_map_add_submap(map, current_key, __jso_gmt_elem(found, 0)); + i = __jso_gmt_elem(found, 1)-1; + state = 3; + break; + case '"': + found = _jso_decode_string(argument0, i); + jso_map_add_string(map, current_key, __jso_gmt_elem(found, 0)); + i = __jso_gmt_elem(found, 1)-1; + state = 3; + break; + case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": case "+": case "-": + found = _jso_decode_real(argument0, i); + jso_map_add_real(map, current_key, __jso_gmt_elem(found, 0)); + i = __jso_gmt_elem(found, 1)-1; + state = 3; + break; + case "t": case "f": + found = _jso_decode_boolean(argument0, i); + jso_map_add_boolean(map, current_key, __jso_gmt_elem(found, 0)); + i = __jso_gmt_elem(found, 1)-1; + state = 3; + break; + default: + if (!_jso_is_whitespace_char(c)) { + show_error("Unexpected character at position " + string(i) + ".", true); + } + break; + } + break; + //3: Done looking for an entry, want comma or } + case 3: + switch (c) { + case "}": + found_end = true; + break; + case ",": + state = 0; + break; + default: + if (!_jso_is_whitespace_char(c)) { + show_error("Unexpected character at position " + string(i) + ".", true); + } + break; + } + break; + } + } + + //Return extracted map with ending position if the ending } is found + if (found_end) { + return __jso_gmt_tuple(map, i); + } + //Ended too early, throw error + else { + show_error("Unexpected end of map in JSON string.", true); + } +} + +#define _jso_decode_list +{ + /** + _jso_decode_list(json, startindex): Extract a list from JSON string starting at position . + Return a 2-tuple of the extracted list handle and the position after the ending ]. + JSOnion version: 1.0.0d + */ + var i, len, list; + i = argument1; + len = string_length(argument0); + list = jso_new_list(); + + //Seek to first [ + var c; + c = string_char_at(argument0, i); + if (c != "[") { + do { + i += 1; + c = string_char_at(argument0, i); + if (!_jso_is_whitespace_char(c)) && (c != "[") { + show_error("Cannot parse list at position " + string(i), true); + } + } until (c == "[") + } + i += 1; + + //Read until end of JSON or ending ] + var found_end, state, found; + found_end = false; + state = 0; + for (i=i; i<=len && !found_end; i+=1) { + c = string_char_at(argument0, i); + switch (state) { + //0: Looking for an item + case 0: + switch (c) { + case "]": + found_end = true; + break; + case "[": + found = _jso_decode_list(argument0, i); + jso_list_add_sublist(list, __jso_gmt_elem(found, 0)); + i = __jso_gmt_elem(found, 1)-1; + state = 1; + break; + case "{": + found = _jso_decode_map(argument0, i); + jso_list_add_submap(list, __jso_gmt_elem(found, 0)); + i = __jso_gmt_elem(found, 1)-1; + state = 1; + break; + case '"': + found = _jso_decode_string(argument0, i); + jso_list_add_string(list, __jso_gmt_elem(found, 0)); + i = __jso_gmt_elem(found, 1)-1; + state = 1; + break; + case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": case "+": case "-": + found = _jso_decode_real(argument0, i); + jso_list_add_real(list, __jso_gmt_elem(found, 0)); + i = __jso_gmt_elem(found, 1)-1; + state = 1; + break; + case "t": case "f": + found = _jso_decode_boolean(argument0, i); + jso_list_add_boolean(list, __jso_gmt_elem(found, 0)); + i = __jso_gmt_elem(found, 1)-1; + state = 1; + break; + default: + if (!_jso_is_whitespace_char(c)) { + show_error("Unexpected character at position " + string(i) + ".", true); + } + break; + } + break; + //1: Done looking for an item, want comma or ] + case 1: + switch (c) { + case "]": + found_end = true; + break; + case ",": + state = 0; + break; + default: + if (!_jso_is_whitespace_char(c)) { + show_error("Unexpected character at position " + string(i) + ".", true); + } + break; + } + break; + } + } + + //Return extracted list with ending position if the ending ] is found + if (found_end) { + return __jso_gmt_tuple(list, i); + } + //Ended too early, throw error + else { + show_error("Unexpected end of list in JSON string.", true); + } +} + +#define _jso_decode_string +{ + /** + _jso_decode_string(json, startindex): Extract a string from JSON string starting at position . + Return a 2-tuple of the extracted string and the position after the ending double quote. + JSOnion version: 1.0.0d + */ + var i, len, str; + i = argument1; + len = string_length(argument0); + str = ""; + + //Seek to first double quote + var c; + c = string_char_at(argument0, i); + if (c != '"') { + do { + i += 1; + c = string_char_at(argument0, i); + } until (c == '"') + } + i += 1; + + //Read until end of JSON or ending double quote + var found_end, escape_mode; + found_end = false; + escape_mode = false; + for (i=i; i<=len && !found_end; i+=1) { + c = string_char_at(argument0, i); + //Escape mode + if (escape_mode) { + switch (c) { + case '"': case "\": case "/": + str += c; + escape_mode = false; + break; + case "b": + str += chr(8); + escape_mode = false; + break; + case "f": + str += chr(12); + escape_mode = false; + break; + case "n": + str += chr(10); + escape_mode = false; + break; + case "r": + str += chr(13); + escape_mode = false; + break; + case "t": + str += chr(9); + escape_mode = false; + break; + case "u": + var u; + if (len-i < 5) { + show_error("Invalid escape character at position " + string(i) + ".", true); + } else { + str += chr(_jso_hex_to_decimal(string_copy(argument0, i+1, 4))); + escape_mode = false; + i += 4; + } + break; + default: + show_error("Invalid escape character at position " + string(i) + ".", true); + break; + } + } + //Regular mode + else { + switch (c) { + case '"': found_end = true; break; + case "\": escape_mode = true; break; + default: str += c; break; + } + } + } + + //Return extracted string with ending position if the ending double quote is found + if (found_end) { + return __jso_gmt_tuple(str, i); + } + //Ended too early, throw error + else { + show_error("Unexpected end of string in JSON string.", true); + } +} + +#define _jso_decode_boolean +{ + /** + _jso_decode_boolean(json, startindex): Extract a boolean from JSON string starting at position . + Return a 2-tuple of the extracted boolean and the position after the last e. + JSOnion version: 1.0.0d + */ + var i, len, str; + i = argument1; + len = string_length(argument0); + + //Seek to first t or f that can be found + var c; + c = string_char_at(argument0, i); + if (c != "t") && (c != "f") { + do { + i += 1; + c = string_char_at(argument0, i); + if (!_jso_is_whitespace_char(c)) && (c != "t") && (c != "f") { + show_error("Cannot parse boolean value at position " + string(i), true); + } + } until (c == "t") || (c == "f") + } + + //Look for true if t is found + if (c == "t") && (string_copy(argument0, i, 4) == "true") { + return __jso_gmt_tuple(true, i+4); + } + //Look for false if f is found + else if (c == "f") && (string_copy(argument0, i, 5) == "false") { + return __jso_gmt_tuple(false, i+5); + } + //Error: unexpected ending + else { + show_error("Unexpected end of boolean in JSON string.", true); + } +} + +#define _jso_decode_real +{ + /** + _jso_decode_real(json, startindex): Extract a real value from JSON string starting at position . + Return a 2-tuple of the extracted real value and the position after the real value. + JSOnion version: 1.0.0d + */ + var i, len, str; + i = argument1; + len = string_length(argument0); + str = ""; + + //Seek to first character: +, -, or 0-9 + var c; + c = string_char_at(argument0, i); + if (string_pos(c, "0123456789+-") == 0) { + do { + i += 1; + c = string_char_at(argument0, i); + if (!_jso_is_whitespace_char(c)) && (string_pos(c, "0123456789+-") == 0) { + show_error("Cannot parse real value at position " + string(i), true); + } + } until (string_pos(c, "0123456789+-") > 0) + } + + //Determine starting state + var state; + switch (c) { + case "+": case "-": + state = 0; + break; + default: + state = 1; + break; + } + str += c; + i += 1; + + //Loop until no more digits found + var done; + done = false; + for (i=i; i<=len && !done; i+=1) { + c = string_char_at(argument0, i); + switch (state) { + //0: Found a sign, looking for a starting number + case 0: + switch (c) { + case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": + str += c; + state = 1; + break; + default: + show_error("Unexpected character at position " + string(i) + ", expecting a digit.", true); + break; + } + break; + //1: Found a starting digit, looking for decimal dot, e, E, or more digits + case 1: + if (_jso_is_whitespace_char(c)) || (string_pos(c, ":,]}") > 0) { + done = true; + i -= 1; + } else { + switch (c) { + case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": + str += c; + break; + case ".": + str += c; + state = 2; + break; + case "e": case "E": + str += c; + state = 3; + break; + default: + show_error("Unexpected character at position " + string(i) + ", expecting a dot, e, E or a digit.", true); + break; + } + } + break; + //2: Found a decimal dot, looking for more digits + case 2: + switch (c) { + case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": + str += c; + state = -2; + break; + default: + show_error("Unexpected character at position " + string(i) + ", expecting a digit.", true); + break; + } + break; + //-2: Found a decimal dot and a digit after it, looking for more digits, e, or E + case -2: + if (_jso_is_whitespace_char(c)) || (string_pos(c, ":,]}") > 0) { + done = true; + i -= 1; + } else { + switch (c) { + case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": + str += c; + break; + case "e": case "E": + str += c; + state = 3; + break; + default: + show_error("Unexpected character at position " + string(i) + ", expecting an e, E or a digit.", true); + break; + } + } + break; + //3: Found an e/E, looking for +, - or more digits + case 3: + switch (c) { + case "+": case "-": + str += c; + state = 4; + break; + case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": + str += c; + state = 5; + break; + default: + show_error("Unexpected character at position " + string(i) + ", expecting a +, - or a digit.", true); + break; + } + break; + //4: Found an e/E exponent sign, looking for more digits + case 4: + switch (c) { + case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": + str += c; + state = 5; + break; + default: + show_error("Unexpected character at position " + string(i) + ", expecting a digit.", true); + break; + } + break; + //5: Looking for final digits of the exponent + case 5: + if (_jso_is_whitespace_char(c)) || (string_pos(c, ":,]}") > 0) { + done = true; + i -= 1; + } else { + switch (c) { + case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": + str += c; + state = 5; + break; + default: + show_error("Unexpected character at position " + string(i) + ", expecting a digit.", true); + break; + } + } + break; + } + } + + //Am I still expecting more characters? + if (done) || (state == 1) || (state == -2) || (state == 5) { + return __jso_gmt_tuple(real(str), i); + } + //Error: unexpected ending + else { + show_error("Unexpected end of real in JSON string.", true); + } +} + +#define _jso_decode_integer +{ + /** + _jso_decode_real(json, startindex): Extract a real value from JSON string starting at position . + Return a 2-tuple of the extracted integer value (with leading i) and the position after the real value. + JSOnion version: 1.0.0d + */ + var i, len, str; + i = argument1; + len = string_length(argument0); + str = ""; + + //Seek to first character: +, -, or 0-9 + var c; + c = string_char_at(argument0, i); + if (string_pos(c, "0123456789+-") == 0) { + do { + i += 1; + c = string_char_at(argument0, i); + if (!_jso_is_whitespace_char(c)) && (string_pos(c, "0123456789+-") == 0) { + show_error("Cannot parse integer value at position " + string(i), true); + } + } until (string_pos(c, "0123456789+-") > 0) + } + + //Determine starting state + var state; + switch (c) { + case "+": case "-": + state = 0; + break; + default: + state = 1; + break; + } + str += c; + i += 1; + + //Loop until no more digits found + var done; + done = false; + for (i=i; i<=len && !done; i+=1) { + c = string_char_at(argument0, i); + switch (state) { + //0: Found a sign, looking for a starting number + case 0: + switch (c) { + case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": + str += c; + state = 1; + break; + default: + show_error("Unexpected character at position " + string(i) + ", expecting a digit.", true); + break; + } + break; + //1: Found a starting digit, looking for decimal dot, e, E, or more digits + case 1: + if (_jso_is_whitespace_char(c)) || (string_pos(c, ":,]}") > 0) { + done = true; + i -= 1; + } else { + switch (c) { + case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": + str += c; + break; + default: + show_error("Unexpected character at position " + string(i) + ", expecting a digit.", true); + break; + } + } + break; + } + } + + //Am I still expecting more characters? + if (done) || (state == 1) { + return __jso_gmt_tuple(floor(real(str)), i); + } + //Error: unexpected ending + else { + show_error("Unexpected end of integer in JSON string.", true); + } +} + +#define jso_compare_maps +{ + /** + jso_compare_maps(map1, map2): Return whether the contents of JSOnion-compatible maps and are the same. + JSOnion version: 1.0.0d + */ + + //If they aren't the same size, they can't be the same + var size; + size = ds_map_size(argument0); + if (size != ds_map_size(argument1)) { + return false; + } + + //Compare contents pairwise + var i, k, type, a, b; + k = ds_map_find_first(argument0); + for (i=0; i and are the same. + JSOnion version: 1.0.0d + */ + + //If they aren't the same size, they can't be the same + var size; + size = ds_list_size(argument0); + if (size != ds_list_size(argument1)) { + return false; + } + + //Compare contents pairwise + var i, type, a, b; + for (i=0; i, return whether a value exists there. + JSOnion version: 1.0.0d + */ + + //Catch empty calls + if (argument_count < 2) { + show_error("Expected at least 2 arguments, got " + string(argument_count) + ".", true); + } + + //Build list of keys/indices + var i, key_list; + key_list = ds_list_create(); + for (i=1; i, return whether a value exists there. + JSOnion version: 1.0.0d + */ + + //Catch empty calls + if (argument_count < 2) { + show_error("Expected at least 2 arguments, got " + string(argument_count) + ".", true); + } + + //Build list of keys/indices + var i, key_list; + key_list = ds_list_create(); + for (i=1; i, return the value that exists there. + JSOnion version: 1.0.0d + */ + + //Catch empty calls + if (argument_count < 2) { + show_error("Expected at least 2 arguments, got " + string(argument_count) + ".", true); + } + + //Build list of keys/indices + var i, key_list; + key_list = ds_list_create(); + for (i=1; i, return the type of value that exists there. + JSOnion version: 1.0.0d + */ + + //Catch empty calls + if (argument_count < 2) { + show_error("Expected at least 2 arguments, got " + string(argument_count) + ".", true); + } + + //Build list of keys/indices + var i, key_list; + key_list = ds_list_create(); + for (i=1; i, return the value that exists there. + JSOnion version: 1.0.0d + */ + + //Catch empty calls + if (argument_count < 2) { + show_error("Expected at least 2 arguments, got " + string(argument_count) + ".", true); + } + + //Build list of keys/indices + var i, key_list; + key_list = ds_list_create(); + for (i=1; i, return the type of value that exists there. + JSOnion version: 1.0.0d + */ + + //Catch empty calls + if (argument_count < 2) { + show_error("Expected at least 2 arguments, got " + string(argument_count) + ".", true); + } + + //Build list of keys/indices + var i, key_list; + key_list = ds_list_create(); + for (i=1; i= ds_list_size(data)) { + switch (task_type) { + case 0: + return false; + break; + default: + show_error("Index overflow for nested lists in " + type_string + " lookup.", true); + break; + } + } + type = jso_list_get_type(data, k); + data = jso_list_get(data, k); + break; + //Trying to go through a leaf; don't attempt to look further + default: + switch (task_type) { + case 0: + return false; + break; + default: + show_error("Recursive overflow in " + type_string + " lookup.", true); + break; + } + break; + } + } + + //Can find something, return the value requested by the task + switch (task_type) { + case 0: + return true; + break; + case 1: + return data; + break; + case 2: + return type; + break; + } +} + +#define _jso_is_whitespace_char +{ + /** + _jso_is_whitespace_char(char): Return whether is a whitespace character. + Definition of whitespace is given by Unicode 6.0, Chapter 4.6. + JSOnion version: 1.0.0d + */ + switch (ord(argument0)) { + case $0009: + case $000A: + case $000B: + case $000C: + case $000D: + case $0020: + case $0085: + case $00A0: + case $1680: + case $180E: + case $2000: + case $2001: + case $2002: + case $2003: + case $2004: + case $2005: + case $2006: + case $2007: + case $2008: + case $2009: + case $200A: + case $2028: + case $2029: + case $202F: + case $205F: + case $3000: + return true; + } + return false; +} + +#define _jso_hex_to_decimal +{ + /** + _jso_hex_to_decimal(hex_string): Return the decimal value of the hex number represented by + JSOnion version: 1.0.0d + */ + var hex_string, hex_digits; + hex_string = string_lower(argument0); + hex_digits = "0123456789abcdef"; + + //Convert digit-by-digit + var i, len, digit_value, num; + len = string_length(hex_string); + num = 0; + for (i=1; i<=len; i+=1) { + digit_value = string_pos(string_char_at(hex_string, i), hex_digits)-1; + if (digit_value >= 0) { + num *= 16; + num += digit_value; + } + //Unknown character + else { + show_error("Invalid hex number: " + argument0, true); + } + } + return num; +} + diff --git a/samples/Game Maker Language/jsonion_test.gml b/samples/Game Maker Language/jsonion_test.gml new file mode 100644 index 00000000..3cf0d423 --- /dev/null +++ b/samples/Game Maker Language/jsonion_test.gml @@ -0,0 +1,1169 @@ +// Originally from /jsonion_test.gml in JSOnion +// JSOnion v1.0.0d is licensed under the MIT licence. You may freely adapt and use this library in commercial and non-commercial projects. + +#define assert_true +{ + /** + assert_true(result, errormsg): Display error unless is true. + */ + + if (!argument0) { + _assert_error_popup(argument1 + string_repeat(_assert_newline(), 2) + "Expected true, got false."); + } +} + +#define assert_false +{ + /** + assert_false(result, errormsg): Display error unless is false. + */ + + if (argument0) { + _assert_error_popup(argument1 + string_repeat(_assert_newline(), 2) + "Expected false, got true."); + } +} + +#define assert_equal +{ + /** + assert_equal(expected, result, errormsg): Display error unless and are equal. + */ + + //Safe equality check; won't crash even if the two are different types + var match; + match = is_string(argument0) == is_string(argument1); + if (match) { + match = argument0 == argument1; + } + + //No match? + if (!match) { + //Data types + var type; + type[0] = "(Real)"; + type[1] = "(String)"; + + //Construct message + var msg; + msg = argument2; + //Add expected value + msg += string_repeat(_assert_newline(), 2); + msg += "Expected " + type[is_string(argument0)] + ":" + _assert_newline(); + msg += _assert_debug_value(argument0); + //Add actual value + msg += string_repeat(_assert_newline(), 2); + msg += "Actual " + type[is_string(argument1)] + ":" + _assert_newline(); + msg += _assert_debug_value(argument1); + + //Display message + _assert_error_popup(msg); + } +} + +#define _assert_error_popup +{ + /** + _assert_error_popup(msg): Display an assertion error. + */ + + //Display message + if (os_browser == browser_not_a_browser) { + show_error(argument0, false); //Full-fledged error message for non-browser environments + } else { + show_message(argument0); //Browsers don't support show_error(), use show_message() instead + } +} + +#define _assert_debug_value +{ + /** + _assert_debug_value(val): Returns a low-level debug value for the value . + can be a string or a real value. + */ + + //String + if (is_string(argument0)) { + if (os_browser == browser_not_a_browser) { + return argument0; + } else { + return string_replace_all(argument0, "#", "\#"); + } + } + + //Numeric --- use GMTuple's algorithm + else { + + //Integers + if (frac(argument0) == 0) { + return string(argument0); + } + + //Decimal numbers; get exponent and mantissa + var mantissa, exponent; + exponent = floor(log10(abs(argument0))); + mantissa = string_format(argument0/power(10,exponent), 15, 14); + //Look for trailing zeros in the mantissa + var i, ca; + i = string_length(mantissa); + do { + ca = string_char_at(mantissa, i); + i -= 1; + } until (ca != "0") + //Remove the dot if only the first digit of the normalized mantissa is nonzero + if (ca != ".") { + mantissa = string_copy(mantissa, 1, i+1); + } + else { + mantissa = string_copy(mantissa, 1, i); + } + //Remove the exponent if it is 0 + if (exponent != 0) { + return mantissa + "e" + string(exponent); + } else { + return mantissa; + } + + //GMTuple algorithm done + } +} + +#define _assert_newline +{ + /** + _assert_newline(): Returns a system-appropriate newline character sequence. + */ + + if (os_browser == browser_not_a_browser) { + return chr(13) + chr(10); + } else { + return "#"; + } +} + +#define jso_test_all +{ + /** + jso_test_all(): Run the test suite for the JSOnion library. + JSOnion version: 1.0.0d + */ + var a, b; + a = current_time; + _test_jso_new(); + _test_jso_map_add(); + _test_jso_list_add(); + _test_jso_encode(); + _test_jso_compare(); + _test_jso_decode(); + _test_jso_lookup(); + _test_jso_bugs(); + __jso_gmt_test_all(); + b = current_time; + show_debug_message("JSOnion: Tests completed in " + string(b-a) + "ms."); +} + +#define _test_jso_new +{ + /** + _test_jso_new(): Test jso_new_*() functions. + JSOnion version: 1.0.0d + */ + + var expected, actual; + + //jso_new_map() + actual = jso_new_map(); + assert_true(actual >= 0, "jso_new_map() failed to create a new map."); + ds_map_destroy(actual); + + //jso_new_list() + actual = jso_new_list(); + assert_true(actual >= 0, "jso_new_list() failed to create a new list."); + ds_list_destroy(actual); +} + +#define _test_jso_map_add +{ + /** + _test_jso_map_add(): Test jso_map_add_*() functions. + JSOnion version: 1.0.0d + */ + + var expected, actual, key, map; + map = jso_new_map(); + + //jso_map_add_real() + expected = pi; + key = "pi"; + jso_map_add_real(map, key, expected); + actual = jso_map_get(map, key); + assert_true(ds_map_exists(map, key), "jso_map_add_real() failed to add the number."); + assert_equal(expected, actual, "jso_map_add_real() added the wrong number."); + ds_map_delete(map, key); + + //jso_map_add_string() + expected = "waahoo"; + key = "str"; + jso_map_add_string(map, key, expected); + actual = jso_map_get(map, key); + assert_true(ds_map_exists(map, key), "jso_map_add_string() failed to add the string."); + assert_equal(expected, actual, "jso_map_add_string() added the wrong string."); + ds_map_delete(map, key); + + //jso_map_add_sublist() + expected = jso_new_list(); + key = "sublist"; + jso_map_add_sublist(map, key, expected); + actual = jso_map_get(map, key); + assert_true(ds_map_exists(map, key), "jso_map_add_sublist() failed to add the new sublist."); + assert_equal(expected, actual, "jso_map_add_sublist() added the wrong sublist."); + ds_map_delete(map, key); + ds_list_destroy(expected); + + //jso_map_add_submap() + expected = jso_new_map(); + key = "sublist"; + jso_map_add_sublist(map, key, expected); + actual = jso_map_get(map, key); + assert_true(ds_map_exists(map, key), "jso_map_add_submap() failed to add the new submap."); + assert_equal(expected, actual, "jso_map_add_submap() added the wrong submap."); + ds_map_delete(map, key); + ds_map_destroy(expected); + + //jso_map_add_integer() + expected = 2345; + key = "integer"; + jso_map_add_integer(map, key, expected); + actual = jso_map_get(map, key); + assert_true(ds_map_exists(map, key), "jso_map_add_integer() failed to add the new integer."); + assert_equal(expected, actual, "jso_map_add_integer() added the wrong integer."); + ds_map_delete(map, key); + + //jso_map_add_boolean() --- true + expected = true; + key = "booleantrue"; + jso_map_add_boolean(map, key, expected); + actual = jso_map_get(map, key); + assert_true(ds_map_exists(map, key), "jso_map_add_boolean() failed to add true."); + assert_true(actual, "jso_map_add_boolean() added the wrong true."); + ds_map_delete(map, key); + + //jso_map_add_boolean() --- false + expected = false; + key = "booleanfalse"; + jso_map_add_boolean(map, key, expected); + actual = jso_map_get(map, key) + assert_true(ds_map_exists(map, key), "jso_map_add_boolean() failed to add false."); + assert_false(actual, "jso_map_add_boolean() added the wrong false."); + ds_map_delete(map, key); + + //Cleanup + ds_map_destroy(map); +} + +#define _test_jso_list_add +{ + /** + _test_jso_list_add(): Test jso_list_add_*() functions. + JSOnion version: 1.0.0d + */ + + var expected, actual, list; + list = jso_new_list(); + + //jso_list_add_real() + expected = pi; + jso_list_add_real(list, expected); + actual = jso_list_get(list, 0); + assert_false(ds_list_empty(list), "jso_list_add_real() failed to add the number."); + assert_equal(expected, actual, "jso_list_add_real() added the wrong number."); + ds_list_clear(list); + + //jso_list_add_string() + expected = "waahoo"; + jso_list_add_string(list, expected); + actual = jso_list_get(list, 0); + assert_false(ds_list_empty(list), "jso_list_add_string() failed to add the string."); + assert_equal(expected, actual, "jso_list_add_string() added the wrong string."); + ds_list_clear(list); + + //jso_list_add_sublist() + expected = jso_new_list(); + jso_list_add_sublist(list, expected); + actual = jso_list_get(list, 0); + assert_false(ds_list_empty(list), "jso_list_add_sublist() failed to add the sublist."); + assert_equal(expected, actual, "jso_list_add_sublist() added the wrong sublist."); + ds_list_clear(list); + ds_list_destroy(expected); + + //jso_list_add_submap() + expected = jso_new_map(); + jso_list_add_submap(list, expected); + actual = jso_list_get(list, 0); + assert_false(ds_list_empty(list), "jso_list_add_submap() failed to add the submap."); + assert_equal(expected, actual, "jso_list_add_submap() added the wrong submap."); + ds_list_clear(list); + ds_map_destroy(expected); + + //jso_list_add_integer() + expected = 2345; + jso_list_add_integer(list, expected); + actual = jso_list_get(list, 0); + assert_false(ds_list_empty(list), "jso_list_add_integer() failed to add integer."); + assert_equal(expected, actual, "jso_list_add_integer() added the wrong integer."); + ds_list_clear(list); + + //jso_list_add_boolean() --- true + expected = true; + jso_list_add_boolean(list, expected); + actual = jso_list_get(list, 0); + assert_false(ds_list_empty(list), "jso_list_add_boolean() failed to add boolean true."); + assert_true(actual, "jso_list_add_boolean() added the wrong boolean true."); + ds_list_clear(list); + + //jso_list_add_boolean() --- false + expected = false; + jso_list_add_boolean(list, expected); + actual = jso_list_get(list, 0); + assert_false(ds_list_empty(list), "jso_list_add_boolean() failed to add boolean false."); + assert_false(actual, "jso_list_add_boolean() added the wrong boolean false."); + ds_list_clear(list); + + //Cleanup + ds_list_destroy(list); +} + +#define _test_jso_encode +{ + /** + _test_jso_encode(): Tests jso_encode_*() functions. + JSOnion version: 1.0.0d + */ + + var original, expected, actual; + + //jso_encode_real() --- Positive + expected = 3.1415; + actual = jso_encode_real(3.1415); + assert_equal(expected, real(actual), "jso_encode_real() failed to encode positive real!"); + + //jso_encode_real() --- Negative + expected = -2.71828; + actual = jso_encode_real(-2.71828); + assert_equal(expected, real(actual), "jso_encode_real() failed to encode negative real!"); + + //jso_encode_real() --- Zero + expected = 0; + actual = jso_encode_integer(0); + assert_equal(expected, real(actual), "jso_encode_real() failed to encode zero!"); + + //jso_encode_integer() --- Positive + expected = "2345"; + actual = jso_encode_integer(2345); + assert_equal(expected, actual, "jso_encode_integer() failed to encode positive integer!"); + + //jso_encode_integer() --- Negative + expected = "-45"; + actual = jso_encode_integer(-45); + assert_equal(expected, actual, "jso_encode_integer() failed to encode negative integer!"); + + //jso_encode_integer() --- Zero + expected = "0"; + actual = jso_encode_integer(0); + assert_equal(expected, actual, "jso_encode_integer() failed to encode zero!"); + + //jso_encode_boolean() --- true + expected = "true"; + actual = jso_encode_boolean(true); + assert_equal(expected, actual, "jso_encode_boolean() failed to encode true!"); + + //jso_encode_boolean() --- false + expected = "false"; + actual = jso_encode_boolean(false); + assert_equal(expected, actual, "jso_encode_boolean() failed to encode false!"); + + //jso_encode_string() --- Simple string + expected = '"waahoo"'; + actual = jso_encode_string("waahoo"); + assert_equal(expected, actual, "jso_encode_string() failed to encode simple string!"); + + //jso_encode_string() --- Empty string + expected = '""'; + actual = jso_encode_string(""); + assert_equal(expected, actual, "jso_encode_string() failed to encode empty string!"); + + //jso_encode_string() --- Basic escape characters + expected = '"\\\"\b\f\n\r\t"'; + actual = jso_encode_string('\"' + chr(8) + chr(12) + chr(10) + chr(13) + chr(9)); + assert_equal(expected, actual, "jso_encode_string() failed to encode escape character string!"); + + //jso_encode_map() --- Empty map + var empty_map; + empty_map = jso_new_map(); + expected = "{}"; + actual = jso_encode_map(empty_map); + assert_equal(expected, actual, "jso_encode_map() failed to encode empty map!"); + jso_cleanup_map(empty_map); + + //jso_encode_map() --- One-element map + var one_map; + one_map = jso_new_map(); + jso_map_add_string(one_map, "key", "value"); + expected = '{"key":"value"}'; + actual = jso_encode_map(one_map); + assert_equal(expected, actual, "jso_encode_map() failed to encode one-element map!"); + jso_cleanup_map(one_map); + + //jso_encode_map() --- Multi-element map + var multi_map, ok1, ok2; + multi_map = jso_new_map(); + jso_map_add_string(multi_map, "key1", "value\1"); + jso_map_add_integer(multi_map, "key2", 2); + ok1 = '{"key1":"value\\1","key2":2}'; + ok2 = '{"key2":2,"key1":"value\\1"}'; + actual = jso_encode_map(multi_map); + assert_true((actual == ok1) || (actual == ok2), "jso_encode_map() failed to encode multi-element map!"); + jso_cleanup_map(multi_map); + + //jso_encode_list() --- Empty list + var empty_list; + empty_list = jso_new_list(); + expected = "[]"; + actual = jso_encode_list(empty_list); + assert_equal(expected, actual, "jso_encode_list() failed to encode empty list!"); + jso_cleanup_list(empty_list); + + //jso_encode_list() --- One-element nested list + var one_list; + one_list = jso_new_list(); + jso_list_add_submap(one_list, jso_new_map()); + expected = "[{}]"; + actual = jso_encode_list(one_list); + assert_equal(expected, actual, "jso_encode_list() failed to encode one-element nested list!"); + jso_cleanup_list(one_list); + + //jso_encode_list() --- Multi-element nested list + var multi_list, submap, sublist; + multi_list = jso_new_list(); + submap = jso_new_map(); + jso_map_add_string(submap, "1", "one"); + jso_list_add_submap(multi_list, submap); + jso_list_add_integer(multi_list, 2); + sublist = jso_new_list(); + jso_list_add_string(sublist, "three"); + jso_list_add_boolean(sublist, true); + jso_list_add_sublist(multi_list, sublist); + expected = '[{"1":"one"},2,["three",true]]'; + actual = jso_encode_list(multi_list); + assert_equal(expected, actual, "jso_encode_list() failed to encode one-element nested list!"); + jso_cleanup_list(multi_list); +} + +#define _test_jso_decode +{ + /** + _test_jso_decode(): Test core _jso_decode_*() functions. + The formatting is intentionally erratic here to simulate actual formatting deviations. + JSOnion version: 1.0.0d + */ + var json, expected, actual, expected_structure, actual_structure; + + ////Primitives + + //_jso_decode_string(): Empty string + json = '""'; + expected = __jso_gmt_tuple("", 3); + actual = _jso_decode_string(json, 1); + assert_equal(expected, actual, "_jso_decode_string() failed to decode an empty string!"); + + //_jso_decode_string(): Small string + json = '"key" '; + expected = __jso_gmt_tuple("key", 6); + actual = _jso_decode_string(json, 1); + assert_equal(expected, actual, "_jso_decode_string() failed to decode a small string!"); + + //_jso_decode_string(): Simple string + json = ' "The quick brown fox jumps over the lazy dog." '; + expected = __jso_gmt_tuple("The quick brown fox jumps over the lazy dog.", 49); + actual = _jso_decode_string(json, 1); + assert_equal(expected, actual, "_jso_decode_string() failed to decode a simple string!"); + + //_jso_decode_string(): Escape characters + json = ' "\"\\\b\f\n\r\t\u003A"'; + expected = __jso_gmt_tuple('"\' + chr(8) + chr(12) + chr(10) + chr(13) + chr(9) + chr($003a), 24); + actual = _jso_decode_string(json, 1); + assert_equal(expected, actual, "_jso_decode_string() failed to decode a string with escape characters!"); + + //_jso_decode_string(): Mixed characters + json = ' "\"\\\bWaahoo\f\n\r\tnegg\u003a"'; + expected = __jso_gmt_tuple('"\' + chr(8) + "Waahoo" + chr(12) + chr(10) + chr(13) + chr(9) + "negg" + chr($003a), 34); + actual = _jso_decode_string(json, 1); + assert_equal(expected, actual, "_jso_decode_string() failed to decode a string with mixed characters!"); + + //_jso_decode_boolean(): True + json = 'true'; + expected = __jso_gmt_tuple(true, 5); + actual = _jso_decode_boolean(json, 1); + assert_equal(expected, actual, "_jso_decode_boolean() failed to decode true!"); + + //_jso_decode_boolean(): False + json = ' false '; + expected = __jso_gmt_tuple(false, 8); + actual = _jso_decode_boolean(json, 1); + assert_equal(expected, actual, "_jso_decode_boolean() failed to decode false!"); + + //_jso_decode_real(): Zero + json = '0'; + expected = __jso_gmt_tuple(0, 2); + actual = _jso_decode_real(json, 1); + assert_equal(expected, actual, "_jso_decode_real() failed to decode standard zero!"); + + //_jso_decode_real(): Signed zero + json = ' +0 '; + expected = __jso_gmt_tuple(0, 5); + actual = _jso_decode_real(json, 1); + assert_equal(expected, actual, "_jso_decode_real() failed to decode signed zero!"); + + //_jso_decode_real(): Signed zero with decimal digits + json = ' -0.000'; + expected = __jso_gmt_tuple(0, 8); + actual = _jso_decode_real(json, 1); + assert_equal(expected, actual, "_jso_decode_real() failed to decode signed zero with decimal digits!"); + + //_jso_decode_real(): Positive real + json = '3.14159'; + expected = __jso_gmt_tuple(3.14159, 8); + actual = _jso_decode_real(json, 1); + assert_equal(expected, actual, "_jso_decode_real() failed to decode positive real number!"); + + //_jso_decode_real(): Negative real + json = ' -2.71828'; + expected = __jso_gmt_tuple(-2.71828, 10); + actual = _jso_decode_real(json, 1); + assert_equal(expected, actual, "_jso_decode_real() failed to decode negative real number!"); + + //_jso_decode_real(): Positive real with positive exponent + json = ' 3.14159e2'; + expected = __jso_gmt_tuple(3.14159*100, 11); + actual = _jso_decode_real(json, 1); + assert_equal(expected, actual, "_jso_decode_real() failed to decode positive real number with positive exponent!"); + + //_jso_decode_real(): Negative real with positive exponent + json = ' -2.71828E2'; + expected = __jso_gmt_tuple(-2.71828*100, 12); + actual = _jso_decode_real(json, 1); + assert_equal(expected, actual, "_jso_decode_real() failed to decode negative real number with positive exponent!"); + + //_jso_decode_real(): Positive real with negative exponent + json = ' 314.159e-2'; + expected = __jso_gmt_tuple(3.14159, 12); + actual = _jso_decode_real(json, 1); + assert_equal(expected, actual, "_jso_decode_real() failed to decode positive real number with negative exponent!"); + + //_jso_decode_real(): Negative real with negative exponent + json = ' -271.828E-2'; + expected = __jso_gmt_tuple(-2.71828, 13); + actual = _jso_decode_real(json, 1); + assert_equal(expected, actual, "_jso_decode_real() failed to decode negative real number with negative exponent!"); + + //_jso_decode_real(): Positive integer + json = ' +1729'; + expected = __jso_gmt_tuple(1729, 7); + actual = _jso_decode_real(json, 1); + assert_equal(expected, actual, "_jso_decode_real() failed to decode positive integer!"); + + //_jso_decode_real(): Negative integer + json = '-583'; + expected = __jso_gmt_tuple(-583, 5); + actual = _jso_decode_real(json, 1); + assert_equal(expected, actual, "_jso_decode_real() failed to decode negative integer!"); + + //_jso_decode_integer(): Zero + json = ' 0 '; + expected = __jso_gmt_tuple(0, 3); + actual = _jso_decode_integer(json, 1); + assert_equal(expected, actual, "_jso_decode_integer() failed to decode zero!"); + + //_jso_decode_integer(): Positive integer + json = ' 1729 '; + expected = __jso_gmt_tuple(1729, 6); + actual = _jso_decode_integer(json, 1); + assert_equal(expected, actual, "_jso_decode_integer() failed to decode positive integer!"); + + //_jso_decode_integer(): Negative integer + json = ' -583'; + expected = __jso_gmt_tuple(-583, 8); + actual = _jso_decode_integer(json, 1); + assert_equal(expected, actual, "_jso_decode_integer() failed to decode negative integer!"); + + + ////Data structures + + //_jso_decode_map(): Empty map #1 + json = '{}'; + expected_structure = jso_new_map(); + expected = __jso_gmt_tuple(expected_structure, 3); + actual = _jso_decode_map(json, 1); + actual_structure = __jso_gmt_elem(actual, 0); + assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_map() didn't stop at the right place! (#1)"); + assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_map() didn't include the right prefix! (#1)"); + assert_true(jso_compare_maps(expected_structure, actual_structure), "_jso_decode_map() failed to decode an empty map! (#1)"); + jso_cleanup_map(expected_structure); + jso_cleanup_map(actual_structure); + + //_jso_decode_map(): Empty map #2 + json = ' { } '; + expected_structure = jso_new_map(); + expected = __jso_gmt_tuple(expected_structure, 7); + actual = _jso_decode_map(json, 1); + actual_structure = __jso_gmt_elem(actual, 0); + assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_map() didn't stop at the right place! (#2)"); + assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_map() didn't include the right prefix! (#2)"); + assert_true(jso_compare_maps(expected_structure, actual_structure), "_jso_decode_map() failed to decode an empty map! (#2)"); + jso_cleanup_map(expected_structure); + jso_cleanup_map(actual_structure); + + //_jso_decode_map(): One-entry map + json = ' {"key": "value"} '; + expected_structure = jso_new_map(); + expected = __jso_gmt_tuple(expected_structure, 18); + jso_map_add_string(expected_structure, "key", "value"); + actual = _jso_decode_map(json, 1); + actual_structure = __jso_gmt_elem(actual, 0); + assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_map() didn't stop at the right place! (one-entry map)"); + assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_map() didn't include the right prefix! (one-entry map)"); + assert_true(jso_compare_maps(expected_structure, actual_structure), "_jso_decode_map() failed to decode a one-entry map!"); + jso_cleanup_map(expected_structure); + jso_cleanup_map(actual_structure); + + //_jso_decode_map(): Multi-entry map + json = ' {"key" : "value", "pi":3.14, "bool" : true} '; + expected_structure = jso_new_map(); + expected = __jso_gmt_tuple(expected_structure, 48); + jso_map_add_string(expected_structure, "key", "value"); + jso_map_add_real(expected_structure, "pi", 3.14); + jso_map_add_boolean(expected_structure, "bool", true); + actual = _jso_decode_map(json, 1); + actual_structure = __jso_gmt_elem(actual, 0); + assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_map() didn't stop at the right place! (multi-entry map)"); + assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_map() didn't include the right prefix! (multi-entry map)"); + assert_true(jso_compare_maps(expected_structure, actual_structure), "_jso_decode_map() failed to decode a multi-entry map!"); + jso_cleanup_map(expected_structure); + jso_cleanup_map(actual_structure); + + //_jso_decode_map(): Nested maps + var submap; + json = '{ "waahoo" : { "woohah" : 3 } , "woohah" : 4 }'; + expected_structure = jso_new_map(); + expected = __jso_gmt_tuple(expected_structure, 47); + jso_map_add_integer(expected_structure, "woohah", 4); + submap = jso_new_map(); + jso_map_add_integer(submap, "woohah", 3); + jso_map_add_submap(expected_structure, "waahoo", submap); + actual = _jso_decode_map(json, 1); + actual_structure = __jso_gmt_elem(actual, 0); + assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_map() didn't stop at the right place! (nested map)"); + assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_map() didn't include the right prefix! (nested map)"); + assert_true(jso_compare_maps(expected_structure, actual_structure), "_jso_decode_map() failed to decode a nested map!"); + jso_cleanup_map(expected_structure); + jso_cleanup_map(actual_structure); + + //_jso_decode_map(): Map with nested lists + var sublist, subsublist; + json = '{ "waahoo" : [ "woohah", [true] ] , "woohah" : 4 }'; + expected_structure = jso_new_map(); + expected = __jso_gmt_tuple(expected_structure, 51); + jso_map_add_real(expected_structure, "woohah", 4); + sublist = jso_new_list(); + jso_list_add_string(sublist, "woohah"); + subsublist = jso_new_list(); + jso_list_add_boolean(subsublist, true); + jso_list_add_sublist(sublist, subsublist); + jso_map_add_sublist(expected_structure, "waahoo", sublist); + actual = _jso_decode_map(json, 1); + actual_structure = __jso_gmt_elem(actual, 0); + assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_map() didn't stop at the right place! (map with nested lists)"); + assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_map() didn't include the right prefix! (map with nested lists)"); + assert_true(jso_compare_maps(expected_structure, actual_structure), "_jso_decode_map() failed to decode a map with nested lists!"); + jso_cleanup_map(expected_structure); + jso_cleanup_map(actual_structure); + + //_jso_decode_map(): Mix-up nested map + var sublist; + json = ' { "waahoo" : [{}, "a", 1] }'; + expected_structure = jso_new_map(); + expected = __jso_gmt_tuple(expected_structure, 30); + sublist = jso_new_list(); + jso_list_add_submap(sublist, jso_new_map()); + jso_list_add_string(sublist, "a"); + jso_list_add_real(sublist, 1); + jso_map_add_sublist(expected_structure, "waahoo", sublist); + actual = _jso_decode_map(json, 1); + actual_structure = __jso_gmt_elem(actual, 0); + assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_map() didn't stop at the right place! (mix-up nested map)"); + assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_map() didn't include the right prefix! (mix-up nested map)"); + assert_true(jso_compare_maps(expected_structure, actual_structure), "_jso_decode_map() failed to decode a mix-up nested map!"); + jso_cleanup_map(expected_structure); + jso_cleanup_map(actual_structure); + + //_jso_decode_list(): Empty list #1 + json = '[]'; + expected_structure = jso_new_list(); + expected = __jso_gmt_tuple(expected_structure, 3); + actual = _jso_decode_list(json, 1); + actual_structure = __jso_gmt_elem(actual, 0); + assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_list() didn't stop at the right place! (#1)"); + assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_list() didn't include the right prefix! (#1)"); + assert_true(jso_compare_lists(expected_structure, actual_structure), "_jso_decode_list() failed to decode an empty list! (#1)"); + jso_cleanup_list(expected_structure); + jso_cleanup_list(actual_structure) + + //_jso_decode_list(): Empty list #2 + json = ' [ ] '; + expected_structure = jso_new_list(); + expected = __jso_gmt_tuple(expected_structure, 6); + actual = _jso_decode_list(json, 1); + actual_structure = __jso_gmt_elem(actual, 0); + assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_list() didn't stop at the right place! (#2)"); + assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_list() didn't include the right prefix! (#2)"); + assert_true(jso_compare_lists(expected_structure, actual_structure), "_jso_decode_list() failed to decode an empty list! (#2)"); + jso_cleanup_list(expected_structure); + jso_cleanup_list(actual_structure); + + //_jso_decode_list(): One-entry list + json = '[3]'; + expected_structure = jso_new_list(); + expected = __jso_gmt_tuple(expected_structure, 4); + jso_list_add_integer(expected_structure, 3); + actual = _jso_decode_list(json, 1); + actual_structure = __jso_gmt_elem(actual, 0); + assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_list() didn't stop at the right place! (one-entry list)"); + assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_list() didn't include the right prefix! (one-entry list)"); + assert_true(jso_compare_lists(expected_structure, actual_structure), "_jso_decode_list() failed to decode a one-entry list!"); + jso_cleanup_list(expected_structure); + jso_cleanup_list(actual_structure); + + //_jso_decode_list(): Multi-entry list + json = ' [4,"multi-entry",true]'; + expected_structure = jso_new_list(); + expected = __jso_gmt_tuple(expected_structure, 24); + jso_list_add_real(expected_structure, 4); + jso_list_add_string(expected_structure, "multi-entry"); + jso_list_add_boolean(expected_structure, true); + actual = _jso_decode_list(json, 1); + actual_structure = __jso_gmt_elem(actual, 0); + assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_list() didn't stop at the right place! (multi-entry list)"); + assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_list() didn't include the right prefix! (multi-entry list)"); + assert_true(jso_compare_lists(expected_structure, actual_structure), "_jso_decode_list() failed to decode a multi-entry list!"); + jso_cleanup_list(expected_structure); + jso_cleanup_list(actual_structure); + + //_jso_decode_list(): Nested list + var sublist; + json = ' [ [], 3, false, ["waahoo"]]'; + expected_structure = jso_new_list(); + expected = __jso_gmt_tuple(expected_structure, 29); + jso_list_add_sublist(expected_structure, jso_new_list()); + jso_list_add_integer(expected_structure, 3); + jso_list_add_boolean(expected_structure, false); + sublist = jso_new_list(); + jso_list_add_string(sublist, "waahoo"); + jso_list_add_sublist(expected_structure, sublist); + actual = _jso_decode_list(json, 1); + actual_structure = __jso_gmt_elem(actual, 0); + assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_list() didn't stop at the right place! (nested list)"); + assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_list() didn't include the right prefix! (nested list)"); + assert_true(jso_compare_lists(expected_structure, actual_structure), "_jso_decode_list() failed to decode a nested list!"); + jso_cleanup_list(expected_structure); + jso_cleanup_list(actual_structure); + + //_jso_decode_list(): List with nested maps + var submap; + json = ' [3, false, { "waahoo":"woo"}]'; + expected_structure = jso_new_list(); + expected = __jso_gmt_tuple(expected_structure, 31); + jso_list_add_integer(expected_structure, 3); + jso_list_add_boolean(expected_structure, false); + submap = jso_new_map(); + jso_map_add_string(submap, "waahoo", "woo"); + jso_list_add_submap(expected_structure, submap); + actual = _jso_decode_list(json, 1); + actual_structure = __jso_gmt_elem(actual, 0); + assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_list() didn't stop at the right place! (list with nested maps)"); + assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_list() didn't include the right prefix! (list with nested maps)"); + assert_true(jso_compare_lists(expected_structure, actual_structure), "_jso_decode_list() failed to decode a list with nested maps!"); + jso_cleanup_list(expected_structure); + jso_cleanup_list(actual_structure); + + //_jso_decode_list(): Mix-up nested list + var submap; + json = '[{}, {"a":[]}]'; + expected_structure = jso_new_list(); + expected = __jso_gmt_tuple(expected_structure, 15); + jso_list_add_submap(expected_structure, jso_new_map()); + submap = jso_new_map(); + jso_map_add_sublist(submap, "a", jso_new_list()); + jso_list_add_submap(expected_structure, submap); + actual = _jso_decode_list(json, 1); + actual_structure = __jso_gmt_elem(actual, 0); + assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_list() didn't stop at the right place! (mix-up nested list)"); + assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_list() didn't include the right prefix! (mix-up nested list)"); + assert_true(jso_compare_lists(expected_structure, actual_structure), "_jso_decode_list() failed to decode a mix-up nested list!"); + jso_cleanup_list(expected_structure); + jso_cleanup_list(actual_structure); +} + +#define _test_jso_compare +{ + /** + _test_jso_compare(): Test basic jso_compare_*() functions. + JSOnion version: 1.0.0d + */ + var a, b; + + //jso_compare_maps(): Empty maps should equal each other + a = jso_new_map(); + b = jso_new_map(); + assert_true(jso_compare_maps(a, b), "Empty maps should equal each other. (#1)"); + assert_true(jso_compare_maps(b, a), "Empty maps should equal each other. (#2)"); + jso_cleanup_map(a); + jso_cleanup_map(b); + + //jso_compare_maps(): An empty map should not equal a filled map + a = jso_new_map(); + b = jso_new_map(); + jso_map_add_string(b, "junk", "info"); + jso_map_add_integer(b, "taxi", 1729); + assert_false(jso_compare_maps(a, b), "An empty map should not equal a filled map. (#1)"); + assert_false(jso_compare_maps(b, a), "An empty map should not equal a filled map. (#2)"); + jso_cleanup_map(a); + jso_cleanup_map(b); + + //jso_compare_maps(): Maps with same content entered in different orders should equal each other + a = jso_new_map(); + b = jso_new_map(); + jso_map_add_real(a, "A", 1); + jso_map_add_real(a, "B", 2); + jso_map_add_real(a, "C", 3); + jso_map_add_real(b, "C", 3); + jso_map_add_real(b, "A", 1); + jso_map_add_real(b, "B", 2); + assert_true(jso_compare_maps(a, b), "Maps with same content entered in different orders should equal each other. (#1)"); + assert_true(jso_compare_maps(b, a), "Maps with same content entered in different orders should equal each other. (#2)"); + jso_cleanup_map(a); + jso_cleanup_map(b); + + //jso_compare_maps(): Maps with different keys should not equal each other + a = jso_new_map(); + b = jso_new_map(); + jso_map_add_real(a, "A", 1); + jso_map_add_real(a, "B", 2); + jso_map_add_real(a, "C", 3); + jso_map_add_real(b, "D", 3); + jso_map_add_real(b, "A", 1); + jso_map_add_real(b, "B", 2); + assert_false(jso_compare_maps(a, b), "Maps with different keys should not equal each other. (#1)"); + assert_false(jso_compare_maps(b, a), "Maps with different keys should not equal each other. (#2)"); + jso_cleanup_map(a); + jso_cleanup_map(b); + + //jso_compare_maps(): Maps with different values should not equal each other + a = jso_new_map(); + b = jso_new_map(); + jso_map_add_real(a, "A", 5); + jso_map_add_real(a, "B", 6); + jso_map_add_real(a, "C", 9); + jso_map_add_real(b, "A", 5); + jso_map_add_real(b, "B", 6); + jso_map_add_real(b, "C", 8); + assert_false(jso_compare_maps(a, b), "Maps with different values should not equal each other. (#1)"); + assert_false(jso_compare_maps(b, a), "Maps with different values should not equal each other. (#2)"); + jso_cleanup_map(a); + jso_cleanup_map(b); + + //jso_compare_maps(): Maps with corresponding values of different types should not equal each other, and should not crash. + a = jso_new_map(); + b = jso_new_map(); + jso_map_add_real(a, "A", 5); + jso_map_add_real(a, "B", 6); + jso_map_add_real(a, "C", 8); + jso_map_add_real(b, "A", 5); + jso_map_add_string(b, "B", "six"); + jso_map_add_real(b, "C", 8); + assert_false(jso_compare_maps(a, b), "Maps with corresponding values of different types should not equal each other, and should not crash. (#1)"); + assert_false(jso_compare_maps(b, a), "Maps with corresponding values of different types should not equal each other, and should not crash. (#2)"); + jso_cleanup_map(a); + jso_cleanup_map(b); + + //jso_compare_lists(): Empty lists should equal each other + a = jso_new_list(); + b = jso_new_list(); + assert_true(jso_compare_lists(a, b), "Empty lists should equal each other. (#1)"); + assert_true(jso_compare_lists(b, a), "Empty lists should equal each other. (#2)"); + jso_cleanup_list(a); + jso_cleanup_list(b); + + //jso_compare_lists(): An empty list should not equal a filled list + a = jso_new_list(); + b = jso_new_list(); + jso_list_add_string(b, "junk"); + jso_list_add_integer(b, 1729); + assert_false(jso_compare_lists(a, b), "An empty list should not equal a filled list. (#1)"); + assert_false(jso_compare_lists(b, a), "An empty list should not equal a filled list. (#2)"); + jso_cleanup_list(a); + jso_cleanup_list(b); + + //jso_compare_lists(): Lists with same content entered in different orders should not equal each other + a = jso_new_list(); + b = jso_new_list(); + jso_list_add_real(a, 1); + jso_list_add_real(a, 2); + jso_list_add_real(a, 3); + jso_list_add_real(b, 3); + jso_list_add_real(b, 1); + jso_list_add_real(b, 2); + assert_false(jso_compare_lists(a, b), "Lists with same content entered in different orders should not equal each other. (#1)"); + assert_false(jso_compare_lists(b, a), "Lists with same content entered in different orders should not equal each other. (#2)"); + jso_cleanup_list(a); + jso_cleanup_list(b); + + //jso_compare_lists(): Lists with corresponding entries of different types should not equal each other, should also not crash. + a = jso_new_list(); + b = jso_new_list(); + jso_list_add_real(a, 1); + jso_list_add_real(a, 2); + jso_list_add_real(a, 3); + jso_list_add_real(b, 1); + jso_list_add_string(b, "two"); + jso_list_add_real(b, 3); + assert_false(jso_compare_lists(a, b), "Lists with corresponding entries of different types should not equal each other, should also not crash. (#1)"); + assert_false(jso_compare_lists(b, a), "Lists with corresponding entries of different types should not equal each other, should also not crash. (#2)"); + jso_cleanup_list(a); + jso_cleanup_list(b); +} + +#define _test_jso_lookup +{ + /** + _test_jso_lookup(): Test core jso_*_lookup() and jso_*_check() functions for nested structures. + JSOnion version: 1.0.0d + */ + var json, structure, expected, actual; + + //jso_map_check(): Single argument --- exists + json = '{ "one" : 1, "two" : 2, "three" : 3 }'; + structure = jso_decode_map(json); + assert_true(jso_map_check(structure, "one"), "jso_map_check() failed to find existing entry! (single argument)"); + jso_cleanup_map(structure); + + //jso_map_lookup(): Single argument --- exists + json = '{ "one" : 1, "two" : 2, "three" : 3 }'; + structure = jso_decode_map(json); + expected = 1; + actual = jso_map_lookup(structure, "one") + assert_equal(expected, actual, "jso_map_lookup() found the wrong entry! (single argument)"); + jso_cleanup_map(structure); + + //jso_map_lookup_type(): Single argument --- exists + json = '{ "one" : -1, "two" : true, "three" : "trap" }'; + structure = jso_decode_map(json); + expected = jso_type_real; + actual = jso_map_lookup_type(structure, "one") + assert_equal(expected, actual, "jso_map_lookup_type() found the wrong type! (single argument)"); + jso_cleanup_map(structure); + + //jso_map_check(): Single argument --- doesn't exist + json = '{ "one" : 1, "two" : 2, "three" : 3 }'; + structure = jso_decode_map(json); + assert_false(jso_map_check(structure, "four"), "jso_map_check() found an inexistent entry! (single argument)"); + jso_cleanup_map(structure); + + //jso_map_check(): Single argument --- doesn't exist + json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : { "A":true, "B":false } }'; + structure = jso_decode_map(json); + assert_false(jso_map_check(structure, "A"), "jso_map_check() found an inexistent entry! (single argument, nested)"); + jso_cleanup_map(structure); + + //jso_map_check(): Multiple arguments (recurse) --- exists + json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : { "A":true, "B":false } }'; + structure = jso_decode_map(json); + assert_true(jso_map_check(structure, "four", "A"), "jso_map_check() failed to find existing entry! (multiple arguments)"); + jso_cleanup_map(structure); + + //jso_map_lookup(): Multiple arguments (recurse) --- exists + json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : { "A":true, "B":false } }'; + structure = jso_decode_map(json); + expected = true; + actual = jso_map_lookup(structure, "four", "A"); + assert_equal(expected, actual, "jso_map_lookup() found the wrong entry! (multiple arguments)"); + jso_cleanup_map(structure); + + //jso_map_lookup_type(): Multiple arguments (recurse) --- exists + json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : { "A":true, "B":"trap" } }'; + structure = jso_decode_map(json); + expected = jso_type_boolean; + actual = jso_map_lookup_type(structure, "four", "A"); + assert_equal(expected, actual, "jso_map_lookup_type() found the wrong type! (multiple arguments)"); + jso_cleanup_map(structure); + + //jso_map_check(): Multiple arguments (recurse) --- doesn't exist + json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : { "A":true, "B":false } }'; + structure = jso_decode_map(json); + assert_false(jso_map_check(structure, "four", "C"), "jso_map_check() found an inexistent entry! (multiple arguments, 1)"); + jso_cleanup_map(structure); + + //jso_map_check(): Multiple arguments (recurse) --- doesn't exist + json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : { "A":true, "B":false } }'; + structure = jso_decode_map(json); + assert_false(jso_map_check(structure, "three", ""), "jso_map_check() found an inexistent entry! (multiple arguments, 2)"); + jso_cleanup_map(structure); + + //jso_map_check(): Multiple arguments with nested list --- exists + json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : [ "A", true, ["B", false] ] }'; + structure = jso_decode_map(json); + assert_true(jso_map_check(structure, "four", 2, 1), "jso_map_check() failed to find an existing entry! (multiple arguments, nested)"); + jso_cleanup_map(structure); + + //jso_map_lookup(): Multiple arguments with nested list --- exists + json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : [ "A", true, ["B", false] ] }'; + structure = jso_decode_map(json); + expected = false; + actual = jso_map_lookup(structure, "four", 2, 1); + assert_equal(expected, actual, "jso_map_lookup() failed to find an existing entry! (multiple arguments, nested)"); + jso_cleanup_map(structure); + + //jso_map_lookup_type(): Multiple arguments with nested list --- exists + json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : [ "A", true, [false, "false"] ] }'; + structure = jso_decode_map(json); + expected = jso_type_string; + actual = jso_map_lookup_type(structure, "four", 2, 1); + assert_equal(expected, actual, "jso_map_lookup_type() found the wrong type! (multiple arguments, nested)"); + jso_cleanup_map(structure); + + //jso_map_check(): Multiple arguments with nested list --- wrong type + json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : [ "A", true, ["B", false] ] }'; + structure = jso_decode_map(json); + assert_false(jso_map_check(structure, "four", "A", 1), "jso_map_check() found an inexistent entry! (multiple arguments, nested, wrong type)"); + jso_cleanup_map(structure); + + //jso_map_check(): Multiple arguments with nested list --- index overflow + json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : [ "A", true, ["B", false] ] }'; + structure = jso_decode_map(json); + assert_false(jso_map_check(structure, "four", 2, 3), "jso_map_check() found an inexistent entry! (multiple arguments, nested, index overflow)"); + jso_cleanup_map(structure); + + //jso_list_check(): Single argument --- exists + json = '["one", 2, "three", true, 5]'; + structure = jso_decode_list(json); + assert_true(jso_list_check(structure, 2), "jso_list_check() failed to find an existing index! (single argument)"); + jso_cleanup_list(structure); + + //jso_list_lookup(): Single argument --- exists + json = '["one", 2, "three", true, 5]'; + structure = jso_decode_list(json); + expected = "three"; + actual = jso_list_lookup(structure, 2); + assert_equal(expected, actual, "jso_list_lookup() found the wrong index! (single argument)"); + jso_cleanup_list(structure); + + //jso_list_lookup_type(): Single argument --- exists + json = '["one", 2, "three", true, 5]'; + structure = jso_decode_list(json); + expected = jso_type_string; + actual = jso_list_lookup_type(structure, 2); + assert_equal(expected, actual, "jso_list_lookup_type() found the wrong type! (single argument)"); + jso_cleanup_list(structure); + + //jso_list_check(): Single argument --- doesn't exist + json = '["one", 2, "three", true, 5]'; + structure = jso_decode_list(json); + assert_false(jso_list_check(structure, 5), "jso_list_check() found an inexistent index! (single argument)"); + jso_cleanup_list(structure); + + //jso_list_check(): Multiple arguments (recurse) --- exists + json = '["one", 2, ["three", 3], true, 5]'; + structure = jso_decode_list(json); + assert_true(jso_list_check(structure, 2, 1), "jso_list_check() failed to find an existing index! (multiple arguments)"); + jso_cleanup_list(structure); + + //jso_list_lookup(): Multiple arguments (recurse) --- exists + json = '["one", 2, ["three", 3], true, 5]'; + structure = jso_decode_list(json); + expected = 3; + actual = jso_list_lookup(structure, 2, 1); + assert_equal(expected, actual, "jso_list_lookup() failed to find an existing index! (multiple arguments)"); + jso_cleanup_list(structure); + + //jso_list_lookup_type(): Multiple arguments (recurse) --- exists + json = '["one", 2, ["three", 3], true, 5]'; + structure = jso_decode_list(json); + expected = jso_type_real; + actual = jso_list_lookup_type(structure, 2, 1); + assert_equal(expected, actual, "jso_list_lookup_type() found the wrong type! (multiple arguments)"); + jso_cleanup_list(structure); + + //jso_list_check(): Multiple arguments (recurse) --- doesn't exist, inner index overflow + json = '["one", 2, ["three", 3], true, 5]'; + structure = jso_decode_list(json); + assert_false(jso_list_check(structure, 2, 2), "jso_list_check() found an inexistent index! (multiple arguments, inner index overflow)"); + jso_cleanup_list(structure); + + //jso_list_check(): Multiple arguments (recurse) --- doesn't exist, trying to index single entry + json = '["one", 2, ["three", 3], true, 5]'; + structure = jso_decode_list(json); + assert_false(jso_list_check(structure, 1, 0), "jso_list_check() found an inexistent index! (multiple arguments, indexing single entry)"); + jso_cleanup_list(structure); + + //jso_list_check(): Multiple arguments with nested map --- exists + json = '["one", 2, {"three":3}, true, 5]'; + structure = jso_decode_list(json); + assert_true(jso_list_check(structure, 2, "three"), "jso_list_check() failed to find an existing entry! (multiple arguments, nested map)"); + jso_cleanup_list(structure); + + //jso_list_lookup(): Multiple arguments with nested map --- exists + json = '["one", 2, {"three":3}, true, 5]'; + structure = jso_decode_list(json); + expected = 3; + actual = jso_list_lookup(structure, 2, "three"); + assert_equal(expected, actual, "jso_list_lookup() failed to find an existing entry! (multiple arguments, nested map)"); + jso_cleanup_list(structure); + + //jso_list_lookup_type(): Multiple arguments with nested map --- exists + json = '["one", 2, {"three":false}, true, 5]'; + structure = jso_decode_list(json); + expected = jso_type_boolean; + actual = jso_list_lookup_type(structure, 2, "three"); + assert_equal(expected, actual, "jso_list_lookup_type() found the wrong type! (multiple arguments, nested map)"); + jso_cleanup_list(structure); + + //jso_list_exists(): Multiple arguments with nested map --- doesn't exist, key on single entry + json = '["one", 2, {"three":3}, true, 5]'; + structure = jso_decode_list(json); + assert_false(jso_list_check(structure, 1, ""), "jso_list_check() found an inexistent entry! (multiple arguments, nested map, key on single entry)"); + jso_cleanup_list(structure); + + //jso_list_exists(): Multiple arguments with nested map --- doesn't exist, bad key + json = '["one", 2, {"three":3}, true, 5]'; + structure = jso_decode_list(json); + assert_false(jso_list_check(structure, 2, ""), "jso_list_check() found an inexistent entry! (multiple arguments, nested map, bad key)"); + jso_cleanup_list(structure); +} + +#define _test_jso_bugs +{ + /** + _test_jso_bugs(): Test reported bugs. + JSOnion version: 1.0.0d + */ + var expected, actual; + + //jso_encode_map() --- One-element map + //Bug 1: Crash when encoding boolean-valued entries in maps, unknown variable jso_type_integer + var one_map; + one_map = jso_new_map(); + jso_map_add_boolean(one_map, "true", true); + expected = '{"true":true}'; + actual = jso_encode_map(one_map); + assert_equal(expected, actual, "jso_encode_map() failed to encode one-element map with boolean entry!"); + jso_cleanup_map(one_map); +} + diff --git a/samples/Game Maker Language/scrInitLevel.gml b/samples/Game Maker Language/scrInitLevel.gml new file mode 100644 index 00000000..af0cf274 --- /dev/null +++ b/samples/Game Maker Language/scrInitLevel.gml @@ -0,0 +1,298 @@ +// Originally from /spelunky/Scripts/Level Generation/scrInitLevel.gml in the Spelunky Community Update Project + +// +// scrInitLevel() +// +// Calls scrLevelGen(), scrRoomGen*(), and scrEntityGen() to build level. +// + +/********************************************************************************** + Copyright (c) 2008, 2009 Derek Yu and Mossmouth, LLC + + This file is part of Spelunky. + + You can redistribute and/or modify Spelunky, including its source code, under + the terms of the Spelunky User License. + + Spelunky is distributed in the hope that it will be entertaining and useful, + but WITHOUT WARRANTY. Please see the Spelunky User License for more details. + + The Spelunky User License should be available in "Game Information", which + can be found in the Resource Explorer, or as an external file called COPYING. + If not, please obtain a new copy of Spelunky from + +***********************************************************************************/ + +global.levelType = 0; +//global.currLevel = 16; +if (global.currLevel > 4 and global.currLevel < 9) global.levelType = 1; +if (global.currLevel > 8 and global.currLevel < 13) global.levelType = 2; +if (global.currLevel > 12 and global.currLevel < 16) global.levelType = 3; +if (global.currLevel == 16) global.levelType = 4; + +if (global.currLevel <= 1 or + global.currLevel == 5 or + global.currLevel == 9 or + global.currLevel == 13) +{ + global.hadDarkLevel = false; +} + +// global.levelType = 3; // debug + +// DEBUG MODE // +/* +if (global.currLevel == 2) global.levelType = 4; +if (global.currLevel == 3) global.levelType = 2; +if (global.currLevel == 4) global.levelType = 3; +if (global.currLevel == 5) global.levelType = 4; +*/ + +// global.levelType = 0; + +global.startRoomX = 0; +global.startRoomY = 0; +global.endRoomX = 0; +global.endRoomY = 0; +oGame.levelGen = false; + +// this is used to determine the path to the exit (generally no bombs required) +for (i = 0; i < 4; i += 1) +{ + for (j = 0; j < 4; j += 1) + { + global.roomPath[i,j] = 0; + } +} + +// side walls +if (global.levelType == 4) + k = 54; +else if (global.levelType == 2) + k = 38; +else if (global.lake) + k = 41; +else + k = 33; +for (i = 0; i <= 42; i += 1) +{ + for (j = 0; j <= k; j += 1) + { + if (not isLevel()) + { + i = 999; + j = 999; + } + else if (global.levelType == 2) + { + if (i*16 == 0 or + i*16 == 656 or + j*16 == 0) + { + obj = instance_create(i*16, j*16, oDark); + obj.invincible = true; + obj.sprite_index = sDark; + } + } + else if (global.levelType == 4) + { + if (i*16 == 0 or + i*16 == 656 or + j*16 == 0) + { + obj = instance_create(i*16, j*16, oTemple); + obj.invincible = true; + if (not global.cityOfGold) obj.sprite_index = sTemple; + } + } + else if (global.lake) + { + if (i*16 == 0 or + i*16 == 656 or + j*16 == 0 or + j*16 >= 656) + { + obj = instance_create(i*16, j*16, oLush); obj.sprite_index = sLush; + obj.invincible = true; + } + } + else if (i*16 == 0 or + i*16 == 656 or + j*16 == 0 or + j*16 >= 528) + { + if (global.levelType == 0) { obj = instance_create(i*16, j*16, oBrick); obj.sprite_index = sBrick; } + else if (global.levelType == 1) { obj = instance_create(i*16, j*16, oLush); obj.sprite_index = sLush; } + else { obj = instance_create(i*16, j*16, oTemple); if (not global.cityOfGold) obj.sprite_index = sTemple; } + obj.invincible = true; + } + } +} + +if (global.levelType == 2) +{ + for (i = 0; i <= 42; i += 1) + { + instance_create(i*16, 40*16, oDark); + //instance_create(i*16, 35*16, oSpikes); + } +} + +if (global.levelType == 3) +{ + background_index = bgTemple; +} + +global.temp1 = global.gameStart; +scrLevelGen(); + +global.cemetary = false; +if (global.levelType == 1 and rand(1,global.probCemetary) == 1) global.cemetary = true; + +with oRoom +{ + if (global.levelType == 0) scrRoomGen(); + else if (global.levelType == 1) + { + if (global.blackMarket) scrRoomGenMarket(); + else scrRoomGen2(); + } + else if (global.levelType == 2) + { + if (global.yetiLair) scrRoomGenYeti(); + else scrRoomGen3(); + } + else if (global.levelType == 3) scrRoomGen4(); + else scrRoomGen5(); +} + +global.darkLevel = false; +//if (not global.hadDarkLevel and global.currLevel != 0 and global.levelType != 2 and global.currLevel != 16 and rand(1,1) == 1) +if (not global.hadDarkLevel and not global.noDarkLevel and global.currLevel != 0 and global.currLevel != 1 and global.levelType != 2 and global.currLevel != 16 and rand(1,global.probDarkLevel) == 1) +{ + global.darkLevel = true; + global.hadDarkLevel = true; + //instance_create(oPlayer1.x, oPlayer1.y, oFlare); +} + +if (global.blackMarket) global.darkLevel = false; + +global.genUdjatEye = false; +if (not global.madeUdjatEye) +{ + if (global.currLevel == 2 and rand(1,3) == 1) global.genUdjatEye = true; + else if (global.currLevel == 3 and rand(1,2) == 1) global.genUdjatEye = true; + else if (global.currLevel == 4) global.genUdjatEye = true; +} + +global.genMarketEntrance = false; +if (not global.madeMarketEntrance) +{ + if (global.currLevel == 5 and rand(1,3) == 1) global.genMarketEntrance = true; + else if (global.currLevel == 6 and rand(1,2) == 1) global.genMarketEntrance = true; + else if (global.currLevel == 7) global.genMarketEntrance = true; +} + +//////////////////////////// +// ENTITY / TREASURES +//////////////////////////// +global.temp2 = global.gameStart; +if (not isRoom("rTutorial") and not isRoom("rLoadLevel")) scrEntityGen(); + +if (instance_exists(oEntrance) and not global.customLevel) +{ + oPlayer1.x = oEntrance.x+8; + oPlayer1.y = oEntrance.y+8; +} + +if (global.darkLevel or + global.blackMarket or + global.snakePit or + global.cemetary or + global.lake or + global.yetiLair or + global.alienCraft or + global.sacrificePit or + global.cityOfGold) +{ + if (not isRoom("rLoadLevel")) + { + with oPlayer1 { alarm[0] = 10; } + } +} + +if (global.levelType == 4) scrSetupWalls(864); +else if (global.lake) scrSetupWalls(656); +else scrSetupWalls(528); + +// add background details +if (global.graphicsHigh) +{ + repeat(20) + { + // bg = instance_create(16*rand(1,42), 16*rand(1,33), oCaveBG); + if (global.levelType == 1 and rand(1,3) < 3) + tile_add(bgExtrasLush, 32*rand(0,1), 0, 32, 32, 16*rand(1,42), 16*rand(1,33), 10002); + else if (global.levelType == 2 and rand(1,3) < 3) + tile_add(bgExtrasIce, 32*rand(0,1), 0, 32, 32, 16*rand(1,42), 16*rand(1,33), 10002); + else if (global.levelType == 3 and rand(1,3) < 3) + tile_add(bgExtrasTemple, 32*rand(0,1), 0, 32, 32, 16*rand(1,42), 16*rand(1,33), 10002); + else + tile_add(bgExtras, 32*rand(0,1), 0, 32, 32, 16*rand(1,42), 16*rand(1,33), 10002); + } +} + +oGame.levelGen = true; + +// generate angry shopkeeper at exit if murderer or thief +if ((global.murderer or global.thiefLevel > 0) and isRealLevel()) +{ + with oExit + { + if (type == "Exit") + { + obj = instance_create(x, y, oShopkeeper); + obj.status = 4; + } + } + // global.thiefLevel -= 1; +} + +with oTreasure +{ + if (collision_point(x, y, oSolid, 0, 0)) + { + obj = instance_place(x, y, oSolid); + if (obj.invincible) instance_destroy(); + } +} + +with oWater +{ + if (sprite_index == sWaterTop or sprite_index == sLavaTop) + { + scrCheckWaterTop(); + } + /* + obj = instance_place(x-16, y, oWater); + if (instance_exists(obj)) + { + if (obj.sprite_index == sWaterTop or obj.sprite_index == sLavaTop) + { + if (type == "Lava") sprite_index = sLavaTop; + else sprite_index = sWaterTop; + } + } + obj = instance_place(x+16, y, oWater); + if (instance_exists(obj)) + { + if (obj.sprite_index == sWaterTop or obj.sprite_index == sLavaTop) + { + if (type == "Lava") sprite_index = sLavaTop; + else sprite_index = sWaterTop; + } + } + */ +} + +global.temp3 = global.gameStart;