🐐 stuff
This commit is contained in:
192
Sly3Callbacks.py
192
Sly3Callbacks.py
@@ -1,9 +1,11 @@
|
||||
from typing import TYPE_CHECKING, Dict, List
|
||||
from time import time
|
||||
|
||||
from NetUtils import ClientStatus
|
||||
from BaseClasses import ItemClassification
|
||||
|
||||
from .data.Constants import REQUIREMENTS
|
||||
from .data import Items
|
||||
from .data.Constants import REQUIREMENTS, DEATH_TYPES, EPISODES, CHALLENGES
|
||||
from .data import Items, Locations
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .Sly3Client import Sly3Context
|
||||
@@ -114,18 +116,196 @@ def accessibility(ctx: "Sly3Context") -> Dict[str, Dict[str, List[List[bool]]]]:
|
||||
"Challenges": challenge_accessibility
|
||||
}
|
||||
|
||||
def set_thiefnet(ctx: "Sly3Context"):
|
||||
# TODO
|
||||
pass
|
||||
|
||||
def unset_thiefnet(ctx: "Sly3Context"):
|
||||
# TODO
|
||||
pass
|
||||
|
||||
def check_jobs(ctx: "Sly3Context"):
|
||||
# TODO
|
||||
pass
|
||||
|
||||
def check_challenges(ctx: "Sly3Context"):
|
||||
# TODO
|
||||
pass
|
||||
|
||||
def set_powerups(ctx: "Sly3Context"):
|
||||
if not ctx.in_safehouse():
|
||||
ctx.game_interface.set_powerups(ctx.powerups)
|
||||
|
||||
#########
|
||||
# Steps #
|
||||
#########
|
||||
|
||||
async def update_in_safehouse(ctx: "Sly3Context"):
|
||||
in_safehouse = ctx.game_interface.in_safehouse()
|
||||
if in_safehouse and not ctx.in_safehouse:
|
||||
ctx.in_safehouse = True
|
||||
set_thiefnet(ctx)
|
||||
elif ctx.in_safehouse and not in_safehouse:
|
||||
ctx.in_safehouse = False
|
||||
unset_thiefnet(ctx)
|
||||
|
||||
async def replace_text(ctx: "Sly3Context"):
|
||||
# TODO
|
||||
# I'm not totally sure yet which text I'm replacing
|
||||
pass
|
||||
|
||||
async def kick_from_episode(ctx: "Sly3Context", availability: Dict):
|
||||
# TODO
|
||||
not_connected = ctx.current_map == 0 and not ctx.is_connected_to_server
|
||||
current_episode = ctx.game_interface.get_current_episode()
|
||||
ep_not_unlocked = current_episode == 0 or ctx.available_episodes[current_episode-1]
|
||||
job_not_available = False # if current job/challenge not available
|
||||
|
||||
if not_connected or ep_not_unlocked or job_not_available:
|
||||
ctx.game_interface.to_episode_menu()
|
||||
|
||||
async def check_jobs_and_challenges(ctx: "Sly3Context"):
|
||||
check_jobs()
|
||||
check_challenges()
|
||||
|
||||
async def send_checks(ctx: "Sly3Context"):
|
||||
if ctx.slot_data is None:
|
||||
return
|
||||
|
||||
# ThiefNet purchases
|
||||
if ctx.in_safehouse:
|
||||
ctx.thiefnet_purchases = ctx.game_interface.read_powerups()
|
||||
purchases = list(ctx.thiefnet_purchases)
|
||||
purchases = (
|
||||
purchases[4:32] +
|
||||
purchases[33:40] +
|
||||
purchases[42:43] +
|
||||
purchases[45:46]
|
||||
)
|
||||
|
||||
thiefnet_n = ctx.slot_data["thiefnet_locations"]
|
||||
purchases = purchases[:thiefnet_n]
|
||||
for i, purchased in enumerate(purchases):
|
||||
if purchased:
|
||||
location_name = f"ThiefNet {i+1:02}"
|
||||
location_code = Locations.location_dict[location_name].code
|
||||
ctx.locations_checked.add(location_code)
|
||||
|
||||
# Jobs
|
||||
for i, episode in enumerate(ctx.jobs_completed):
|
||||
episode_name = list(EPISODES.keys())[i]
|
||||
for j, chapter in enumerate(episode):
|
||||
for k, job in enumerate(chapter):
|
||||
if job:
|
||||
job_name = EPISODES[episode_name][j][k]
|
||||
location_name = f"{episode_name} - {job_name}"
|
||||
location_code = Locations.location_dict[location_name].code
|
||||
ctx.locations_checked.add(location_code)
|
||||
|
||||
# Challenges
|
||||
for i, episode in enumerate(ctx.challenges_completed):
|
||||
episode_name = list(CHALLENGES.keys())[i]
|
||||
for j, chapter in enumerate(episode):
|
||||
for k, job in enumerate(chapter):
|
||||
if job:
|
||||
job_name = CHALLENGES[episode_name][j][k]
|
||||
location_name = f"{episode_name} - {job_name}"
|
||||
location_code = Locations.location_dict[location_name].code
|
||||
ctx.locations_checked.add(location_code)
|
||||
|
||||
await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": ctx.locations_checked}])
|
||||
|
||||
async def receive_items(ctx: "Sly3Context"):
|
||||
# TODO
|
||||
pass
|
||||
|
||||
async def check_goal(ctx: "Sly3Context"):
|
||||
if ctx.slot_data is None:
|
||||
return
|
||||
|
||||
goal = ctx.slot_data["goal"]
|
||||
goaled = ctx.game_interface.is_goaled(goal)
|
||||
|
||||
if goaled:
|
||||
await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}])
|
||||
|
||||
async def handle_job_markers(ctx: "Sly3Context", availability: Dict):
|
||||
# TODO
|
||||
pass
|
||||
|
||||
async def handle_notifications(ctx: "Sly3Context"):
|
||||
if (
|
||||
(ctx.showing_notification and time() - ctx.notification_timestamp < 10) or
|
||||
(
|
||||
(not ctx.showing_notification) and
|
||||
ctx.game_interface.showing_infobox() and
|
||||
ctx.game_interface.current_infobox() != 0xffffffff
|
||||
) or
|
||||
ctx.game_interface.in_cutscene()
|
||||
):
|
||||
return
|
||||
|
||||
ctx.game_interface.disable_infobox()
|
||||
ctx.showing_notification = False
|
||||
if len(ctx.notification_queue) > 0 and ctx.game_interface.in_hub():
|
||||
new_notification = ctx.notification_queue.pop(0)
|
||||
ctx.notification_timestamp = time()
|
||||
ctx.showing_notification = True
|
||||
ctx.game_interface.set_infobox(new_notification)
|
||||
|
||||
async def handle_deathlink(ctx: "Sly3Context"):
|
||||
if not ctx.death_link_enabled:
|
||||
return
|
||||
|
||||
if time()-ctx.deathlink_timestamp <= 20:
|
||||
return
|
||||
|
||||
if ctx.game_interface.alive():
|
||||
if ctx.queued_deaths > 0:
|
||||
ctx.game_interface.kill_player()
|
||||
ctx.queued_deaths = 0
|
||||
ctx.deathlink_timestamp = time()
|
||||
else:
|
||||
damage_type = ctx.game_interface.get_damage_type()
|
||||
player_name = ctx.player_names[ctx.slot if ctx.slot else 0]
|
||||
death_message = DEATH_TYPES.get(damage_type, "{player} died").format(player=player_name)
|
||||
|
||||
await ctx.send_death(death_message)
|
||||
ctx.deathlink_timestamp = time()
|
||||
|
||||
##################
|
||||
# Main Functions #
|
||||
##################
|
||||
|
||||
async def init(ctx: "Sly3Context", ap_connected: bool) -> None:
|
||||
async def init(ctx: "Sly3Context") -> None:
|
||||
"""Called when the player connects to the AP server or changes map"""
|
||||
pass
|
||||
if ctx.current_map is None or not ctx.is_connected_to_server:
|
||||
return
|
||||
|
||||
async def update(ctx: "Sly3Context", ap_connected: bool) -> None:
|
||||
if ctx.current_map == 0:
|
||||
ctx.game_interface.unlock_episodes()
|
||||
|
||||
await replace_text(ctx)
|
||||
# Maybe fix jobs if they break?
|
||||
|
||||
async def update(ctx: "Sly3Context") -> None:
|
||||
"""Called continuously"""
|
||||
pass
|
||||
if ctx.current_map is None:
|
||||
return
|
||||
|
||||
availability = accessibility(ctx)
|
||||
kick_from_episode(ctx, availability)
|
||||
|
||||
if not ctx.is_connected_to_server:
|
||||
return
|
||||
|
||||
await update_in_safehouse(ctx)
|
||||
await check_jobs_and_challenges(ctx)
|
||||
await send_checks(ctx)
|
||||
await receive_items(ctx)
|
||||
await check_goal(ctx)
|
||||
await handle_job_markers(ctx, availability["Jobs"])
|
||||
|
||||
if ctx.in_safehouse:
|
||||
await handle_notifications(ctx)
|
||||
await handle_deathlink(ctx)
|
||||
|
||||
@@ -59,9 +59,9 @@ class Sly3Context(CommonContext): # type: ignore[misc]
|
||||
is_connected_to_server: bool = False
|
||||
slot_data: Optional[Dict[str, Utils.Any]] = None
|
||||
last_error_message: Optional[str] = None
|
||||
# notification_queue: list[str] = []
|
||||
# notification_timestamp: float = 0
|
||||
# showing_notification: bool = False
|
||||
notification_queue: list[str] = []
|
||||
notification_timestamp: float = 0
|
||||
showing_notification: bool = False
|
||||
deathlink_timestamp: float = 0
|
||||
death_link_enabled = False
|
||||
queued_deaths: int = 0
|
||||
@@ -71,10 +71,11 @@ class Sly3Context(CommonContext): # type: ignore[misc]
|
||||
in_safehouse: bool = False
|
||||
in_hub: bool = False
|
||||
current_map: Optional[int] = None
|
||||
current_job: Optional[int] = None
|
||||
|
||||
# Items and checks
|
||||
inventory: Dict[int,int] = {l.code: 0 for l in Items.item_dict.values()}
|
||||
available_episodes: Dict[Sly3Episode,int] = {e: 0 for e in Sly3Episode}
|
||||
available_episodes: Dict[Sly3Episode,bool] = {e: False for e in Sly3Episode}
|
||||
thiefnet_items: Optional[list[str]] = None
|
||||
powerups: PowerUps = PowerUps()
|
||||
thiefnet_purchases: PowerUps = PowerUps()
|
||||
@@ -93,6 +94,7 @@ class Sly3Context(CommonContext): # type: ignore[misc]
|
||||
self.game_interface = Sly3Interface(logger)
|
||||
|
||||
def on_deathlink(self, data: Utils.Dict[str, Utils.Any]) -> None:
|
||||
# TODO
|
||||
pass
|
||||
|
||||
def make_gui(self):
|
||||
@@ -139,6 +141,10 @@ class Sly3Context(CommonContext): # type: ignore[misc]
|
||||
]
|
||||
}]))
|
||||
|
||||
def notification(self):
|
||||
# TODO
|
||||
pass
|
||||
|
||||
def update_connection_status(ctx: Sly3Context, status: bool):
|
||||
if ctx.is_connected_to_game == status:
|
||||
return
|
||||
@@ -158,6 +164,8 @@ async def _handle_game_not_ready(ctx: Sly3Context):
|
||||
|
||||
async def _handle_game_ready(ctx: Sly3Context) -> None:
|
||||
current_map = ctx.game_interface.get_current_map()
|
||||
ctx.in_hub = ctx.game_interface.in_hub()
|
||||
ctx.current_job = ctx.game_interface.get_current_job()
|
||||
|
||||
ctx.game_interface.skip_cutscene()
|
||||
|
||||
@@ -175,9 +183,9 @@ async def _handle_game_ready(ctx: Sly3Context) -> None:
|
||||
if ctx.current_map != current_map or new_connection:
|
||||
ctx.current_map = current_map
|
||||
ctx.is_connected_to_server = connected_to_server
|
||||
await init(ctx, connected_to_server)
|
||||
await init(ctx)
|
||||
|
||||
await update(ctx, connected_to_server)
|
||||
await update(ctx)
|
||||
|
||||
if ctx.server:
|
||||
ctx.last_error_message = None
|
||||
@@ -200,7 +208,8 @@ async def pcsx2_sync_task(ctx: Sly3Context):
|
||||
try:
|
||||
is_connected = ctx.game_interface.get_connection_state()
|
||||
update_connection_status(ctx, is_connected)
|
||||
if is_connected:
|
||||
game_started = ctx.game_interface.is_game_started()
|
||||
if is_connected and game_started:
|
||||
await _handle_game_ready(ctx)
|
||||
else:
|
||||
await _handle_game_not_ready(ctx)
|
||||
|
||||
@@ -195,6 +195,30 @@ class Sly3Interface(GameInterface):
|
||||
def is_loading(self) -> bool:
|
||||
return self._read32(self.addresses["loading"]) == 2
|
||||
|
||||
def in_safehouse(self) -> bool:
|
||||
# TODO
|
||||
return False
|
||||
|
||||
def in_hub(self) -> bool:
|
||||
# TODO
|
||||
return False
|
||||
|
||||
def is_goaled(self) -> bool:
|
||||
# TODO
|
||||
return False
|
||||
|
||||
def is_game_started(self) -> bool:
|
||||
# TODO
|
||||
return False
|
||||
|
||||
def showing_infobox(self) -> bool:
|
||||
# TODO
|
||||
return False
|
||||
|
||||
def alive(self) -> bool:
|
||||
# TODO
|
||||
return False
|
||||
|
||||
#######################
|
||||
## Getters & Setters ##
|
||||
#######################
|
||||
@@ -244,6 +268,26 @@ class Sly3Interface(GameInterface):
|
||||
relevant_bits = bits[2:48]
|
||||
return PowerUps(*relevant_bits)
|
||||
|
||||
def activate_jobs(self, job_ids: int|list[int]):
|
||||
# TODO
|
||||
pass
|
||||
|
||||
def deactivate_jobs(self, job_ids: int|list[int]):
|
||||
# TODO
|
||||
pass
|
||||
|
||||
def jobs_completed(self, job_ids: int|list[int]):
|
||||
# TODO
|
||||
pass
|
||||
|
||||
def current_infobox(self) -> int:
|
||||
# TODO
|
||||
pass
|
||||
|
||||
def get_damage_type(self) -> int:
|
||||
# TODO
|
||||
pass
|
||||
|
||||
#################
|
||||
## Other Utils ##
|
||||
#################
|
||||
@@ -272,6 +316,18 @@ class Sly3Interface(GameInterface):
|
||||
new_amount = max(current_amount + to_add,0)
|
||||
self._write32(self.addresses["coins"],new_amount)
|
||||
|
||||
def disable_infobox(self):
|
||||
# TODO
|
||||
pass
|
||||
|
||||
def set_infobox(self):
|
||||
# TODO
|
||||
pass
|
||||
|
||||
def kill_player(self):
|
||||
# TODO
|
||||
pass
|
||||
|
||||
#### TESTING ZONE ####
|
||||
|
||||
def read_text(interf: Sly3Interface, address: int):
|
||||
|
||||
@@ -13,6 +13,9 @@ from dataclasses import dataclass
|
||||
class StartingEpisode(Choice):
|
||||
"""
|
||||
Select Which episode to start with.
|
||||
|
||||
A Cold Alliance and Dead Men Tell No Tales require starting items, so
|
||||
starting with them will break a solo game.
|
||||
"""
|
||||
|
||||
display_name = "Starting Episode"
|
||||
@@ -37,6 +40,21 @@ class Goal(Choice):
|
||||
option_All_Bosses = 6
|
||||
default = 5
|
||||
|
||||
class BonusCrewMember(Choice):
|
||||
"""
|
||||
Which crew member, in addition to Sly, you start with.
|
||||
"""
|
||||
display_name = "Bonus Crew Member"
|
||||
option_None = 0
|
||||
option_Bentley = 1
|
||||
option_Murray = 2
|
||||
option_Guru = 3
|
||||
option_Penelope = 4
|
||||
option_Panda_King = 5
|
||||
option_Dimitri = 6
|
||||
option_Carmelita = 7
|
||||
default = 1
|
||||
|
||||
|
||||
class IncludeMegaJump(Toggle):
|
||||
"""
|
||||
@@ -77,7 +95,7 @@ class ThiefNetLocations(Range):
|
||||
display_name = "ThiefNet Locations"
|
||||
range_start = 0
|
||||
range_end = 37
|
||||
default = 25
|
||||
default = 20
|
||||
|
||||
class ThiefNetCostMinimum(Range):
|
||||
"""
|
||||
@@ -112,12 +130,14 @@ class Sly3Options(PerGameCommonOptions):
|
||||
thiefnet_locations: ThiefNetLocations
|
||||
thiefnet_minimum: ThiefNetCostMinimum
|
||||
thiefnet_maximum: ThiefNetCostMaximum
|
||||
bonus_crew_member: BonusCrewMember
|
||||
|
||||
sly3_option_groups = [
|
||||
OptionGroup("Goal",[
|
||||
Goal
|
||||
]),
|
||||
OptionGroup("Items",[
|
||||
BonusCrewMember,
|
||||
IncludeMegaJump,
|
||||
CoinsMinimum,
|
||||
CoinsMaximum
|
||||
|
||||
20
Sly3Pool.py
20
Sly3Pool.py
@@ -28,11 +28,23 @@ def gen_powerups(world: "Sly3World") -> list[Item]:
|
||||
|
||||
def gen_crew(world: "Sly3World") -> list[Item]:
|
||||
"""Generate the crew for the item pool"""
|
||||
crew = []
|
||||
for item_name in item_groups["Crew"]:
|
||||
crew.append(world.create_item(item_name))
|
||||
crew = list(item_groups["Crew"])
|
||||
|
||||
return crew
|
||||
bonus_crew_n = world.options.bonus_crew_member.value
|
||||
if bonus_crew_n != 0:
|
||||
bonus_crew = [
|
||||
"Bentley",
|
||||
"Murray",
|
||||
"Guru",
|
||||
"Penelope",
|
||||
"Panda King",
|
||||
"Dimitri",
|
||||
"Carmelita"
|
||||
][bonus_crew_n-1]
|
||||
crew.remove(bonus_crew)
|
||||
world.multiworld.push_precollected(world.create_item(bonus_crew))
|
||||
|
||||
return [world.create_item(c) for c in crew]
|
||||
|
||||
def gen_episodes(world: "Sly3World") -> list[Item]:
|
||||
"""Generate the episodes items for the item pool"""
|
||||
|
||||
@@ -46,7 +46,6 @@ def create_regions_sly3(world: "Sly3World"):
|
||||
world.multiworld.regions.append(menu)
|
||||
|
||||
for i, episode in enumerate(EPISODES.keys()):
|
||||
print(f"==={episode}===")
|
||||
for n in range(1,5):
|
||||
if n == 2 and episode == "Honor Among Thieves":
|
||||
break
|
||||
|
||||
29
Sly3Rules.py
29
Sly3Rules.py
@@ -5,6 +5,7 @@ from BaseClasses import CollectionState
|
||||
|
||||
from worlds.generic.Rules import add_rule
|
||||
from .data.Constants import EPISODES, CHALLENGES, REQUIREMENTS
|
||||
from .data.Locations import location_dict
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from . import Sly3World
|
||||
@@ -78,23 +79,19 @@ def set_rules_sly3(world: "Sly3World"):
|
||||
][world.options.goal.value]
|
||||
|
||||
victory_location = world.multiworld.get_location(victory_condition, world.player)
|
||||
victory_location.address = None
|
||||
victory_location.place_locked_item(world.create_event("Victory"))
|
||||
world.multiworld.completion_condition[world.player] = lambda state: state.has("Victory", world.player)
|
||||
elif world.options.goal.value == 6:
|
||||
def access_rule(state: CollectionState):
|
||||
victory_conditions = [
|
||||
"An Opera of Fear - Operation: Tar-Be Gone!",
|
||||
"Rumble Down Under - Operation: Moon Crash",
|
||||
"Flight of Fancy - Operation: Turbo Dominant Eagle",
|
||||
"A Cold Alliance - Operation: Wedding Crasher",
|
||||
"Dead Men Tell No Tales - Operation: Reverse Double-Cross",
|
||||
"Honor Among Thieves - Final Legacy"
|
||||
]
|
||||
all_requirements = list(set(sum([sum(sum(ep,[]),[]) for ep in REQUIREMENTS["Jobs"].values()],[])))
|
||||
menu_region = world.multiworld.get_region("Menu", world.player)
|
||||
menu_region.add_locations({"All Bosses": location_dict["All Bosses"].code})
|
||||
|
||||
return all(
|
||||
world.multiworld.get_location(cond,world.player).access_rule(state)
|
||||
for cond in victory_conditions
|
||||
victory_location = world.multiworld.get_location("All Bosses", world.player)
|
||||
add_rule(
|
||||
victory_location,
|
||||
lambda state, items=reqs: (
|
||||
all(state.has(item, player) for item in all_requirements)
|
||||
)
|
||||
)
|
||||
|
||||
world.multiworld.completion_condition[world.player] = access_rule
|
||||
victory_location.address = None
|
||||
victory_location.place_locked_item(world.create_event("Victory"))
|
||||
world.multiworld.completion_condition[world.player] = lambda state: state.has("Victory", world.player)
|
||||
|
||||
@@ -109,6 +109,7 @@ class Sly3World(World):
|
||||
self.options.thiefnet_locations.value = slot_data["thiefnet_locations"]
|
||||
self.options.thiefnet_minimum.value = slot_data["thiefnet_minimum"]
|
||||
self.options.thiefnet_maximum.value = slot_data["thiefnet_maximum"]
|
||||
self.options.bonus_crew_member.value = slot_data["bonus_crew_member"]
|
||||
return
|
||||
|
||||
self.validate_options(self.options)
|
||||
@@ -159,6 +160,7 @@ class Sly3World(World):
|
||||
"thiefnet_locations",
|
||||
"thiefnet_minimum",
|
||||
"thiefnet_maximum",
|
||||
"bonus_crew_member",
|
||||
)
|
||||
|
||||
def fill_slot_data(self) -> Mapping[str, Any]:
|
||||
|
||||
@@ -523,3 +523,5 @@ MENU_RETURN_DATA = (
|
||||
"7F2319BC"+
|
||||
"7B8274B1"
|
||||
)
|
||||
|
||||
DEATH_TYPES = {} # TODO
|
||||
|
||||
@@ -26,7 +26,7 @@ challenges_list = [
|
||||
for challenge in challenges
|
||||
]
|
||||
|
||||
location_list = jobs_list + purchases_list + challenges_list
|
||||
location_list = jobs_list + purchases_list + challenges_list + [("All Bosses", "-")]
|
||||
|
||||
base_code = 8008135
|
||||
|
||||
|
||||
154
data/completed.txt
Normal file
154
data/completed.txt
Normal file
@@ -0,0 +1,154 @@
|
||||
m1_recon - 468FEC
|
||||
|
||||
m1_follow - 468FAC
|
||||
m1_gauntlet - 468FBC
|
||||
m1_canal_chase - 468F7C
|
||||
|
||||
m1_turf_war - 46900C
|
||||
m1_ball - 468F6C
|
||||
m1_run - 468FFC
|
||||
m1_disguise - 468F9C
|
||||
|
||||
m1_heist - 468FCC
|
||||
|
||||
#################
|
||||
|
||||
m2_recon - 46909C
|
||||
|
||||
m2_bridge - 46902C
|
||||
m2_cave - 46903C
|
||||
m2_dumptruck - 46905C
|
||||
m2_shaman - 4690AC
|
||||
|
||||
m2_claw - 46904C
|
||||
m2_bar_brawl - 46901C
|
||||
m2_feed_croc - 46906C
|
||||
|
||||
m2_heist - 46907C
|
||||
|
||||
#################
|
||||
|
||||
m3_roster - 46916C
|
||||
|
||||
m3_frame_a - 4690DC
|
||||
m3_frame_b - 4690EC
|
||||
m3_hangar_defense - 46910C
|
||||
m3_semifinals - 46917C
|
||||
|
||||
m3_wolf - 46919C
|
||||
m3_windmill_hack - 46918C
|
||||
m3_muggshot - 46914C
|
||||
|
||||
m3_heist - 46911C
|
||||
|
||||
#################
|
||||
|
||||
m4_recon - 46920C
|
||||
|
||||
m4_get_job - 4691BC
|
||||
m4_van - 46922C
|
||||
m4_webcam - 46923C
|
||||
m4_stealing_thiefnet - 46921C
|
||||
|
||||
m4_zombies - 46925C
|
||||
m4_rccar - 4691FC
|
||||
m4_battery - 4691AC
|
||||
|
||||
m4_heist - 4691CC
|
||||
|
||||
#################
|
||||
|
||||
m5_recon - 4692FC
|
||||
|
||||
m5_love - 4692CC
|
||||
m5_jollyboat - 4692BC
|
||||
m5_treasure - 46931C
|
||||
|
||||
m5_squid - 46930C
|
||||
m5_dive - 46929C
|
||||
m5_battle - 46926C
|
||||
|
||||
m5_heist - 4692AC
|
||||
|
||||
#################
|
||||
|
||||
m6_freesly - 46936C
|
||||
m6_shark - 46938C
|
||||
m6_dive - 46935C
|
||||
m6_car - 46934C
|
||||
m6_biplane - 46932C
|
||||
m6_gauntlet - 46937C
|
||||
m6_boss - 46933C
|
||||
m6_vault - 46939C
|
||||
|
||||
#################
|
||||
|
||||
w1_canal_chase_health - 46DF30
|
||||
|
||||
w1_ball_timed - 46DF20
|
||||
w1_run_gauntlet - 46DF98
|
||||
w1_run_chase - 46DF90
|
||||
|
||||
w1_heist_bombing - 46DF60
|
||||
w1_heist_canal - 46DF70
|
||||
w1_heist_boss - 46DF68o
|
||||
w1_map - 46DF78
|
||||
|
||||
#################
|
||||
|
||||
w2_recon_gauntlet - 46E028
|
||||
|
||||
w2_cave_a_enter - 46DFC8
|
||||
w2_cave_b_escape - 46DFD0
|
||||
w2_dumptruck_tower - 46DFF0
|
||||
w2_shaman_guards - 46E038
|
||||
|
||||
w2_claw_section2 - 46DFE0
|
||||
w2_bar_brawl_timed - 46DFB0
|
||||
w2_feed_croc_brawl - 46E000
|
||||
|
||||
w2_heist_c - 46E010
|
||||
w2_map - 46E018
|
||||
|
||||
#################
|
||||
|
||||
w3_roster_ascension - 46E0B0
|
||||
|
||||
w3_hangar_defense_brawl - 46E068
|
||||
w3_hangar_defense_security - 46E078
|
||||
w3_hangar_defense_chopper - 46E070
|
||||
w3_semifinals_spree - 46E0C0
|
||||
|
||||
w3_wolf_ride - 46E0D8
|
||||
w3_muggshot_spree - 46E0A0
|
||||
|
||||
w3_heist_boss - 46E088
|
||||
w3_map - 46E090
|
||||
|
||||
#################
|
||||
|
||||
w4_murray_bounce_timed - 46E100
|
||||
|
||||
w4_van_turret - 46E138
|
||||
w4_stealing_thiefnet_treetop - 46E128
|
||||
w4_stealing_thiefnet_ground - 46E120
|
||||
|
||||
w4_map - 46E0F8
|
||||
|
||||
#################
|
||||
|
||||
w5_recon_patch - 46E1B0
|
||||
w5_recon_peg_leg - 46E1B8
|
||||
|
||||
w5_jollyboat_armor - 46E190
|
||||
w5_boat_hunt - 46E160
|
||||
|
||||
w5_map - 46E1A0
|
||||
|
||||
#################
|
||||
|
||||
w6_freesly_battle - 46E210
|
||||
w6_car_battle - 46E1F8
|
||||
w6_biplane_boss - 46E1D8
|
||||
w6_gauntlet_timed - 46E220
|
||||
w6_boss_timed - 46E1E8
|
||||
Reference in New Issue
Block a user