on parse_gamestatus(me, tConn) {
	tGameSystem = me.getGameSystem()

	if (tGameSystem == 0) {
		return(0)
	}

	tTurnNum = tConn.GetIntFrom()
	tCheckSum = tConn.GetIntFrom()
	tNumSubturns = tConn.GetIntFrom()

	tTurn = tGameSystem.getNewTurnContainer()

	if (!objectp(tTurn)) {
		return(error(me, "Cannot create turn container!", #parse_gamestatus))
	}

	tTurn.SetNumber(tTurnNum)
	tTurn.SetChecksum(tCheckSum)

	tSubTurnIndex = []
	tSubTurnNum = 1

	while (tNumSubturns > tSubTurnNum) {
		tSubTurnIndex.setAt(tSubTurnNum, [])

		tNumEvents = tConn.GetIntFrom()
		tEventNum = 1

		while (tNumEvents > tEventNum) {
			tEvent = me.parse_event(tConn)
			if (tEvent == 0) {
				return(error(
					me,
					"SERVER ERROR: No event received when expected!",
					#parse_gamestatus
				))
			}

			tTurn.AddElement(tSubTurnNum, tEvent)

			tEventNum = tEventNum + 1
		}

		if (tNumEvents == 0) {
			tTurn.AddElement(tSubTurnNum, void())
		}

		tSubTurnNum = tSubTurnNum + 1
	}

	return(tGameSystem.sendGameSystemEvent(#gamestatus_turn, tTurn))
}

on parse_event(me, tConn) {
	tEventType = tConn.GetIntFrom()

	switch(tEventType) {
		case 0: {
			tEvent = me.parse_snowwar_gameobject(tConn)
			tEvent.addProp(#event_type, 0)
		}

		case 1: {
			tIntKeyList = [#int_id]
		}

		case 2: {
			tIntKeyList = [#int_id, #x, #y]
		}

		case 3: {
			tIntKeyList = [#int_id, #int_target_id, #throw_height]
		}

		case 4: {
			tIntKeyList = [#int_id, #TargetX, #TargetY, #throw_height]
		}

		case 5: {
			tIntKeyList = [#int_thrower_id, #int_id, #hit_direction]
		}

		case 6: {
			tIntKeyList = [#x, #y]
		}

		case 7: {
			tIntKeyList = [#int_id]
		}

		case 8: {
			tIntKeyList = [#int_id, #int_thrower_id, #TargetX, #TargetY, #trajectory]
		}

		case 9: {
			tIntKeyList = [#int_id, #int_thrower_id, #hit_direction]
		}

		case 10: {
			tIntKeyList = []
		}

		case 11: {
			tIntKeyList = [#int_machine_id]
		}

		case 12: {
			tIntKeyList = [#int_player_id, #int_machine_id]
		}

		default: {
			return(error(
				me,
				"Undefined event sent by server, parsing cannot continue!",
				#handle_gamestatus
			))
		}
	}

	if (listp(tIntKeyList)) {
		tEvent = [#event_type, tEventType]

		for (int i = 1; tIntKeyList.count > i; i++) {
			tKey = tIntKeyList.getAt(i)
			tEvent.addProp(tKey, tConn.GetIntFrom())
		}

		if (tEvent.findPos(#int_id) > 0) {
			tEvent.addProp(#id, string(tEvent.getAt(#int_id))
		}
	}

	return(tEvent)
}

on parse_snowwar_gameobject(me, tConn) {
	tdata = []
	tdata.addProp(#type, tConn.GetIntFrom())
	tID = tConn.GetIntFrom()
	tdata.addProp(#int_id, tID)
	tdata.addProp(#id, string(tID))

	switch (tdata.getAt(#type)) {
		case 0: {
			tObjectData = me.parse_snowwar_player_gameobjectvariables(tdata.duplicate(), tConn)
			tdata.addProp(#objectDataStruct, tObjectData)
			tdata.addProp(#str_type, "player")
		}

		case 1: {
			tObjectData = me.parse_snowwar_snowball_gameobjectvariables(tdata.duplicate(), tConn)
			tdata.addProp(#objectDataStruct, tObjectData)
			tdata.addProp(#str_type, "snowball")
		}

		case 2: {
			return(0)
		}

		case 3: {
			tObjectData = me.parse_snowwar_large_snowball_gameobjectvariables(tdata.duplicate(), tConn)
			tdata.addProp(#objectDataStruct, tObjectData)
			tdata.addProp(#str_type, "large_snowball")
		}

		case 4: {
			tObjectData = me.parse_snowwar_snowball_machine_gameobjectvariables(tdata.duplicate(), tConn)
			tdata.addProp(#objectDataStruct, tObjectData)
			tdata.addProp(#str_type, "snowball_machine")
		}

		case 5: {
			tObjectData = me.parse_snowwar_avatar_gameobjectvariables(tdata.duplicate(), tConn)
			tdata.addProp(#objectDataStruct, tObjectData)

			i = 1
			while (tObjectData.count > i) {
				tdata.addProp(tObjectData.getPropAt(i), tObjectData.getAt(i))
				i = i + 1
			}

			tdata.addProp(#human_id, tdata.getAt(#id))
			tdata.addProp(#dirBody, tdata.getAt(#body_direction))
			tdata.addProp(#name, tConn.GetStrFrom())
			tdata.addProp(#mission, tConn.GetStrFrom())
			tdata.addProp(#figure, tConn.GetStrFrom())
			tdata.addProp(#sex, tConn.GetStrFrom())
			tdata.addProp(#str_type, "avatar")
		}

		default: {
			error(me, "Unsupported game object type:" && tdata.getAt(#type), #parse_snowwar_object)
		}
	}

	tExtraProps = ["collisionshape_type", "height", "collisionshape_radius"]

	for (int i = 1; tExtraProps.count > i; i++) {
		tProp = tExtraProps.getAt(i)
		if variableExists("snowwar.object_" & tdata.getAt(#str_type)) {
			tdata.addProp(
				symbol("gameobject_" & tProp),
				getVariable("snowwar.object_" & tdata.getAt(#str_type) & "." & tProp)
			)
		}
	}

	return(tdata)
}

on parse_snowwar_snowball_gameobjectvariables(me, tdata, tConn) {
	tdata.addProp(#x, tConn.GetIntFrom())
	tdata.addProp(#y, tConn.GetIntFrom())
	tdata.addProp(#z, tConn.GetIntFrom())
	tdata.addProp(#movement_direction, tConn.GetIntFrom())
	tdata.addProp(#trajectory, tConn.GetIntFrom())
	tdata.addProp(#time_to_live, tConn.GetIntFrom())
	tdata.addProp(#int_thrower_id, tConn.GetIntFrom())
	tdata.addProp(#parabola_offset, tConn.GetIntFrom())

	return (tdata)
}

on parse_snowwar_player_gameobjectvariables(me, tdata, tConn) {
	tdata.addProp(#room_index, tConn.GetIntFrom())
	tdata.addProp(#human_id, tConn.GetIntFrom())

	return(tdata)
}

on parse_snowwar_avatar_gameobjectvariables(me, tdata, tConn) {
	tdata.addProp(#x, tConn.GetIntFrom())
	tdata.addProp(#y, tConn.GetIntFrom())
	tdata.addProp(#body_direction, tConn.GetIntFrom())
	tdata.addProp(#hit_points, tConn.GetIntFrom())
	tdata.addProp(#snowball_count, tConn.GetIntFrom())
	tdata.addProp(#is_bot, tConn.GetIntFrom())
	tdata.addProp(#activity_timer, tConn.GetIntFrom())
	tdata.addProp(#activity_state, tConn.GetIntFrom())
	tdata.addProp(#next_tile_x, tConn.GetIntFrom())
	tdata.addProp(#next_tile_y, tConn.GetIntFrom())
	tdata.addProp(#move_target_x, tConn.GetIntFrom())
	tdata.addProp(#move_target_y, tConn.GetIntFrom())
	tdata.addProp(#score, tConn.GetIntFrom())
	tdata.addProp(#player_id, tConn.GetIntFrom())
	tdata.addProp(#team_id, tConn.GetIntFrom())
	tdata.addProp(#room_index, tConn.GetIntFrom())

	return(tdata)
}

on parse_snowwar_large_snowball_gameobjectvariables(me, tdata, tConn) {
	tdata.addProp(#x, tConn.GetIntFrom())
	tdata.addProp(#y, tConn.GetIntFrom())

	return(tdata)
}

on parse_snowwar_snowball_machine_gameobjectvariables(me, tdata, tConn) {
	tdata.addProp(#x, tConn.GetIntFrom())
	tdata.addProp(#y, tConn.GetIntFrom())
	tdata.addProp(#snowball_count, tConn.GetIntFrom())

	return(tdata)
}