· 2 years ago · Jul 17, 2023, 01:10 PM
1---- tfm_lua/pshy.games.pacmice.tfm.lua.txt
2---
3--- This script is a compilation of other scripts.
4--- Compiler: pshy_merge (https://github.com/Pshy0/pshy_merge).
5--- pshy version: v0.12.17
6---
7
8if __PSHY_PASTED__ then error("<b><r>\nYOU PASTED THE SCRIPT TWICE!!!</r></b>") end
9do
10local pshy = {}
11pshy.MAIN_MODULE_NAME = "pshy.games.pacmice"
12pshy.PSHY_VERSION = "v0.12.17"
13pshy.BUILD_TIME = "1687959979.4384763"
14pshy.INIT_TIME = os.time()
15math.randomseed(os.time())
16if not _ENV then _ENV = _G end
17_ENV.pshy = pshy
18print(" ")
19pshy.modules_list = {
20[1] = {name = "pshy.compiler.require", file = "./lua/pshy/compiler/require.lua", start_line = 78, end_line = 117},
21[2] = {name = "pshy.patches.old_movephysicobject", file = "./lua/pshy/patches/old_movephysicobject.lua", start_line = 120, end_line = 125, manually_enabled = true},
22[3] = {name = "pshy.events", file = "./lua/pshy/events/init.lua", start_line = 127, end_line = 230},
23[4] = {name = "pshy.utils.print", file = "./lua/pshy/utils/print.lua", start_line = 232, end_line = 252},
24[5] = {name = "pshy.help.pages", file = "./lua/pshy/help/pages.lua", start_line = 255, end_line = 261},
25[6] = {name = "pshy.commands.list", file = "./lua/pshy/commands/list/init.lua", start_line = 263, end_line = 266},
26[7] = {name = "pshy.utils.ids", file = "./lua/pshy/utils/ids.lua", start_line = 268, end_line = 323},
27[8] = {name = "pshy.room", file = "./lua/pshy/room.lua", start_line = 325, end_line = 340},
28[9] = {name = "pshy.alternatives.chat", file = "./lua/pshy/alternatives/chat.lua", start_line = 343, end_line = 406},
29[10] = {name = "pshy.alternatives.timers", file = "./lua/pshy/alternatives/timers.lua", start_line = 408, end_line = 473},
30[11] = {name = "pshy.players", file = "./lua/pshy/players/init.lua", start_line = 475, end_line = 512},
31[12] = {name = "pshy.anticheats.ban", file = "./lua/pshy/anticheats/ban.lua", start_line = 515, end_line = 700},
32[13] = {name = "pshy.perms", file = "./lua/pshy/perms.lua", start_line = 703, end_line = 1007},
33[14] = {name = "pshy.anticheats.adminchat", file = "./lua/pshy/anticheats/adminchat.lua", start_line = 1010, end_line = 1045},
34[15] = {name = "pshy.anticheats.loadersync", file = "./lua/pshy/anticheats/loadersync.lua", start_line = 1048, end_line = 1118},
35[16] = {name = "pshy.bases.loopmore", file = "./lua/pshy/bases/loopmore.lua", start_line = 1120, end_line = 1196},
36[17] = {name = "pshy.utils.strings", file = "./lua/pshy/utils/strings.lua", start_line = 1198, end_line = 1237},
37[18] = {name = "pshy.ui.dialog", file = "./lua/pshy/ui/dialog.lua", start_line = 1239, end_line = 1280},
38[19] = {name = "pshy.enums.colors", file = "./lua/pshy/enums/colors.lua", start_line = 1282, end_line = 1316},
39[20] = {name = "pshy.utils.lua", file = "./lua/pshy/utils/lua.lua", start_line = 1318, end_line = 1356},
40[21] = {name = "pshy.utils.tfm", file = "./lua/pshy/utils/tfm.lua", start_line = 1358, end_line = 1410},
41[22] = {name = "pshy.utils.types", file = "./lua/pshy/utils/types.lua", start_line = 1412, end_line = 1547},
42[23] = {name = "pshy.commands", file = "./lua/pshy/commands/init.lua", start_line = 1549, end_line = 1861},
43[24] = {name = "pshy.ui.v1", file = "./lua/pshy/ui/v1.lua", start_line = 1863, end_line = 1914},
44[25] = {name = "pshy.bases.scores", file = "./lua/pshy/bases/scores.lua", start_line = 1916, end_line = 2074},
45[26] = {name = "pshy.bases.splashscreen", file = "./lua/pshy/bases/splashscreen.lua", start_line = 2076, end_line = 2109},
46[27] = {name = "pshy.bases.version", file = "./lua/pshy/bases/version.lua", start_line = 2111, end_line = 2153},
47[28] = {name = "pshy.utils.tables", file = "./lua/pshy/utils/tables.lua", start_line = 2155, end_line = 2244},
48[29] = {name = "pshy.bonuses.list", file = "./lua/pshy/bonuses/list/init.lua", start_line = 2246, end_line = 2249},
49[30] = {name = "pshy.images.list", file = "./lua/pshy/images/list/init.lua", start_line = 2251, end_line = 2255},
50[31] = {name = "pshy.bonuses", file = "./lua/pshy/bonuses/init.lua", start_line = 2257, end_line = 2549},
51[32] = {name = "pshy.images.list.bonuses", file = "./lua/pshy/images/list/bonuses.lua", start_line = 2551, end_line = 2579},
52[33] = {name = "pshy.players.keyboard", file = "./lua/pshy/players/keyboard.lua", start_line = 2581, end_line = 2625},
53[34] = {name = "pshy.bonuses.list.mario", file = "./lua/pshy/bonuses/list/mario.lua", start_line = 2627, end_line = 2741},
54[35] = {name = "pshy.moduleswitch", file = "./lua/pshy/moduleswitch.lua", start_line = 2743, end_line = 2831},
55[36] = {name = "pshy.commands.list.modules", file = "./lua/pshy/commands/list/modules.lua", start_line = 2834, end_line = 2939},
56[37] = {name = "pshy.enums.keycodes", file = "./lua/pshy/enums/keycodes.lua", start_line = 2941, end_line = 2997},
57[38] = {name = "pshy.help", file = "./lua/pshy/help/init.lua", start_line = 2999, end_line = 3219},
58[39] = {name = "pshy.images.addimage", file = "./lua/pshy/images/addimage.lua", start_line = 3221, end_line = 3261},
59[40] = {name = "pshy.images.searchimage", file = "./lua/pshy/images/searchimage.lua", start_line = 3264, end_line = 3327},
60[41] = {name = "pshy.commands.get_target_or_error", file = "./lua/pshy/commands/get_target_or_error.lua", start_line = 3329, end_line = 3343},
61[42] = {name = "pshy.images.changeimage", file = "./lua/pshy/images/changeimage.lua", start_line = 3346, end_line = 3485},
62[43] = {name = "pshy.utils.rotation", file = "./lua/pshy/utils/rotation.lua", start_line = 3487, end_line = 3554},
63[44] = {name = "pshy.maps.list", file = "./lua/pshy/maps/list/init.lua", start_line = 3556, end_line = 3561},
64[45] = {name = "pshy.rotations.list", file = "./lua/pshy/rotations/list/init.lua", start_line = 3563, end_line = 3578},
65[46] = {name = "pshy.rotations.list.transformice", file = "./lua/pshy/rotations/list/transformice.lua", start_line = 3580, end_line = 3618},
66[47] = {name = "pshy.rotations.newgame.settings_override", file = "./lua/pshy/rotations/newgame/settings_override.lua", start_line = 3620, end_line = 3646},
67[48] = {name = "pshy.rotations.newgame", file = "./lua/pshy/rotations/newgame/init.lua", start_line = 3649, end_line = 4201},
68[49] = {name = "pshy.tools.fcplatform", file = "./lua/pshy/tools/fcplatform.lua", start_line = 4204, end_line = 4362},
69[50] = {name = "pshy.tools.motd", file = "./lua/pshy/tools/motd.lua", start_line = 4365, end_line = 4420},
70[51] = {name = "pshy.games.pacmice", file = "./lua/pshy/games/pacmice.lua", start_line = 4424, end_line = 4978, manually_enabled = true},
71}
72pshy.modules = pshy.modules or {}
73for i_module, module in ipairs(pshy.modules_list) do
74 pshy.modules[module.name] = module
75 module.required_modules = {}
76end
77do
78
79pshy.require_postload_functions={}
80pshy.loading_module_names={}
81pshy.loaded_module_list={}
82function pshy.require(module_name,is_required)
83local module=pshy.modules[module_name]
84if not module then
85if is_required~=false then
86print(string.format("<r>ERROR: <n>require: Module `%s` not found!",module_name))
87end
88return nil
89end
90if#pshy.loading_module_names>0 and is_required==nil then
91pshy.modules[pshy.loading_module_names[#pshy.loading_module_names]].required_modules[module_name]=module
92end
93if not module.loaded then
94if module.loading then
95error(string.format("<r> Module `%s` recursively required!",module_name))
96end
97module.loading=true
98table.insert(pshy.loading_module_names,module_name)
99local success
100success,module.value=pcall(module.load)
101table.remove(pshy.loading_module_names,#pshy.loading_module_names)
102if not success then
103if is_required~=false then
104error(string.format("<r>Loading %s:\n %s",module_name,module.value))
105end
106module.value=nil
107end
108module.loading=false
109module.loaded=true
110table.insert(pshy.loaded_module_list,module)
111for i_postload_function,postload_function in ipairs(pshy.require_postload_functions)do
112postload_function(module_name)
113end
114end
115return pshy.modules[module_name].value
116end
117end
118pshy.modules["pshy.compiler.require"].loaded = true
119pshy.modules["pshy.patches.old_movephysicobject"].load = function()
120
121local incorrect_tfm_exec_movePhysicObject=tfm.exec.movePhysicObject
122tfm.exec.movePhysicObject=function(id,x,y,pos_offset,vx,vy,speed_offset,...)
123return incorrect_tfm_exec_movePhysicObject(id,x,y,pos_offset,(vx or 0)/10,(vy or 0)/10,speed_offset,...)
124end
125end
126pshy.modules["pshy.events"].load = function()
127
128local events={}
129events.to_minimize={}
130events.to_minimize["eventEmotePlayed"]=true
131events.to_minimize["eventKeyboard"]=true
132events.to_minimize["eventPlayerCrouchKey"]=true
133events.to_minimize["eventPlayerGetCheese"]=true
134events.to_minimize["eventPlayerJumpKey"]=true
135events.to_minimize["eventPlayerMeep"]=true
136events.to_minimize["eventPlayerMeepKey"]=true
137events.module_only_events={
138["eventThisModuleEnabled"]=true,
139["eventThisModuleDisabled"]=true
140}
141events.events={}
142events.global_events={}
143local event_functions_created=false
144local function RecoverEventFunctions(module_name)
145local module=pshy.modules[module_name]
146module.events={}
147module.event_count=0
148for obj_name,obj in pairs(_ENV)do
149if type(obj)=="function"and string.find(obj_name,"event",1,true)==1 then
150module.event_count=module.event_count+1
151module.events[obj_name]=obj
152end
153end
154for event_name,event_function in pairs(module.events)do
155_ENV[event_name]=nil
156end
157end
158function events.UpdateEventFunctions(module_name)
159local module=pshy.modules[module_name]
160assert(module_name~=nil)
161for obj_name,obj in pairs(_ENV)do
162if type(obj)=="function"then
163if not module.events or not module.events[obj_name]then
164print("<r>ERROR: cannot add new events after initialization.</r>")
165else
166module.events[obj_name]=obj
167if events.global_events[obj_name]then
168if events.global_events[obj_name]~=obj then
169local i_module=events.events[obj_name].module_indices[module_name]
170events.events[obj_name].original_functions[i_module]=obj
171events.events[obj_name].functions[i_module]=obj
172_ENV[obj_name]=events.global_events[obj_name]
173end
174end
175end
176end
177end
178end
179local function CreateEventsTable()
180for i_module,module in ipairs(pshy.loaded_module_list)do
181if module.events then
182for event_name,event_function in pairs(module.events)do
183if not events.module_only_events[event_name]then
184if not events.events[event_name]then
185events.events[event_name]={module_names={},module_indices={},functions={},original_functions={}}
186end
187table.insert(events.events[event_name].module_names,module.name)
188events.events[event_name].module_indices[module.name]=#events.events[event_name].module_names
189table.insert(events.events[event_name].original_functions,event_function)
190table.insert(events.events[event_name].functions,event_function)
191end
192end
193end
194end
195end
196function events.MakeEventFunction(event_name,event_functions)
197return function(...)
198for i_func,func in ipairs(event_functions)do
199if(func(...)~=nil)then
200return
201end
202end
203end
204end
205function events.MakeMinimumEventFunction(event_name,event_functions)
206return function(...)
207for i_func,func in ipairs(event_functions)do
208func(...)
209end
210end
211end
212function events.CreateFunctions()
213CreateEventsTable()
214assert(event_functions_created==false)
215for event_name,event in pairs(events.events)do
216if not events.to_minimize[event_name]then
217_ENV[event_name]=events.MakeEventFunction(event_name,event.functions)
218else
219_ENV[event_name]=events.MakeMinimumEventFunction(event_name,event.functions)
220end
221events.global_events[event_name]=_ENV[event_name]
222end
223event_functions_created=true
224if eventInit then
225eventInit(os.time()-pshy.INIT_TIME)
226end
227end
228table.insert(pshy.require_postload_functions,RecoverEventFunctions)
229return events
230end
231do
232
233local function nothrow_format(format,...)
234local rst,rtn=pcall(string.format,format,...)
235return rtn
236end
237function print_debug(format,...)
238print("<bv>DEBUG: </bv>"..nothrow_format(tostring(format),...))
239end
240function print_info(format,...)
241print("<ch>INFO: </ch>"..nothrow_format(tostring(format),...))
242end
243function print_warn(format,...)
244print("<o>WARN: </o>"..nothrow_format(tostring(format),...))
245end
246function print_error(format,...)
247print("<r>ERROR: </r>"..nothrow_format(tostring(format),...))
248end
249function print_critical(format,...)
250print("<r>CRITICAL: </r>"..nothrow_format(tostring(format),...))
251end
252end
253pshy.modules["pshy.utils.print"].loaded = true
254pshy.modules["pshy.help.pages"].load = function()
255
256local help_pages={}
257help_pages[""]={title="Main Help",text="Use '<j>*</j>' to run a command on all players.\nPrefix commands with `<j>pshy.</j>` or <j>`other.`</j> in case of conflict.\n",details="Commands syntax:\n\n<p align='left'><v>!command(aliases) <required_argument> [optional_argument]</v></p>\nCommands color code:\n\n<p align='left'><v>GREEN - Commands everyone can use (commands may still not allow some actions).<v>\n<j>YELLOW - Cheat commands that are enabled when an admin use `!enablecheats`.</j>\n<r>RED - Admin only commands.</r>\n<vi>PURPLE - Script loader only commands.</vi></p>\n",subpages={}}
258help_pages["pshy"]={back="",title="Pshy",text="Pshy version '<ch2>"..tostring(pshy.PSHY_VERSION).."</ch2>'.\n",subpages={}}
259help_pages[""].subpages["pshy"]=help_pages["pshy"]
260return help_pages
261end
262pshy.modules["pshy.commands.list"].load = function()
263
264local command_list={}
265return command_list
266end
267pshy.modules["pshy.utils.ids"].load = function()
268
269local ids={}
270local init_done=true
271local pools={}pools["Popup"]={first_id=4624,last_id=14624}
272pools["ColorPicker"]={first_id=4624,last_id=14624}
273pools["TextArea"]={first_id=4624,last_id=14624}
274pools["PhysicObject"]={first_id=4624,last_id=14624}pools["Joint"]={first_id=4624,last_id=14624}pools["Bonus"]={first_id=4624,last_id=14624}
275for pool_name,pool in pairs(pools)do
276pool.allocated={}pool.freed={}pool.next_id=pool.first_id pool.init_id=pool.next_id local allocated=pool.allocated
277local freed=pool.freed
278local first_id=pool.first_id
279local last_id=pool.last_id
280ids["Alloc"..pool_name.."Id"]=function()
281local new_id
282if#freed>0 then
283new_id=freed[#freed]
284table.remove(freed,#freed)
285end
286if not new_id then
287for id=pool.next_id,last_id do
288if not allocated[id]then
289new_id=id
290break
291end
292end
293end
294assert(new_id)
295allocated[new_id]=true
296pool.next_id=new_id+1
297return new_id
298end
299ids["Reserve"..pool_name.."Id"]=function(new_id)
300assert(type(new_id)=="number")
301if new_id<first_id or new_id>last_id then
302return
303end
304allocated[new_id]=true
305return new_id
306end
307ids["Free"..pool_name.."Id"]=function(old_id)
308if allocated[old_id]then
309allocated[old_id]=false
310if old_id>=pool.init_id then
311table.insert(freed,#freed+1,old_id)
312end
313end
314end
315end
316function eventInit()
317init_done=true
318for pool_name,pool in pairs(pools)do
319pool.init_id=pool.next_id
320end
321end
322return ids
323end
324pshy.modules["pshy.room"].load = function()
325pshy.require("pshy.events")
326local room={}
327room.loader=string.match(({pcall(nil)})[2],"^(.-)%.")
328room.launcher=nil
329for player_name in pairs(tfm.get.room.playerList)do
330if room.launcher then
331room.launcher=room.loader
332break
333end
334room.launcher=player_name
335end
336room.is_private=string.sub(tfm.get.room.name,1,1)=="@"
337room.is_tribehouse=tfm.get.room.isTribeHouse
338room.is_funcorp=not room.is_tribehouse
339return room
340end
341pshy.modules["pshy.alternatives.chat"].load = function()
342local __MODULE_NAME__ = "pshy.alternatives.chat"
343pshy.require("pshy.events")
344pshy.require("pshy.utils.print")
345local help_pages=pshy.require("pshy.help.pages")
346local command_list=pshy.require("pshy.commands.list")
347local ids=pshy.require("pshy.utils.ids")
348local room=pshy.require("pshy.room")
349local alternative_chat={}
350help_pages[__MODULE_NAME__]={title="Alternatives",text="Allow some scripts to run without all lua features.\n",commands={}}
351alternative_chat.chat_id=ids.AllocTextAreaId()
352local have_sync_access=room.is_funcorp
353local players_chats={}local players_hidden_chats={}
354local function GetPlayerChatContent(player_name)
355local chat=players_chats[player_name]
356local total=""
357for i_line,line in ipairs(chat)do
358total="<n>"..total..line.."</n>\n"
359end
360return total
361end
362local function UpdatePlayerChat(player_name)
363if not players_hidden_chats[player_name]then
364local text=GetPlayerChatContent(player_name)
365ui.addTextArea(alternative_chat.chat_id,text,player_name,0,50,400,nil,0x0,0x0,1.0,true)
366else
367ui.removeTextArea(alternative_chat.chat_id,player_name)
368end
369end
370local function chatMessage(message,player_name)
371if type(message)~="string"then
372message=tostring(message)
373end
374message=message:gsub("http","https"):gsub("://","://")
375if#message>200 then
376print_error("<fc>[Alt]</fc> chatMessage: message length is limited to 200!")
377return
378end
379if not player_name then
380for player_name in pairs(tfm.get.room.playerList)do
381chatMessage(message,player_name)
382end
383return
384end
385players_chats[player_name]=players_chats[player_name]or{}
386local chat=players_chats[player_name]
387if#chat>8 then
388table.remove(chat,1)
389end
390table.insert(chat,message)
391UpdatePlayerChat(player_name)
392end
393local function ChatCommandChat(user)
394players_hidden_chats[user]=not players_hidden_chats[user]
395UpdatePlayerChat(user)
396return true
397end
398command_list["chat"]={perms="everyone",func=ChatCommandChat,desc="toggle the alternative chat",argc_min=0,argc_max=0}
399help_pages[__MODULE_NAME__].commands["chat"]=command_list["chat"]
400if not have_sync_access then
401tfm.exec.chatMessage=chatMessage
402chatMessage("▣ This text area is replacing tfm.exec.chatMessage().")
403chatMessage("▣ Type <ch2>!chat</ch2> to toggle this text.")
404end
405return alternative_chat
406end
407pshy.modules["pshy.alternatives.timers"].load = function()
408pshy.require("pshy.events")
409pshy.require("pshy.utils.print")
410local room=pshy.require("pshy.room")
411local alternative_timers={}
412local have_sync_access=room.is_funcorp
413local timers={}
414local function newTimer(callback,time,loop,arg1,arg2,arg3,arg4)
415if time<500 then
416print_error("newTimer: minimum time is 500 (you passed %d)!",time)
417return
418end
419local timer_id=1
420while timers[timer_id]do
421timer_id=timer_id+1
422end
423timers[timer_id]={}
424timer=timers[timer_id]
425timer.timer_id=timer_id
426timer.callback=callback
427timer.time=time
428timer.loop=loop
429timer.arg1=arg1
430timer.arg2=arg2
431timer.arg3=arg3
432timer.arg4=arg4
433timer.next_run_time=os.time()+timer.time
434return timer_id
435end
436local function removeTimer(timer_id)
437if timer_id then
438timers[timer_id]=nil
439end
440end
441function alternative_timers.RunTimers()
442local time=os.time()
443if not have_sync_access then
444local ended_timers={}
445local timers_copy={}
446local timers_cnt=0
447for i_timer,timer in pairs(timers)do
448timers_copy[i_timer]=timer
449timers_cnt=timers_cnt+1
450end
451for i_timer,timer in pairs(timers_copy)do
452if timer.next_run_time<time then
453timer.callback(timer.timer_id,timer.arg1,timer.arg2,timer.arg3,timer.arg4)
454if timer.loop then
455timer.next_run_time=timer.next_run_time+timer.time else
456ended_timers[i_timer]=true
457end
458end
459end
460for i_ended_timer in pairs(ended_timers)do
461timers[i_ended_timer]=nil
462end
463end
464end
465if not have_sync_access then
466system.newTimer=newTimer
467system.removeTimer=removeTimer
468function eventLoop()
469alternative_timers.RunTimers()
470end
471end
472return alternative_timers
473end
474pshy.modules["pshy.players"].load = function()
475pshy.require("pshy.events")
476local players={}
477players.list={}players.in_room={}players.in_room_count=0
478local player_list=players.list
479local players_in_room=players.in_room
480local function TouchPlayer(player_name)
481if not player_list[player_name]then
482local new_player={}
483new_player.name=player_name
484new_player.tfm_player=tfm.get.room.playerList[player_name]
485new_player.tag=string.match(player_name,"#....$")
486player_list[player_name]=new_player
487players_in_room[player_name]=new_player
488else
489players_in_room[player_name]=player_list[player_name]
490end
491end
492function eventNewPlayer(player_name)
493if not players_in_room[player_name]then
494TouchPlayer(player_name)
495players.in_room_count=players.in_room_count+1
496end
497end
498function eventPlayerRespawn(player_name)
499if not players_in_room[player_name]then
500eventNewPlayer(player_name)
501end
502end
503function eventPlayerLeft(player_name)
504players_in_room[player_name]=nil
505players.in_room_count=players.in_room_count-1
506end
507for player_name in pairs(tfm.get.room.playerList)do
508TouchPlayer(player_name)
509players.in_room_count=players.in_room_count+1
510end
511return players
512end
513pshy.modules["pshy.anticheats.ban"].load = function()
514local __MODULE_NAME__ = "pshy.anticheats.ban"
515local command_list=pshy.require("pshy.commands.list")
516pshy.require("pshy.events")
517local help_pages=pshy.require("pshy.help.pages")
518local players=pshy.require("pshy.players")
519local player_list=players.list local ids=pshy.require("pshy.utils.ids")
520help_pages[__MODULE_NAME__]={restricted=true,back="pshy",title="Kick / Ban",text="",commands={}}
521help_pages["pshy"].subpages[__MODULE_NAME__]=help_pages[__MODULE_NAME__]
522local ban={}
523ban.banned_players={}
524ban.shadow_banned_players={}
525ban.shadowban_simulate_death=false
526ban.shadowban_abort_winning=true
527local player_list=players.list
528local ban_mask_ui_id=ids.AllocTextAreaId()
529local pass_next_event_player_died=false
530local banned_players=ban.banned_players
531local shadow_banned_players=ban.shadow_banned_players
532local tfm_exec_respawnPlayer=tfm.exec.respawnPlayer
533tfm.exec.respawnPlayer=function(player_name,...)
534if banned_players[player_name]then
535return
536end
537return tfm_exec_respawnPlayer(player_name,...)
538end
539local function ApplyBanEffects(player_name)
540tfm.exec.removeCheese(player_name)
541tfm.exec.movePlayer(player_name,-1001,-1001,false,0,0,true)
542tfm.exec.killPlayer(player_name)
543ui.addTextArea(ban_mask_ui_id,"",player_name,-999,-999,800+2002,400+2002,0x111111,0,0.01,false)
544tfm.exec.setPlayerScore(player_name,-1,false)
545end
546function ban.KickPlayer(player_name,reason)
547local player=player_list[player_name]
548if player.banned then
549return false,"This player is already banned."
550end
551banned_players[player_name]=player
552player.kicked=true
553player.banned=true
554player.ban_reason=reason or"reason not provided"
555ApplyBanEffects(player_name)
556return true,string.format("%s script kicked (%s)",player_name,player.ban_reason)
557end
558command_list["kick"]={perms="admins",func=ban.KickPlayer,desc="'Kick' a player from the script (they need to rejoin).",no_user=true,argc_min=1,argc_max=1,arg_types={"player"}}
559help_pages[__MODULE_NAME__].commands["kick"]=command_list["kick"]
560function ban.BanPlayer(player_name,reason)
561local player=player_list[player_name]
562if player.banned and not player.kicked then
563return false,"This player is already banned."
564end
565banned_players[player_name]=player
566player.kicked=false
567player.banned=true
568player.ban_reason=reason or"reason not provided"
569ApplyBanEffects(player_name)
570return true,string.format("%s script banned (%s)",player_name,player.ban_reason)
571end
572command_list["ban"]={perms="admins",func=ban.BanPlayer,desc="'ban' a player from the script.",no_user=true,argc_min=1,argc_max=1,arg_types={"player"}}
573help_pages[__MODULE_NAME__].commands["ban"]=command_list["ban"]
574function ban.ShadowBanPlayer(player_name,reason)
575local player=player_list[player_name]
576shadow_banned_players[player_name]=player
577player.kicked=false
578player.banned=false
579player.shadow_banned=true
580player.shadow_ban_score=tfm.get.room.playerList[player_name].score
581player.ban_reason=reason or"reason not provided"
582if ban.shadowban_simulate_death then
583pass_next_event_player_died=true
584eventPlayerDied(player_name)
585end
586return true,string.format("%s script shadowbanned (%s)",player_name,player.ban_reason)
587end
588command_list["shadowban"]={perms="admins",func=ban.ShadowBanPlayer,desc="Disable most of the script's features for this player.",no_user=true,argc_min=1,argc_max=1,arg_types={"player"}}
589help_pages[__MODULE_NAME__].commands["shadowban"]=command_list["shadowban"]
590function ban.UnbanPlayer(player_name)
591local player=player_list[player_name]
592if not player then
593return false,"This player does not exist."
594end
595if not player.kicked and not player.banned and not player.shadow_banned then
596return false,"This player is not banned."
597end
598banned_players[player_name]=nil
599shadow_banned_players[player_name]=nil
600player.kicked=false
601player.banned=false
602player.shadow_banned=false
603ui.removeTextArea(ban_mask_ui_id,player_name)
604return true,string.format("Unbanned %s.",player_name)
605end
606command_list["unban"]={perms="admins",func=ban.UnbanPlayer,desc="Unban a player from the room.",no_user=true,argc_min=1,argc_max=1,arg_types={"string"}}
607help_pages[__MODULE_NAME__].commands["unban"]=command_list["unban"]
608function eventNewPlayer(player_name)
609if banned_players[player_name]then
610ApplyBanEffects(player_name)
611end
612end
613function eventPlayerLeft(player_name)
614local player=banned_players[player_name]
615if player and player.kicked then
616banned_players[player_name]=nil
617player.kicked=false
618player.banned=false
619end
620end
621function eventNewGame()
622for player_name in pairs(banned_players)do
623if tfm.get.room.playerList[player_name]then
624ApplyBanEffects(player_name)
625end
626end
627for player_name in pairs(shadow_banned_players)do
628if tfm.get.room.playerList[player_name]then
629if not banned_players[player_name]then
630pass_next_event_player_died=true
631eventPlayerDied(player_name)
632end
633end
634end
635end
636function eventPlayerDied(player_name)
637local player=player_list[player_name]
638if(player.shadow_banned and ban.shadowban_simulate_death)or player.banned then
639if pass_next_event_player_died then
640pass_next_event_player_died=false
641return
642end
643return false
644end
645if ban.shadowban_simulate_death then
646for player_name in pairs(shadow_banned_players)do
647if tfm.get.room.playerList[player_name]then
648tfm.get.room.playerList[player_name].isDead=true
649end
650end
651end
652end
653function eventPlayerRespawn(player_name)
654if banned_players[player_name]then
655ApplyBanEffects(player_name)
656elseif ban.shadowban_simulate_death and shadow_banned_players[player_name]then
657tfm.exec.killPlayer(player_name)
658end
659end
660function eventChatCommand(player_name,message)
661if banned_players[player_name]then
662return false
663end
664end
665function eventPlayerWon(player_name)
666if player_list[player_name].shadow_banned and ban.shadowban_abort_winning then
667local player=player_list[player_name]
668player.won=false
669tfm.exec.setPlayerScore(player_name,player.shadow_ban_score,false)
670tfm.get.room.playerList[player_name].score=player.shadow_ban_score
671return false
672end
673end
674function eventPlayerGetCheese(player_name)
675if player_list[player_name].shadow_banned then
676return false
677end
678end
679function eventPlayerBonusGrabbed(player_name)
680if shadow_banned_players[player_name]then
681return false
682end
683end
684local function ChatCommandBanlist(user)
685tfm.exec.chatMessage("<r><b>SCRIPT-BANNED PLAYERS:</b></r>",user)
686for player_name,player in pairs(player_list)do
687if player.kicked then
688tfm.exec.chatMessage(string.format("<j>%s KICKED:<j> %s",player_name,player.ban_reason),user)
689elseif player.banned then
690tfm.exec.chatMessage(string.format("<r>%s BANNED:<r> %s",player_name,player.ban_reason),user)
691elseif player.shadow_banned then
692tfm.exec.chatMessage(string.format("<vi>%s SHADOW BANNED:<vi> %s",player_name,player.ban_reason),user)
693end
694end
695return true
696end
697command_list["banlist"]={perms="admins",func=ChatCommandBanlist,desc="See the bans list.",argc_min=0,argc_max=0,arg_types={}}
698help_pages[__MODULE_NAME__].commands["banlist"]=command_list["banlist"]
699return ban
700end
701pshy.modules["pshy.perms"].load = function()
702local __MODULE_NAME__ = "pshy.perms"
703local command_list=pshy.require("pshy.commands.list")
704pshy.require("pshy.events")
705local help_pages=pshy.require("pshy.help.pages")
706local room=pshy.require("pshy.room")
707local perms={}
708help_pages[__MODULE_NAME__]={title="Permissions",text="Handles permissions.\n",commands={}}
709perms.admins={}
710perms.admins[room.loader]=0
711perms.auto_admin_admins=true
712perms.auto_admin_moderators=true
713perms.auto_admin_funcorps=true
714perms.auto_admin_authors=false
715perms.authors={}
716perms.authors["Pshy#3752"]=true
717perms.approved_mappers={
718["#Module#0000"]=true;
719["Mattseba#0000"]=true;
720["Nnaaaz#0000"]=true;
721}
722perms.perms={}
723perms.perms.everyone={}perms.perms.cheats={}perms.perms.admins={}
724perms.admin_instructions={}
725perms.cheats_enabled=false
726local admin_add_count=1
727local admins_added={}local admins=perms.admins
728local authors=perms.authors
729local perms_map=perms.perms
730local perms_admins=perms.perms.admins
731local perms_cheats=perms.perms.cheats
732local perms_everyone=perms.perms.everyone
733local approved_mappers=perms.approved_mappers
734function perms.HavePerm(player_name,perm)
735assert(type(perm)=="string","permission must be a string")
736if perms_everyone[perm]then
737return true
738elseif perms.perms_cheats_enabled and perms_cheats[perm]then
739return true
740elseif admins[player_name]and(perms_admins[perm]or perms_cheats[perm])then
741return true
742elseif perms_map[player_name]then
743return true
744elseif player_name==room.loader then
745return true
746end
747return false
748end
749function perms.IsTrustedMapper(map_author)
750if admins[map_author]or authors[map_author]or approved_mappers[map_author]then
751return true
752end
753return false
754end
755function perms.IsTrustedMap()
756return(not tfm.get.room.xmlMapInfo)or(tfm.get.room.xmlMapInfo.permCode~=22)or perms.IsTrustedMapper(tfm.get.room.xmlMapInfo.author)
757end
758local function ShowAdminMOTDTo(player_name)
759for i,instruction in ipairs(perms.admin_instructions)do
760tfm.exec.chatMessage("<r>[Perms]</r> <fc>"..instruction.."</fc>",new_admin)
761end
762return#perms.admin_instructions>0
763end
764local function AddAdmin(new_admin,reason,by)
765if admins[new_admin]then
766return false,"This user is already admin!"
767end
768admins[new_admin]=admin_add_count
769admin_add_count=admin_add_count+1
770if by then
771admins_added[by]=admins_added[by]or{}
772table.insert(admins_added[by],new_admin)
773end
774for an_admin,void in pairs(admins)do
775tfm.exec.chatMessage(string.format("<r>[Perms]</r> %s added to room admins%s.",new_admin,reason and(" ("..reason..")")or""),an_admin)
776end
777ShowAdminMOTDTo(new_admin)
778return true
779end
780local function RemoveAdmin(old_admin,reason,by)
781if not admins[old_admin]then
782return false,"This user is not a room admin."
783end
784if by then
785if(admins[by]~=true and admins[old_admin]~=true)and(admins[old_admin]<admins[by])then
786return false,"Cannot remove an older room admin!"
787end
788end
789admins[old_admin]=nil
790for admin_name,void in pairs(admins)do
791tfm.exec.chatMessage(string.format("<r>[Perms]</r> %s removed from room admins%s.",old_admin,reason and(" ("..reason..")")or""),an_admin)
792end
793if admins_added[old_admin]then
794for _,another_old_admin in ipairs(admins_added[old_admin])do
795RemoveAdmin(another_old_admin,"recursive removal",by)
796end
797end
798return true
799end
800local function CanAutoAdmin(player_name)
801local player_id=tfm.get.room.playerList[player_name].id
802if admins[player_name]then
803return false,"Already Admin"
804elseif player_name==perms.loader then
805return true,"Script Loader"
806elseif perms.perms_auto_admin_admins and string.sub(player_name,-5)=="#0001"then
807return true,"Admin <3"
808elseif perms.perms_auto_admin_moderators and string.sub(player_name,-5)=="#0010"then
809return true,"Moderator"
810elseif perms.perms_auto_admin_funcorps and tfm.get.room.playerList[player_name].isFunCorp then
811return true,"FunCorp"
812elseif(perms.perms_auto_admin_authors or room.is_private or room.is_tribehouse)and perms.authors[player_name]then
813return true,"Author"
814else
815return false,"Not Allowed"
816end
817end
818local function TouchPlayer(player_name)
819local can_admin,reason=CanAutoAdmin(player_name)
820if can_admin then
821tfm.exec.chatMessage("<r>[Perms]</r> <j>You may join room admins ("..reason..").</j>",player_name)
822ShowAdminMOTDTo(player_name)
823tfm.exec.chatMessage("<r>[Perms]</r> <j>To become a room admin, use `<fc>!adminme</fc>`</j>",player_name)
824print(string.format("<r>[Perms]</r> Current settings are allowing %s to join room admins (%s).",player_name,reason))
825end
826end
827function eventNewPlayer(player_name)
828TouchPlayer(player_name)
829end
830local function ChatCommandAdmin(user,new_admin_name)
831return AddAdmin(new_admin_name,"by "..user,user)
832end
833command_list["admin"]={perms="admins",func=ChatCommandAdmin,desc="add a room admin",argc_min=1,argc_max=1,arg_types={"string"},arg_names={"Newadmin#0000"}}
834help_pages[__MODULE_NAME__].commands["admin"]=command_list["admin"]
835local function ChatCommandUnadmin(user,admin_name)
836return RemoveAdmin(admin_name,"by "..user,user)
837end
838command_list["unadmin"]={perms="admins",func=ChatCommandUnadmin,desc="remove a room admin",argc_min=1,argc_max=1,arg_types={"string"},arg_names={"Oldadmin#0000"}}
839help_pages[__MODULE_NAME__].commands["unadmin"]=command_list["unadmin"]
840local function ChatCommandAdminme(user)
841local allowed,reason=CanAutoAdmin(user)
842if allowed then
843AddAdmin(user,reason)
844return true
845else
846return false,reason
847end
848end
849command_list["adminme"]={perms="everyone",func=ChatCommandAdminme,desc="join room admins if allowed",argc_min=0,argc_max=0}
850help_pages[__MODULE_NAME__].commands["adminme"]=command_list["adminme"]
851local function ChatCommandSetadminmotd(user,instruction)
852perms.admin_instructions={}
853if instruction then
854perms.admin_instructions[1]=instruction
855return true,"Admin motd set to `"..instruction.."`"
856end
857return true,"Admin motd removed"
858end
859command_list["setadminmotd"]={perms="admins",func=ChatCommandSetadminmotd,desc="message to display to new admins",argc_min=0,argc_max=1,arg_types={"string"}}
860help_pages[__MODULE_NAME__].commands["setadminmotd"]=command_list["setadminmotd"]
861local function ChatCommandAdminmotd(user)
862if not ShowAdminMOTDTo(new_admin)then
863return false,"No admin motd, set one with `!setadminmotd`."
864end
865return true
866end
867command_list["adminmotd"]={perms="admins",func=ChatCommandAdminmotd,desc="read the room admin motd",argc_min=0,argc_max=0}
868help_pages[__MODULE_NAME__].commands["adminmotd"]=command_list["adminmotd"]
869local function ChatCommandAdmins(user)
870local strlist=""
871for an_admin,is_admin in pairs(admins)do
872if is_admin then
873if#strlist>0 then
874strlist=strlist..", "
875end
876strlist=strlist..an_admin
877end
878end
879tfm.exec.chatMessage("<r>[Perms]</r> Script Loader: "..tostring(room.loader),user)
880tfm.exec.chatMessage("<r>[Perms]</r> Room admins: "..strlist..".",user)
881if perms.auto_admin_authors then
882tfm.exec.chatMessage("<r>[Perms]</r> Major authors can join room admins.",user)
883end
884if perms.auto_admin_funcorps then
885tfm.exec.chatMessage("<r>[Perms]</r> Funcorps can join room admins.",user)
886end
887if perms.auto_admin_moderators then
888tfm.exec.chatMessage("<r>[Perms]</r> Moderators can join room admins.",user)
889end
890if perms.auto_admin_moderators or perms.auto_admin_funcorps or perms.auto_admin_authors then
891tfm.exec.chatMessage("<r>[Perms]</r> Disable in settings or with `!setperm everyone adminme no`.",user)
892end
893return true
894end
895command_list["admins"]={perms="everyone",func=ChatCommandAdmins,desc="see a list of room admins",argc_min=0,argc_max=0}
896help_pages[__MODULE_NAME__].commands["admins"]=command_list["admins"]
897local function ChatCommandAuthors(user)
898local strlist=""
899for author_name,is_major in pairs(perms.authors)do
900if#strlist>0 then
901strlist=strlist..", "
902end
903if is_major then
904strlist=strlist.."<fc>"..author_name.."</fc>"
905else
906strlist=strlist..author_name
907end
908end
909tfm.exec.chatMessage("<r>[Perms]</r> Authors: "..strlist..".",user)
910return true
911end
912command_list["authors"]={perms="everyone",func=ChatCommandAuthors,desc="see a list of authors",argc_min=0,argc_max=0}
913help_pages[__MODULE_NAME__].commands["authors"]=command_list["authors"]
914local function ChatCommandTrust(user,target_player)
915approved_mappers[target_player]=true
916for admin_name,void in pairs(admins)do
917tfm.exec.chatMessage(string.format("<r>[Perms]</r> %s's content is now trusted (by %s).",target_player,user),admin_name)
918end
919return true
920end
921command_list["trust"]={perms="admins",func=ChatCommandTrust,desc="trust a player's maps (enable advanced features)",argc_min=1,argc_max=1,arg_types={'string'},arg_names={'Player#0000'}}
922help_pages[__MODULE_NAME__].commands["trust"]=command_list["trust"]
923local function ChatCommandEnablecheats(user,cheats_enabled)
924perms.perms_cheats_enabled=cheats_enabled
925if cheats_enabled then
926return true,"cheat commands enabled for everyone"
927else
928return true,"cheat commands enabled for admins only"
929end
930end
931command_list["enablecheats"]={perms="admins",func=ChatCommandEnablecheats,desc="enable cheats commands for everyone",argc_min=1,argc_max=1,arg_types={'boolean'}}
932help_pages[__MODULE_NAME__].commands["enablecheats"]=command_list["enablecheats"]
933local function ChatCommandSetcommandperms(user,target,perm,value)
934if not perms.HavePerm(user,perm)then
935return false,"you cannot give permissions for a command you do not have permissions for"
936end
937perms_map[target]=perms_map[target]or{}
938perms_map[target][perm]=value
939local rst=string.format("permission %s %s %s by %s",perm,(value and"given to"or"removed from"),target,user)
940for an_admin,void in pairs(admins)do
941tfm.exec.chatMessage("<r>[Perms]</r> "..rst,an_admin)
942end
943return true,rst
944end
945command_list["setperm"]={perms="admins",func=ChatCommandSetcommandperms,desc="set permissions for a command",argc_min=3,argc_max=3,arg_types={'string','string','bool'},arg_names={"Player#0000|admins|cheats|everyone","!command","yes|no"}}
946help_pages[__MODULE_NAME__].commands["setperm"]=command_list["setperm"]
947local function SetThirdpartyAdminSet(parent_table,admin_table_name)
948local admin_table=parent_table[admin_table_name]
949if not admin_table or type(admin_table)~="table"then
950return false
951end
952if admin_table[1]then
953return false
954end
955local has_player_keys=false
956for key,value in pairs(admin_table)do
957if string.match(key,"#....$")and value==true then
958has_player_keys=true
959end
960break
961end
962if has_player_keys then
963parent_table[admin_table_name]=perms.admins
964return true
965end
966return false
967end
968local function InsertIntoThirdpartyAdminList(admin_table,admin)
969if admin_table[1]and type(admin_table[1])=="string"then
970table.insert(admin_table,admin)
971return true
972end
973return false
974end
975function eventInit()
976assert(admins==perms.admins)
977assert(perms_map==perms.perms)
978assert(perms_admins==perms.perms.admins)
979assert(perms_cheats==perms.perms.cheats)
980assert(perms_everyone==perms.perms.everyone)
981for player_name in pairs(tfm.get.room.playerList)do
982TouchPlayer(player_name)
983end
984if perms.auto_admin_authors then
985print("<r>[Perms]</r> Authors can join room admins (`see !admins`).")
986end
987if _G.admin and type(_G.admin)=="string"then
988_G.admin=room.loader
989end
990if _G.Admin and type(_G.Admin)=="string"then
991_G.Admin=room.loader
992end
993local need_add_loader_admin=false
994SetThirdpartyAdminSet(_G,"admin")
995SetThirdpartyAdminSet(_G,"admins")
996if _G.game then
997SetThirdpartyAdminSet(_G.game,"admins")
998end
999if _G.admins and type(_G.admins)=="table"then
1000InsertIntoThirdpartyAdminList(_G.admins,room.loader)
1001end
1002if _G.game and _G.game.admins and type(_G.game.admins)=="table"then
1003InsertIntoThirdpartyAdminList(_G.game.admins,room.loader)
1004end
1005end
1006return perms
1007end
1008pshy.modules["pshy.anticheats.adminchat"].load = function()
1009local __MODULE_NAME__ = "pshy.anticheats.adminchat"
1010local command_list=pshy.require("pshy.commands.list")
1011pshy.require("pshy.events")
1012local help_pages=pshy.require("pshy.help.pages")
1013local perms=pshy.require("pshy.perms")
1014local adminchat={}
1015help_pages[__MODULE_NAME__]={back="pshy",restricted=true,title="Admin Chat",text="Chat for room admins",commands={}}
1016help_pages["pshy"].subpages[__MODULE_NAME__]=help_pages[__MODULE_NAME__]
1017local displayed_admin_disclaimers={}
1018function adminchat.Message(origin,message)
1019if not message then
1020message=origin
1021origin="SCRIPT"
1022end
1023for admin in pairs(perms.admins)do
1024if origin then
1025tfm.exec.chatMessage("<r>⚔ ["..origin.."] <o>"..message,admin)
1026else
1027tfm.exec.chatMessage("<r>⚔ <o>"..message,admin)
1028end
1029end
1030end
1031local function ChatCommandAdminchat(user,message)
1032displayed_admin_disclaimers[user]=true
1033for admin in pairs(perms.admins)do
1034tfm.exec.chatMessage("<r>⚔ ["..user.."] <ch2>"..message,admin)
1035if not displayed_admin_disclaimers[admin]==true then
1036tfm.exec.chatMessage("<r>⚔ <o>Use `<r>!ac <message></r>` to send a message to other room admins.",admin)
1037displayed_admin_disclaimers[admin]=true
1038end
1039end
1040return true
1041end
1042command_list["adminchat"]={aliases={"ac"},perms="admins",func=ChatCommandAdminchat,desc="send a message to room admins",argc_min=1,argc_max=1,arg_types={"string"},arg_names={"room-admin-only message"}}
1043help_pages[__MODULE_NAME__].commands["adminchat"]=command_list["adminchat"]
1044return adminchat
1045end
1046pshy.modules["pshy.anticheats.loadersync"].load = function()
1047local __MODULE_NAME__ = "pshy.anticheats.loadersync"
1048local adminchat=pshy.require("pshy.anticheats.adminchat")
1049local command_list=pshy.require("pshy.commands.list")
1050pshy.require("pshy.events")
1051local help_pages=pshy.require("pshy.help.pages")
1052pshy.require("pshy.utils.print")
1053local room=pshy.require("pshy.room")
1054local perms=pshy.require("pshy.perms")
1055local loadersync={}
1056help_pages[__MODULE_NAME__]={back="pshy",restricted=true,text="Enforce the sync to prevent some exploits.\n",commands={}}
1057help_pages["pshy"].subpages[__MODULE_NAME__]=help_pages[__MODULE_NAME__]
1058loadersync.enabled=true
1059local wished_sync=room.loader local forced_sync=nil local is_get_player_sync_available=(tfm.exec.getPlayerSync()~=nil)
1060function eventNewGame()
1061if loadersync.enabled then
1062if forced_sync and tfm.exec.getPlayerSync()~=forced_sync then
1063adminchat.Message("loadersync",string.format("Sync changed from %s to %s, restoring the previous one!",forced_sync or"nil",tfm.exec.getPlayerSync()or"nil"))
1064tfm.exec.setPlayerSync(forced_sync)
1065end
1066end
1067end
1068function eventNewPlayer(player_name)
1069if loadersync.enabled then
1070if player_name==wished_sync then
1071tfm.exec.setPlayerSync(player_name)
1072forced_sync=player_name
1073adminchat.Message("loadersync",string.format("%s returned and set as sync!",player_name))
1074end
1075end
1076end
1077function eventPlayerLeft(player_name)
1078if loadersync.enabled then
1079if forced_sync==player_name then
1080for player_name in pairs(perms.admins)do
1081if tfm.get.room.playerList[player_name]then
1082tfm.exec.setPlayerSync(player_name)
1083forced_sync=player_name
1084adminchat.Message("loadersync",string.format("Sync left, replacing it with %s!",player_name))
1085return
1086end
1087end
1088for player_name in pairs(tfm.get.room.playerList)do
1089tfm.exec.setPlayerSync(player_name)
1090forced_sync=player_name
1091print_warn(__MODULE_NAME__..": Sync left, replacing it with %s!",player_name)
1092return
1093end
1094end
1095end
1096end
1097function eventInit()
1098if not is_get_player_sync_available then
1099loadersync.enabled=false
1100else
1101tfm.exec.setPlayerSync(wished_sync)
1102forced_sync=wished_sync
1103end
1104end
1105local function ChatCommandLoadersync(user,enabled,sync_player)
1106loadersync.enabled=enabled
1107if sync_player then
1108wished_sync=sync_player
1109tfm.exec.setPlayerSync(sync_player)
1110forced_sync=sync_player
1111end
1112adminchat.Message("loadersync",enabled and string.format("Now enforcing the sync to be %s.",forced_sync)or"No longer enforcing the sync.")
1113return true
1114end
1115command_list["loadersync"]={perms="admins",func=ChatCommandLoadersync,desc="Enable or disable the enforcing of the sync.",argc_min=1,argc_max=2,arg_types={"boolean","player"},arg_names={"on/off","sync_player"}}
1116help_pages[__MODULE_NAME__].commands["loadersync"]=command_list["loadersync"]
1117return loadersync
1118end
1119pshy.modules["pshy.bases.loopmore"].load = function()
1120pshy.require("pshy.events")
1121local loopmore={}
1122loopmore.call_standard_loop=false loopmore.down_keys={0,1,2,3}loopmore.up_keys={0,2}
1123local interval=nil local tfm_timers_interval=nil local map_start_os_time=nil local map_end_os_time=nil local last_loopmore_os_time=os.time()local anticipated_skips=0 local timers={}
1124local function RunLoopMore()
1125if not map_start_os_time or not map_end_os_time then
1126return
1127end
1128local os_time=os.time()
1129eventLoopMore(os_time-map_start_os_time,map_end_os_time-os_time)
1130last_loopmore_os_time=os_time
1131end
1132local function TimerCallback(tfmid,id)
1133local timer=timers[id]
1134assert(timer~=nil,"timer #"..tostring(id).."/"..tostring(#timers)..": "..tostring(os.time()%10000))
1135RunLoopMore()
1136end
1137local function InitTimerCallback(tid,i_timer)
1138local timer=timers[i_timer]
1139assert(timer.id~=nil)
1140system.removeTimer(timer.id)
1141timer.id=system.newTimer(TimerCallback,tfm_timers_interval,true,i_timer)
1142end
1143function loopmore.SetInterval(interval)
1144assert(type(interval)=="number")
1145assert(interval>=50)
1146assert(interval<=500)
1147interval=interval
1148for i_timer,timer in ipairs(timers)do
1149system.removeTimer(timer.id)
1150end
1151timers={}
1152local tfm_interval=interval
1153while tfm_interval<500 do
1154tfm_interval=tfm_interval+interval
1155end
1156tfm_timers_interval=tfm_interval
1157local timer_count=tfm_interval/interval
1158assert(timer_count>=1)
1159assert(timer_count<=10)
1160for i_timer=1,timer_count do
1161timers[i_timer]={}
1162local timer=timers[i_timer]
1163timer.sync_time=interval*(i_timer-1)
1164timer.id=system.newTimer(InitTimerCallback,tfm_timers_interval+timer.sync_time,false,i_timer)
1165timer.i_timer=i_timer
1166end
1167end
1168function eventLoopMore(time,time_remaining)
1169if loopmore.call_standard_loop and eventLoop then
1170eventLoop(time,time_remaining)
1171end
1172end
1173function eventNewGame()
1174map_start_os_time=os.time()
1175map_end_os_time=nil
1176anticipated_skips=0
1177end
1178function eventLoop(time,time_remaining)
1179local os_time=os.time()
1180map_start_os_time=os_time-time
1181map_end_os_time=os_time+time_remaining
1182end
1183function loopmore.setGameTime(time_remaining,init)
1184local os_time=os.time()
1185if init then
1186map_end_os_time=os_time+time_remaining
1187elseif map_end_os_time and time_remaining<(map_end_os_time-os_time)then
1188map_end_os_time=os_time+time_remaining
1189end
1190loopmore.original_setGameTime(time_remaining,init)
1191end
1192loopmore.original_setGameTime=tfm.exec.setGameTime
1193tfm.exec.setGameTime=loopmore.setGameTime
1194loopmore.SetInterval(250)
1195return loopmore
1196end
1197pshy.modules["pshy.utils.strings"].load = function()
1198local utils_strings={}
1199function utils_strings.Split(str,separator,max)
1200assert(type(str)=="string")
1201separator=separator or"%s"
1202max=max or-1
1203local remlen=#str
1204local parts={}
1205for part in string.gmatch(str,"([^"..separator.."]+)")do
1206if max==1 and remlen>=0 then
1207table.insert(parts,string.sub(str,-remlen))
1208return parts
1209end
1210table.insert(parts,part)
1211remlen=remlen-#part-1
1212max=max-1
1213end
1214return parts
1215end
1216function utils_strings.Split2(str,separator)
1217assert(type(str)=="string")
1218separator=separator or'%s'
1219local fields={}
1220for field,s in string.gmatch(str,"([^"..separator.."]*)("..separator.."?)")do
1221table.insert(fields,field)
1222if s==""then return fields
1223end
1224end
1225return fields
1226end
1227function utils_strings.LenSplit(str,len)
1228local to_return={}
1229while#str>0 do
1230local part=string.sub(str,1,len)
1231table.insert(to_return,part)
1232str=string.sub(str,len+1,#str)
1233end
1234return to_return
1235end
1236return utils_strings
1237end
1238pshy.modules["pshy.ui.dialog"].load = function()
1239pshy.require("pshy.events")
1240pshy.require("pshy.utils.print")
1241local ids=pshy.require("pshy.utils.ids")
1242local dialog={}
1243local dialog_popup_id=ids.AllocPopupId()
1244local dialog_color_picker_id=ids.AllocColorPickerId()
1245local dialog_x=300
1246local dialog_y=100
1247local dialog_players_callbacks={}
1248function dialog.AskForYesOrNo(player_name,text,callback)
1249dialog_players_callbacks[player_name]=callback
1250ui.addPopup(dialog_popup_id,1,text,player_name,dialog_x,dialog_y,nil,true)
1251end
1252function dialog.AskForText(player_name,text,callback)
1253dialog_players_callbacks[player_name]=callback
1254ui.addPopup(dialog_popup_id,2,text,player_name,dialog_x,dialog_y,nil,true)
1255end
1256function dialog.AskForColor(player_name,title,callback,default_color)
1257dialog_players_callbacks[player_name]=callback
1258ui.showColorPicker(dialog_color_picker_id,player_name,default_color or 0xffffff,title)
1259end
1260local function Answered(player_name,answer)
1261local callback=dialog_players_callbacks[player_name]
1262if callback then
1263dialog_players_callbacks[player_name]=nil
1264callback(player_name,answer)
1265else
1266print_warn("pshy_dialog: no callback for %s: %s",player_name,tostring(answer))
1267end
1268end
1269function eventPopupAnswer(popup_id,player_name,answer)
1270if popup_id==dialog_popup_id then
1271Answered(player_name,answer)
1272end
1273end
1274function eventColorPicked(popup_id,player_name,color)
1275if popup_id==dialog_color_picker_id then
1276Answered(player_name,color)
1277end
1278end
1279return dialog
1280end
1281pshy.modules["pshy.enums.colors"].load = function()
1282
1283local colors={
1284red=0xff0000;
1285lime=0x00ff00;
1286blue=0x0000ff;
1287yellow=0xffff00;
1288magenta=0xff00ff;
1289cyan=0x00ffff;
1290transparent=0x000000;black=0x010101;grey=0x808080;
1291gray=0x808080;
1292silver=0xc0c0c0;
1293white=0xffffff;
1294maroon=0x800000;
1295green=0x008000;
1296navy=0x000080;
1297olive=0x808000;
1298purple=0x800080;
1299teal=0x008080;
1300aquamarine=0x7fffd4;
1301brown=0xa52a2a;
1302bronze=0x967444;
1303coral=0xff7f50;
1304darkgreen=0x006400;
1305gold=0xffd700;
1306indigo=0x4b0082;
1307lavender=0xb2a4d4;
1308orange=0xffa500;
1309pink=0xffc0cb;
1310tan=0xd2b48c;
1311turquoise=0x40e0d0;
1312violet=0x9b26b6;
1313funcorp=0xff8000;
1314}
1315return colors
1316end
1317pshy.modules["pshy.utils.lua"].load = function()
1318local utils_strings=pshy.require("pshy.utils.strings")
1319local utils_lua={}
1320function utils_lua.Get(path,sep)
1321assert(type(path)=="string",debug.traceback())
1322sep=sep or"."
1323local parts=utils_strings.Split(path,sep)
1324local cur=_G
1325for index,value in pairs(parts)do
1326possible_int=tonumber(value)
1327value=possible_int or value
1328cur=cur[value]
1329if cur==nil then
1330return nil
1331end
1332end
1333return cur
1334end
1335function utils_lua.Set(obj_path,value,sep)
1336assert(type(obj_path)=="string",debug.traceback())
1337sep=sep or"."
1338local parts=utils_strings.Split(obj_path,sep)
1339local cur=_G
1340for i_part,part in pairs(parts)do
1341possible_int=tonumber(part)
1342part=possible_int or part
1343if i_part==#parts then
1344cur[part]=value
1345return cur[part]
1346end
1347cur[part]=cur[part]or{}
1348if type(cur)~="table"then
1349return nil
1350end
1351cur=cur[part]
1352end
1353error("unreachable code")
1354end
1355return utils_lua
1356end
1357pshy.modules["pshy.utils.tfm"].load = function()
1358local utils_lua=pshy.require("pshy.utils.lua")
1359local utils_strings=pshy.require("pshy.utils.strings")
1360local utils_tfm={}
1361function utils_tfm.GetPlayerNick(player_name)
1362return string.match(player_name,"([^#]*)")
1363end
1364function utils_tfm.FindPlayerName(partial_name)
1365local player_list=tfm.get.room.playerList
1366if player_list[partial_name]then
1367return partial_name
1368else
1369local real_name
1370for player_name in pairs(player_list)do
1371if string.sub(player_name,1,#partial_name)==partial_name then
1372if real_name then
1373return nil,"several players found"end
1374real_name=player_name
1375end
1376end
1377if not real_name then
1378return nil,"player not found"
1379end
1380return real_name end
1381end
1382function utils_tfm.FindPlayerNameOrError(partial_name)
1383local real_name,reason=utils_tfm.FindPlayerName(partial_name)
1384if not real_name then
1385error(reason)
1386end
1387return real_name
1388end
1389function utils_tfm.EnumGet(index)
1390assert(type(index)=="string")
1391local value
1392for enum_name,enum in pairs(tfm.enum)do
1393value=enum[index]
1394if value then
1395return value
1396end
1397end
1398return nil
1399end
1400function utils_tfm.CountPlayersAlive()
1401local count=0
1402for player_name,player in pairs(tfm.get.room.playerList)do
1403if not player.isDead then
1404count=count+1
1405end
1406end
1407return count
1408end
1409return utils_tfm
1410end
1411pshy.modules["pshy.utils.types"].load = function()
1412local colors=pshy.require("pshy.enums.colors")
1413local utils_lua=pshy.require("pshy.utils.lua")
1414local utils_tfm=pshy.require("pshy.utils.tfm")
1415local utils_types={}
1416function utils_types.ToBoolean(s)
1417if s=="true"then
1418return true
1419end
1420if s=="false"then
1421return false
1422end
1423return nil
1424end
1425function utils_types.ToPermissiveBoolean(s)
1426if s=="true"or s=="on"or s=="yes"then
1427return true
1428end
1429if s=="false"or s=="off"or s=="no"then
1430return false
1431end
1432return nil
1433end
1434local ToPermissiveBoolean=utils_types.ToPermissiveBoolean
1435function utils_types.ToNumberHex(s)
1436if string.sub(s,1,1)=='#'then
1437s=string.sub(s,2,#s)
1438end
1439return tonumber(s,16)
1440end
1441local ToNumberHex=utils_types.ToNumberHex
1442function utils_types.ToColor(s)
1443if colors[s]then
1444return colors[s]
1445end
1446return ToNumberHex(s)
1447end
1448local ToColor=utils_types.ToColor
1449utils_types.converters={}
1450utils_types.converters["number"]=tonumber
1451utils_types.converters["string"]=tostring
1452utils_types.converters["bool"]=utils_types.ToPermissiveBoolean
1453utils_types.converters["boolean"]=utils_types.ToPermissiveBoolean
1454utils_types.converters["player"]=utils_tfm.FindPlayerName
1455utils_types.converters["hexnumber"]=utils_types.ToNumberHex
1456utils_types.converters["color"]=utils_types.ToColor
1457utils_types.converters["lua"]=utils_lua.Get
1458utils_types.converters["lua/"]=function(s)return utils_lua.Get(s,"/")end
1459local converters=utils_types.converters
1460function utils_types.ToType(s,t)
1461assert(type(s)=="string","wrong argument type")
1462assert(type(t)=="string","wrong argument type")
1463if t=="string"then
1464return s
1465end
1466if t=="player"then
1467return utils_tfm.FindPlayerName(s)
1468end
1469if s=="nil"then
1470return nil
1471end
1472if t=="bool"or t=="boolean"then
1473return ToPermissiveBoolean(s)
1474end
1475if t=="number"then
1476return tonumber(s)
1477end
1478if t=="color"then
1479if colors[s]then
1480return colors[s]
1481end
1482t="hexnumber"
1483end
1484if t=="hexnumber"then
1485if string.sub(s,1,1)=='#'then
1486s=string.sub(s,2,#s)
1487end
1488return tonumber(s,16)
1489end
1490local enum=utils_lua.Get(t)
1491if type(enum)=="table"then
1492return enum[s]
1493end
1494error("type not supported")
1495end
1496function utils_types.AutoType(s)
1497assert(type(s)=="string","wrong argument type")
1498local rst
1499if s=="nil"then
1500return nil
1501end
1502if s=="true"then
1503return true
1504end
1505if s=="false"then
1506return false
1507end
1508rst=tonumber(s,10)
1509if rst then
1510return rst
1511end
1512if s=="{}"then
1513return{}
1514end
1515rst=utils_tfm.EnumGet(s)
1516if rst then
1517return rst
1518end
1519rst=utils_lua.Get(s)
1520if rst then
1521return rst
1522end
1523if string.sub(s,1,1)=='#'then
1524rst=tonumber(string.sub(s,2,#s),16)
1525if rst then
1526return rst
1527end
1528end
1529return s
1530end
1531local AutoType=utils_types.AutoType
1532function utils_types.ToTypeFromPrefix(s)
1533assert(type(s)=="string","wrong argument type")
1534local i_colon=s:find(":",1,true)
1535if i_colon and i_colon>1 and i_colon<16 then
1536local type_str=s:sub(1,i_colon-1)
1537if converters[type_str]then
1538return converters[type_str](s:sub(i_colon+1))
1539end
1540end
1541if#s>1 and s:sub(1,1)=="\""and s:sub(-1,-1)=="\""then
1542return s:sub(2,-2)
1543end
1544return AutoType(s)
1545end
1546return utils_types
1547end
1548pshy.modules["pshy.commands"].load = function()
1549pshy.require("pshy.events")
1550local dialog=pshy.require("pshy.ui.dialog")
1551pshy.require("pshy.utils.print")
1552local utils_strings=pshy.require("pshy.utils.strings")
1553local utils_types=pshy.require("pshy.utils.types")
1554local perms=pshy.require("pshy.perms")
1555local command_list=pshy.require("pshy.commands.list")
1556local commands={}
1557commands.require_prefix=false commands.always_enable_ui=true
1558local ignore_next_command=false
1559commands.names_ordered={}
1560commands.aliases=commands.aliases or{}
1561local function ResolveAlias(alias_name)
1562while not command_list[alias_name]and commands.aliases[alias_name]do
1563alias_name=commands.aliases[alias_name]
1564end
1565return alias_name
1566end
1567local function GetCommand(alias_name)
1568return(command_list[ResolveAlias(alias_name)])
1569end
1570commands.GetCommand=GetCommand
1571function commands.GetPermColorMarkups(perm)
1572if perms.perms.everyone[perm]then
1573return"<v>","</v>"
1574elseif perms.perms.cheats[perm]then
1575return"<j>","</j>"
1576elseif perms.perms.admins[perm]then
1577return"<r>","</r>"
1578else
1579return"<vi>","</vi>"
1580end
1581end
1582function commands.GetUsage(cmd_name)
1583local text="!"..cmd_name
1584local real_command=GetCommand(cmd_name)
1585if not real_command then
1586return"This command does not exist or is unavailable."
1587end
1588if real_command.aliases then
1589text=text.."("
1590local first_alias=true
1591for i_alias,alias in ipairs(real_command.aliases)do
1592if not first_alias then
1593text=text..","
1594end
1595first_alias=false
1596text=text..alias
1597end
1598text=text..")"
1599end
1600local min=real_command.argc_min or 0
1601local max=real_command.argc_max or min
1602if max>0 then
1603for i=1,max do
1604text=text.." "..((i<=min)and"<"or"[")
1605if real_command.arg_names and i<=#real_command.arg_names then
1606text=text..real_command.arg_names[i]
1607elseif real_command.arg_types and i<=#real_command.arg_types then
1608if type(real_command.arg_types[i])=="string"then
1609text=text..real_command.arg_types[i]
1610else
1611text=text..type(real_command.arg_types[i])
1612end
1613else
1614text=text.."?"
1615end
1616text=text..((i<=min)and">"or"]")
1617end
1618end
1619if not real_command.argc_max then
1620text=text.." [...]"
1621end
1622return text
1623end
1624local function ConvertArgs(args,types)
1625local reason
1626local has_multiple_players=false
1627for index=1,#args do
1628if(not types)or index>#types or types[index]==nil then
1629args[index]=utils_types.ToTypeFromPrefix(args[index])
1630elseif type(types[index])=="function"then
1631args[index],reason=types[index](args[index])
1632if args[index]==nil then
1633return false,(reason or("wrong type for argument "..tostring(index)..", conversion function returned `nil`"))
1634end
1635elseif type(types[index])=="table"then
1636args[index]=types[index][args[index]]
1637if args[index]==nil then
1638return false,"wrong type for argument "..tostring(index)..", expected an enum value"
1639end
1640elseif types[index]=='player'and args[index]=='*'then
1641if has_multiple_players then
1642return false,"only a single '*' argument may represent all the players"
1643end
1644has_multiple_players=true
1645else
1646args[index],reason=utils_types.ToType(args[index],types[index])
1647if reason~=nil then
1648return false,reason
1649end
1650if args[index]==nil then
1651return false,"wrong type for argument "..tostring(index)..", expected "..types[index]
1652end
1653end
1654end
1655return true
1656end
1657local players_resumable_commands={}
1658local function AnsweredArg(user,answer)
1659local resumable_command=players_resumable_commands[user]
1660if not resumable_command then
1661print_warn("pshy_commands: no command to resume for %s",user)
1662return
1663end
1664local arg_type="string"
1665if resumable_command.command.arg_types then
1666arg_type=resumable_command.command.arg_types[#resumable_command.argv+1]or"string"
1667end
1668if arg_type=="color"and type(answer)=="number"then
1669answer=string.format("#%06x",answer)
1670end
1671table.insert(resumable_command.argv,tostring(answer))
1672local command=resumable_command.command
1673local argv=resumable_command.argv
1674players_resumable_commands[user]=nil
1675commands.RunCommandWithArgs(user,command,argv)
1676end
1677local function AskNextArg(user,command,argv)
1678local arg_type="string"
1679local arg_index=#argv+1
1680if command.arg_types then
1681arg_type=command.arg_types[#argv+1]or"string"
1682end
1683local arg_name=nil
1684if command.arg_names and command.arg_names[arg_index]then
1685arg_name=command.arg_names[arg_index]
1686end
1687local text
1688if arg_name then
1689text=string.format("<n><b>%s</b></n> (argument %d):",arg_name,arg_index)
1690else
1691text=string.format("<n><b>%s</b></n> (argument %d):",arg_type,arg_index)
1692end
1693players_resumable_commands[user]={command=command,argv=argv}
1694if arg_type=="bool"or arg_type=="boolean"then
1695dialog.AskForYesOrNo(user,text,AnsweredArg)
1696elseif arg_type=="color"then
1697dialog.AskForColor(user,(arg_type or arg_name or"anything"),AnsweredArg)
1698else
1699dialog.AskForText(user,text,AnsweredArg)
1700end
1701end
1702local function Answer(msg,player_name)
1703assert(player_name~=nil)
1704tfm.exec.chatMessage("<n> ↳ "..tostring(msg),player_name)
1705end
1706local function AnswerError(msg,player_name)
1707assert(player_name~=nil)
1708tfm.exec.chatMessage("<r> × "..tostring(msg),player_name)
1709end
1710function commands.Run(user,command_str)
1711assert(type(user)=="string")
1712assert(type(command_str)=="string")
1713if ignore_next_command then
1714ignore_next_command=false
1715return
1716end
1717if not perms.admins[user]then
1718print("<g>["..user.."] !"..command_str)
1719end
1720if string.sub(command_str,1,6)=="other."then
1721ignore_next_command=true
1722return eventChatCommand(user,string.sub(command_str,7))or false
1723end
1724local had_pshy_prefix=false
1725if string.sub(command_str,1,5)=="pshy."then
1726command_str=string.sub(command_str,6,#command_str)
1727had_pshy_prefix=true
1728elseif commands.require_prefix then
1729return
1730end
1731local command_alias_and_args_str=utils_strings.Split(command_str," ",2)
1732local command_alias=command_alias_and_args_str[1]
1733local args_str=command_alias_and_args_str[2]
1734local command=GetCommand(command_alias)
1735if not command then
1736if had_pshy_prefix then
1737AnswerError("Unknown pshy command.",user)
1738return nil
1739end
1740tfm.exec.chatMessage("Another module may handle this command.",user)
1741return nil
1742end
1743if not perms.HavePerm(user,"!"..command.name)then
1744AnswerError("You do not have permission to use this command.",user)
1745return false
1746end
1747local args=args_str and utils_strings.Split(args_str," ",command.argc_max or 16)or{}return commands.RunCommandWithArgs(user,command,args)
1748end
1749function commands.RunCommandWithArgs(user,command,argv)
1750if not perms.HavePerm(user,"!"..command.name)then
1751AnswerError("You do not longer have permission to use this command.",user)
1752return false
1753end
1754if command.argc_min and#argv<command.argc_min then
1755if command.ui or commands.always_enable_ui then
1756AskNextArg(user,command,argv)
1757return true
1758end
1759AnswerError("Usage: "..(command.usage or"(no usage, error)"),user)
1760return false
1761end
1762if command.argc_max and#argv>command.argc_max then
1763AnswerError("This command do not use arguments.",user)
1764return false
1765end
1766local multiple_players_index=nil
1767if command.arg_types then
1768for i_type,type in ipairs(command.arg_types)do
1769if type=="player"and argv[i_type]=='*'then
1770multiple_players_index=i_type
1771end
1772end
1773end
1774local rst,rtn=ConvertArgs(argv,command.arg_types)
1775if not rst then
1776AnswerError(tostring(rtn),user)
1777return not had_prefix
1778end
1779local pcallrst,rst,rtn
1780if multiple_players_index then
1781for player_name in pairs(tfm.get.room.playerList)do
1782argv[multiple_players_index]=player_name
1783if not command.no_user then
1784pcallrst,rst,rtn=pcall(command.func,user,table.unpack(argv))
1785else
1786pcallrst,rst,rtn=pcall(command.func,table.unpack(argv))
1787end
1788if pcallrst==false or rst==false then
1789break
1790end
1791end
1792else
1793if not command.no_user then
1794pcallrst,rst,rtn=pcall(command.func,user,table.unpack(argv))
1795else
1796pcallrst,rst,rtn=pcall(command.func,table.unpack(argv))
1797end
1798end
1799if pcallrst==false then
1800AnswerError(rst,user)
1801elseif rst==false then
1802AnswerError(rtn,user)
1803elseif rst==nil then
1804Answer("Command executed.",user)
1805elseif rst==true and rtn~=nil then
1806if type(rtn)=="string"then
1807Answer(rtn,user)
1808else
1809Answer(string.format("Command returned %s.",tostring(rtn)),user)
1810end
1811end
1812end
1813local function ChatCommandCommands(user,page_index)
1814page_index=page_index or 1
1815local commands_per_page=10
1816tfm.exec.chatMessage(string.format("<n>Commands (page %d/%d):</n>",page_index,math.ceil(#commands.names_ordered/commands_per_page)),user)
1817local i_command_first=((page_index-1)*commands_per_page)+1
1818local i_command_last=((page_index-1)*commands_per_page+10)
1819for i_command=i_command_first,i_command_last do
1820local command_name=commands.names_ordered[i_command]
1821if command_name then
1822local real_command=GetCommand(command_name)
1823local is_admin=perms.admins[user]
1824if not real_command.restricted or is_admin then
1825local usage=real_command.usage or"(no usage, error)"
1826local markup_1,markup_2=commands.GetPermColorMarkups("!"..command_name)
1827tfm.exec.chatMessage(string.format(" %s%s%s",markup_1,usage,markup_2),user)
1828end
1829else
1830break
1831end
1832end
1833return true
1834end
1835command_list["commands"]={aliases={"cmds"},perms="everyone",func=ChatCommandCommands,desc="list commands",argc_min=0,argc_max=1,arg_types={"number"}}
1836function eventChatCommand(player_name,message)
1837return commands.Run(player_name,message)
1838end
1839function eventInit()
1840for command_name,command in pairs(command_list)do
1841command.name=command_name
1842command.usage=commands.GetUsage(command_name)
1843if command.aliases then
1844for i_alias,alias in ipairs(command.aliases)do
1845commands.aliases[alias]=command_name
1846end
1847end
1848table.insert(commands.names_ordered,command_name)
1849if command.perms then
1850if command.perms=="cheats"or command.perms=="admins"or command.perms=="everyone"then
1851perms.perms[command.perms]["!"..command_name]=true
1852perms.perms["admins"]["!"..command_name.."-others"]=true
1853else
1854print_warn(string.format("Invalid `perms == \"%s\"` for command `%s`!",command.perms,command_name))
1855end
1856end
1857end
1858table.sort(commands.names_ordered)
1859end
1860return commands
1861end
1862pshy.modules["pshy.ui.v1"].load = function()
1863pshy.require("pshy.events")
1864local utils_strings=pshy.require("pshy.utils.strings")
1865local perms=pshy.require("pshy.perms")
1866local commands=pshy.require("pshy.commands")
1867function pshy.UICreate(text)
1868local ui={}
1869ui.id=2049
1870ui.text=text or"<b>New Control</b>"
1871ui.player=nil
1872ui.x=50
1873ui.y=50
1874ui.w=nil ui.h=nil ui.alpha=1.0
1875ui.fixed=true
1876return ui
1877end
1878function pshy.UIShow(u,player_name)
1879ui.addTextArea(u.id,u.text,player_name or u.player,u.x,u.y,u.w,u.h,u.back_color,u.border_color,u.alpha,u.fixed)
1880end
1881function eventTextAreaCallback(textAreaId,playerName,callback)
1882if type(callback)~="string"then
1883print(string.format("WARNING: eventTextAreaCallback callback was %s",type(callback)))
1884return
1885end
1886local callbacks=utils_strings.Split(callback,"\n")
1887for i_c,c in ipairs(callbacks)do
1888if(c=="close")then
1889ui.removeTextArea(textAreaId,playerName)
1890end
1891if(c=="closeall")then
1892if perms.admins[playerName]then
1893ui.removeTextArea(textAreaId,nil)
1894end
1895end
1896if(string.sub(c,1,5)=="pcmd ")then
1897commands.Run(playerName,utils_strings.Split(c," ",2)[2])
1898end
1899if(string.sub(c,1,6)=="apcmd ")then
1900if perms.admins[playerName]then
1901commands.Run(playerName,utils_strings.Split(c," ",2)[2])
1902else
1903return
1904end
1905end
1906if(string.sub(c,1,4)=="cmd ")then
1907eventChatCommand(playerName,utils_strings.Split(c," ",2)[2])
1908eventChatMessage(playerName,"!"..utils_strings.Split(c," ",2)[2])
1909end
1910end
1911end
1912function eventChatMessage(player_name,message)
1913end
1914end
1915pshy.modules["pshy.bases.scores"].load = function()
1916pshy.require("pshy.events")
1917local help_pages=pshy.require("pshy.help.pages")
1918pshy.require("pshy.ui.v1")
1919local ids=pshy.require("pshy.utils.ids")
1920local scores={}
1921tfm.exec.disableAutoScore(true)
1922scores.per_win=0 scores.per_first_wins={}scores.per_cheese=0 scores.per_first_cheeses={}scores.per_death=0 scores.per_first_deaths={}scores.survivors_win=false scores.ui_id=ids.AllocTextAreaId()scores.show=true scores.per_bonus=0 scores.reset_on_leave=true
1923scores.scores={}scores.firsts_win={}scores.round_wins={}scores.round_cheeses={}scores.round_deaths={}scores.round_ended=true scores.should_update_ui=false
1924local original_setPlayerScore=tfm.exec.setPlayerScore
1925tfm.exec.setPlayerScore=function(player_name,score,add)
1926local tfm_player=tfm.get.room.playerList[player_name]
1927if tfm_player then
1928if add then
1929tfm_player.score=tfm_player.score+score
1930else
1931tfm_player.score=score
1932end
1933end
1934return original_setPlayerScore(player_name,score,add)
1935end
1936function eventPlayerScore(player_name,points)
1937tfm.exec.setPlayerScore(player_name,scores.scores[player_name],false)
1938end
1939function scores.Add(player_name,points)
1940scores.scores[player_name]=scores.scores[player_name]+points
1941eventPlayerScore(player_name,points)
1942end
1943function scores.Set(player_name,points)
1944scores.scores[player_name]=points
1945tfm.exec.setPlayerScore(player_name,scores.scores[player_name],false)
1946end
1947local function ScoresUpdateRoundTop(player_name)
1948if((#scores.round_wins+#scores.round_cheeses+#scores.round_deaths)==0)then
1949return
1950end
1951local text="<font size='10'><p align='left'>"
1952if#scores.round_wins>0 then
1953text=text.."<font color='#ff0000'><b> First Win: "..scores.round_wins[1].."</b></font>\n"
1954end
1955if#scores.round_cheeses>0 then
1956text=text.."<d><b> First Cheese: "..scores.round_cheeses[1].."</b></d>\n"
1957end
1958if#scores.round_deaths>0 then
1959end
1960text=text.."</p></font>"
1961local title=pshy.UICreate(text)
1962title.id=scores.ui_id
1963title.x=810
1964title.y=30
1965title.w=nil
1966title.h=nil
1967title.back_color=0
1968title.border_color=0
1969pshy.UIShow(title,player_name)
1970end
1971function scores.ResetPlayer(player_name)
1972assert(type(player_name)=="string")
1973scores.scores[player_name]=0
1974scores.firsts_win[player_name]=0
1975tfm.exec.setPlayerScore(player_name,0,false)
1976end
1977function scores.ResetPlayers()
1978scores.scores={}
1979for player_name,player in pairs(tfm.get.room.playerList)do
1980scores.ResetPlayer(player_name)
1981end
1982end
1983function eventNewGame()
1984scores.round_wins={}
1985scores.round_cheeses={}
1986scores.round_deaths={}
1987scores.round_ended=false
1988scores.should_update_ui=false
1989ui.removeTextArea(scores.ui_id,nil)
1990for player_name,score in pairs(scores.scores)do
1991tfm.exec.setPlayerScore(player_name,score,false)
1992end
1993end
1994function eventLoop(time,time_remaining)
1995if scores.show and scores.should_update_ui then
1996ScoresUpdateRoundTop()
1997scores.should_update_ui=false
1998end
1999if time_remaining<1000 and scores.survivors_win~=false then
2000scores.round_ended=true
2001for player_name,player in pairs(tfm.get.room.playerList)do
2002tfm.giveCheese(player_name,true)
2003tfm.playerVictory(player_name)
2004end
2005end
2006end
2007function eventPlayerDied(player_name)
2008if not scores.round_ended then
2009local points=scores.per_death
2010table.insert(scores.round_deaths,player_name)
2011local rank=#scores.round_deaths
2012if scores.per_first_deaths[rank]then
2013points=points+scores.per_first_deaths[rank]
2014end
2015if points~=0 then
2016scores.Add(player_name,points)
2017end
2018end
2019scores.should_update_ui=true
2020end
2021function eventPlayerGetCheese(player_name)
2022if not scores.round_ended then
2023local points=scores.per_cheese
2024table.insert(scores.round_cheeses,player_name)
2025local rank=#scores.round_cheeses
2026if scores.per_first_cheeses[rank]then
2027points=points+scores.per_first_cheeses[rank]
2028end
2029if points~=0 then
2030scores.Add(player_name,points)
2031end
2032end
2033scores.should_update_ui=true
2034end
2035function eventPlayerLeft(player_name)
2036if scores.reset_on_leave then
2037scores.scores[player_name]=0
2038end
2039end
2040function eventPlayerWon(player_name,time_elapsed)
2041local points=0
2042if scores.round_ended and scores.survivors_win~=false then
2043points=points+((scores.survivors_win==true)and scores.per_win or scores.survivors_win)
2044elseif not scores.round_ended then
2045points=points+scores.per_win
2046table.insert(scores.round_wins,player_name)
2047local rank=#scores.round_wins
2048if scores.per_first_wins[rank]then
2049points=points+scores.per_first_wins[rank]
2050end
2051if rank==1 then
2052scores.firsts_win[player_name]=scores.firsts_win[player_name]+points
2053end
2054end
2055if points~=0 then
2056scores.Add(player_name,points)
2057end
2058scores.should_update_ui=true
2059end
2060function eventPlayerBonusGrabbed(player_name,bonus_id)
2061if scores.per_bonus~=0 then
2062scores.Add(player_name,scores.per_bonus)
2063end
2064end
2065function eventNewPlayer(player_name)
2066if not scores.scores[player_name]then
2067scores.ResetPlayer(player_name)
2068else
2069tfm.exec.setPlayerScore(player_name,scores.scores[player_name],false)
2070end
2071end
2072scores.ResetPlayers()
2073return scores
2074end
2075pshy.modules["pshy.bases.splashscreen"].load = function()
2076pshy.require("pshy.events")
2077local splashscreen={}
2078splashscreen.image="17ab692dc8e.png"splashscreen.x=100 splashscreen.y=-10 splashscreen.sx=1 splashscreen.sy=1 splashscreen.text="<fc>Pshy Module</fc>"splashscreen.text_x=0 splashscreen.text_y=0 splashscreen.text_w=nil splashscreen.text_h=nil splashscreen.text_arbitrary_id=13
2079splashscreen.text_backcolor=0x0 splashscreen.text_bordercolor=0x0 splashscreen.text_alpha=1.0 splashscreen.duration=6*1000
2080local first_new_game=true
2081local function removeSplashImageCallback(callback_id,image_id)
2082tfm.exec.removeImage(image_id,true)
2083end
2084local function Show(player_name)
2085local splash_image_id=tfm.exec.addImage(splashscreen.image,"&0",splashscreen.x,splashscreen.y,player_name,splashscreen.sx,splashscreen.sy)
2086system.newTimer(removeSplashImageCallback,splashscreen.duration,false,splash_image_id)
2087end
2088local function showSplashIfNoNewgameCallback()
2089if first_new_game then
2090Show(nil)
2091first_new_game=false
2092end
2093end
2094function eventNewGame()
2095if first_new_game then
2096Show(nil)
2097first_new_game=false
2098end
2099end
2100function eventNewPlayer(player_name)
2101if not first_new_game then
2102Show(player_name)
2103end
2104end
2105function eventInit()
2106system.newTimer(showSplashIfNoNewgameCallback,1000,false)
2107end
2108return splashscreen
2109end
2110pshy.modules["pshy.bases.version"].load = function()
2111
2112local version={}
2113pshy.TFM_VERSION=8.63 pshy.TFM_API_VERSION="0.28"version.days_before_update_suggested=30 version.days_before_update_advised=50 local VERSION_MARGIN=0.03
2114function version.Check()
2115if pshy.MAIN_VERSION then
2116print(string.format("<v>Script version <ch>%s</ch></v>",pshy.MAIN_VERSION))
2117end
2118print(string.format("<v>Pshy version <ch>%s</ch></v>",pshy.PSHY_VERSION))
2119local release_days=pshy.BUILD_TIME/60/60/24
2120local current_days=os.time()/1000/60/60/24
2121local days_old=current_days-release_days
2122if version.days_before_update_advised and days_old>version.days_before_update_advised then
2123print(string.format("<o>This build is <r>%d days</r> old. Please obtain a newer version as soon as possible.</o>",days_old))
2124elseif version.days_before_update_suggested and days_old>version.days_before_update_suggested then
2125print(string.format("<j>This build is <o>%d days</o> old. An update may be available.</j>",days_old))
2126else
2127print(string.format("<v>This build is <ch>%d days</ch> old.</v>",days_old))
2128end
2129if tfm.get.misc.apiVersion~=pshy.TFM_API_VERSION then
2130print("<o>⚠ The TFM LUA API was updated, an update of pshy's script may be available for this new version.</o>")
2131end
2132local tfm_version=tfm.get.misc.transformiceVersion
2133if not pshy.MAIN_VERSION then
2134if math.floor(tfm_version)>math.floor(pshy.TFM_VERSION)then
2135print("<o>⚠ Transformice had a major update, an update of pshy's script may be available for this new version.</o>")
2136elseif tfm_version>pshy.TFM_VERSION+VERSION_MARGIN+0.0001 then
2137print("<j>⚠ Transformice had a minor update, an update of pshy's script may be available for this new version.</j>")
2138end
2139end
2140if tfm_version+0.0001<pshy.TFM_VERSION then
2141print("<vi>⚠ Transformice's version is behind what it is supposed to be!</vi>")
2142end
2143end
2144version.Check()
2145print("<vi><b>Report pshy_merge bugs at <bl><u>https://github.com/Pshy0/pshy_merge/issues/new/choose</u></bl></b></vi>")
2146local d=os.date("%m-%d")
2147if d=="09-20"then
2148print("<o>squeak :c</o>")
2149elseif d=="05-02"then
2150print("<o>piou piou</o>")
2151end
2152return version
2153end
2154pshy.modules["pshy.utils.tables"].load = function()
2155local utils_tables={}
2156function utils_tables.Copy(t)
2157assert(type(t)=="table")
2158local new_table={}
2159for key,value in pairs(t)do
2160new_table[key]=value
2161end
2162return new_table
2163end
2164function utils_tables.DeepCopy(t)
2165assert(type(t)=="table")
2166local new_table={}
2167for key,value in pairs(t)do
2168if type(value)=="table"then
2169value=utils_tables.DeepCopy(value)
2170end
2171new_table[key]=value
2172end
2173return new_table
2174end
2175function utils_tables.ListCopy(t)
2176assert(type(t)=="table")
2177local new_table={}
2178for key,value in ipairs(t)do
2179table.insert(new_table,value)
2180end
2181return new_table
2182end
2183function utils_tables.Keys(t)
2184local keys={}
2185for key in pairs(t)do
2186table.insert(keys,key)
2187end
2188return keys
2189end
2190function utils_tables.SortedKeys(t)
2191local keys=utils_tables.Keys(t)
2192table.sort(keys)
2193return keys
2194end
2195function utils_tables.CountKeys(t)
2196local count=0
2197for key,value in pairs(t)do
2198count=count+1
2199end
2200return count
2201end
2202function utils_tables.SortedListRemoveDuplicates(t)
2203local prev_size=#t
2204local i=#t-1
2205while i>=1 do
2206if t[i]==t[i+1]then
2207table.remove(t,i+1)
2208end
2209i=i-1
2210end
2211return prev_size-#t
2212end
2213function utils_tables.ListAppend(dst_list,src_list)
2214assert(type(dst_list)=="table")
2215assert(type(dst_list)=="table")
2216for i_item,item in ipairs(src_list)do
2217table.insert(dst_list,item)
2218end
2219end
2220function utils_tables.CountValue(t,v)
2221local count=0
2222for key,value in pairs(t)do
2223if value==v then
2224count=count+1
2225end
2226end
2227return count
2228end
2229function utils_tables.ListRemoveValue(l,v)
2230for i=#l,1,-1 do
2231if l[i]==v then
2232table.remove(l,i)
2233end
2234end
2235end
2236function utils_tables.RandomTableKey(t)
2237local keylist={}
2238for k in pairs(t)do
2239table.insert(keylist,k)
2240end
2241return keylist[math.random(#keylist)]
2242end
2243return utils_tables
2244end
2245pshy.modules["pshy.bonuses.list"].load = function()
2246
2247local bonus_types={}
2248return bonus_types
2249end
2250pshy.modules["pshy.images.list"].load = function()
2251
2252local image_map={}
2253image_map["15568238225.png"]={meme=true,w=40,h=40,desc="FUUU"}
2254return image_map
2255end
2256pshy.modules["pshy.bonuses"].load = function()
2257pshy.require("pshy.events")
2258pshy.require("pshy.utils.print")
2259local utils_tables=pshy.require("pshy.utils.tables")
2260local bonus_types=pshy.require("pshy.bonuses.list")
2261local players=pshy.require("pshy.players")
2262local commands_list=pshy.require("pshy.commands.list")
2263local images=pshy.require("pshy.images.list")
2264local function AddImage(image_name,target,x,y,player_name,angle)
2265local image=images[image_name]or images["15568238225.png"]
2266return tfm.exec.addImage(image_name,target,x,y,player_name,1.0,1.0,angle,alpha,image.ax or 0.5,image.ay or 0.5)
2267end
2268local bonuses={}
2269bonuses.BEHAVIOR_STANDARD=nil bonuses.BEHAVIOR_SHARED=1 bonuses.BEHAVIOR_REMAIN=2 bonuses.BEHAVIOR_RESPAWN=3 local PSHY_BONUS_BEHAVIOR_STANDARD=bonuses.BEHAVIOR_STANDARD
2270local PSHY_BONUS_BEHAVIOR_SHARED=bonuses.BEHAVIOR_SHARED
2271local PSHY_BONUS_BEHAVIOR_REMAIN=bonuses.BEHAVIOR_REMAIN
2272local PSHY_BONUS_BEHAVIOR_RESPAWN=bonuses.BEHAVIOR_RESPAWN
2273local function ConvertBonus(bonus)
2274if type(bonus.type)=="table"then
2275bonus.type_name=bonus.type_name or"UNKNOWN"
2276elseif type(bonus.type)=="string"then
2277bonus.type_name=bonus.type
2278bonus.type=nil
2279end
2280if not bonus.type then
2281bonus.type=bonus_types[bonus.type_name]
2282assert(bonus.type,string.format("bonus type %s not found",bonus.type_name))
2283end
2284if not bonus.behavior then
2285if bonus.shared or bonus.type.shared then
2286bonus.behavior=PSHY_BONUS_BEHAVIOR_SHARED
2287elseif bonus.remain or bonus.type.remain then
2288bonus.behavior=PSHY_BONUS_BEHAVIOR_REMAIN
2289elseif bonus.respawn or bonus.type.respawn then
2290bonus.behavior=PSHY_BONUS_BEHAVIOR_RESPAWN
2291end
2292end
2293assert(bonus.type)
2294assert(bonus.type_name)
2295end
2296bonuses.list={}local bonuses_taken={}
2297local bonuses_list=bonuses.list
2298local players_image_ids={}local shared_image_ids={}local delayed_player_bonuses_refresh={}local taken_shared_bonuses={}local players_taken_bonuses={}local new_player_joined=false
2299local loop_count=0
2300function bonuses.SetList(bonus_list)
2301DisableAllBonuses()
2302bonuses.list=utils_tables.ListCopy(bonus_list)
2303bonuses_list=bonuses.list
2304for bonus_id,bonus in ipairs(bonuses_list)do
2305ConvertBonus(bonus)
2306end
2307EnableAllBonuses()
2308end
2309function bonuses.Add(bonus_type_name,bonus_x,bonus_y,bonus_enabled,angle)
2310return bonuses.AddNoCopy({type_name=bonus_type_name,x=bonus_x,y=bonus_y,enabled=bonus_enabled,angle=angle})
2311end
2312function bonuses.AddNoCopy(bonus)
2313ConvertBonus(bonus)
2314bonus.id=#bonuses.list+1
2315bonuses.list[bonus.id]=bonus
2316if bonus.enabled~=false then
2317bonuses.Enable(bonus.id)
2318end
2319if not bonus.angle then
2320bonus.angle=0
2321end
2322return bonus.id
2323end
2324local function RefreshSharedBonusesImages()
2325for bonus_id,bonus in ipairs(bonuses.list)do
2326if shared_image_ids[bonus_id]then
2327local bonus_behavior=bonus.behavior or bonus.type.behavior
2328local bonus_image=bonus.image or bonus.type.image
2329if bonus_behavior==PSHY_BONUS_BEHAVIOR_SHARED or bonus_behavior==PSHY_BONUS_BEHAVIOR_REMAIN then
2330if bonus_image then
2331local old_image_id=shared_image_ids[bonus_id]
2332shared_image_ids[bonus_id]=AddImage(bonus_image,(bonus.foreground or bonus.type.foreground)and"!9999"or"?9999",bonus.x,bonus.y,nil,(bonus.angle or 0)*math.pi/180)
2333if old_image_id then
2334tfm.exec.removeImage(old_image_id)
2335end
2336end
2337end
2338end
2339end
2340end
2341function bonuses.Enable(bonus_id,player_name)
2342assert(type(bonus_id)=="number")
2343local bonus=bonuses.list[bonus_id]
2344local bonus_type=bonus.type
2345local bonus_behavior=bonus.behavior or bonus_type.behavior
2346local bonus_image=bonus.image or bonus_type.image
2347local bonus_foreground=bonus.foreground or bonus_type.foreground
2348tfm.exec.removeBonus(bonus_id,player_name)
2349tfm.exec.addBonus(0,bonus.x,bonus.y,bonus_id,0,false,player_name)
2350if bonus_image then
2351if bonus_behavior==PSHY_BONUS_BEHAVIOR_SHARED or bonus_behavior==PSHY_BONUS_BEHAVIOR_REMAIN then
2352assert(player_name==nil,"Bonuses of behavior type SHARED or REMAIN can only be enabled/disabled for all players.")
2353if not shared_image_ids[bonus_id]then
2354shared_image_ids[bonus_id]=AddImage(bonus_image,(bonus.foreground or bonus.type.foreground)and"!9999"or"?9999",bonus.x,bonus.y,nil,(bonus.angle or 0)*math.pi/180)
2355end
2356else
2357for player_name in pairs(player_name and{[player_name]=true}or players.in_room)do
2358local ids=players_image_ids[player_name]
2359if not ids then
2360ids={}
2361players_image_ids[player_name]=ids
2362end
2363if not ids[bonus_id]then
2364ids[bonus_id]=AddImage(bonus_image,bonus_foreground and"!9999"or"?9999",bonus.x,bonus.y,player_name,(bonus.angle or 0)*math.pi/180)
2365end
2366end
2367end
2368end
2369if(bonus.bahavior or bonus_type.behavior)==PSHY_BONUS_BEHAVIOR_SHARED then
2370taken_shared_bonuses[bonus_id]=nil
2371else
2372if players_taken_bonuses[player_name]then
2373players_taken_bonuses[player_name][bonus_id]=nil
2374end
2375end
2376end
2377function bonuses.Disable(bonus_id,player_name)
2378assert(type(bonus_id)=="number")
2379if player_name==nil then
2380for player_name in pairs(tfm.get.room.playerList)do
2381bonuses.Disable(bonus_id,player_name)
2382end
2383return
2384end
2385if not players_image_ids[player_name]then
2386return
2387end
2388local bonus=bonuses.list[bonus_id]
2389local ids=players_image_ids[player_name]
2390if ids[bonus_id]==nil then
2391return
2392end
2393tfm.exec.removeBonus(bonus_id,player_name)
2394tfm.exec.removeImage(ids[bonus_id])
2395end
2396local function EnableAllBonuses()
2397print_warn("called EnableAllBonuses() but it isnt supposed to be used")
2398for bonus_id,bonus in pairs(bonuses.list)do
2399if bonus.enabled~=false then
2400tfm.exec.removeBonus(bonus.id,nil)
2401tfm.exec.addBonus(0,bonus.x,bonus.y,bonus.id,0,false,nil)
2402local bonus_behavior=bonus.behavior or bonus.type.behavior
2403if bonus_behavior==PSHY_BONUS_BEHAVIOR_SHARED or bonus_behavior==PSHY_BONUS_BEHAVIOR_REMAIN then
2404if bonus.image then
2405shared_image_ids[bonus_id]=AddImage(bonus.image,(bonus.foreground or bonus.type.foreground)and"!9999"or"?9999",bonus.x,bonus.y,nil,(bonus.angle or 0)*math.pi/180)
2406end
2407end
2408end
2409end
2410for player_name in pairs(players.in_room)do
2411local images_ids=players_image_ids[player_name]
2412for bonus_id,bonus in pairs(bonuses.list)do
2413if bonus.enabled~=false then
2414local bonus_behavior=bonus.behavior or bonus.type.behavior
2415if bonus_behavior==PSHY_BONUS_BEHAVIOR_STANDARD or bonus_behavior==PSHY_BONUS_BEHAVIOR_RESPAWN then
2416images_ids[bonus_id]=AddImage(bonus.image,(bonus.foreground or bonus.type.foreground)and"!9999"or"?9999",bonus.x,bonus.y,player_name,(bonus.angle or 0)*math.pi/180)
2417end
2418end
2419end
2420end
2421taken_shared_bonuses={}
2422players_taken_bonuses={}
2423end
2424local function DisableAllBonuses()
2425for bonus_id,bonus in pairs(bonuses.list)do
2426tfm.exec.removeBonus(bonus.id,nil)
2427end
2428for bonus_id,image_id in pairs(shared_image_ids)do
2429tfm.exec.removeImage(image_id)
2430end
2431shared_image_ids={}
2432for player_name,images_ids in pairs(players_image_ids)do
2433for bonus_id,image_id in pairs(images_ids)do
2434tfm.exec.removeImage(image_id)
2435end
2436end
2437players_image_ids={}
2438end
2439local function SharedBonusTaken(bonus)
2440assert(bonus.behavior==PSHY_BONUS_BEHAVIOR_SHARED or bonus.type.behavior==PSHY_BONUS_BEHAVIOR_SHARED)
2441taken_shared_bonuses[bonus.id]=true
2442tfm.exec.removeBonus(bonus.id,nil)
2443tfm.exec.removeImage(shared_image_ids[bonus.id])
2444shared_image_ids[bonus.id]=nil
2445taken_shared_bonuses[bonus.id]=bonus
2446end
2447function eventPlayerBonusGrabbed(player_name,id)
2448if id<1 or id>#bonuses.list then
2449return
2450end
2451if loop_count<4 then
2452print_warn("%s grabbed bonus %d within 2 seconds",player_name,id)
2453return
2454end
2455local bonus=bonuses.list[id]
2456if not bonus then
2457print_error("%s grabbed non-existing bonus with id %d",player_name,id)
2458return
2459end
2460local bonus_type=bonus.type
2461local bonus_behavior=bonus.behavior or bonus_type.behavior
2462if bonus_behavior==PSHY_BONUS_BEHAVIOR_SHARED and taken_shared_bonuses[id]then
2463return false
2464end
2465local func=bonus.func or bonus_type.func
2466local pick_rst=nil
2467if func then
2468pick_rst=func(player_name,bonus)
2469end
2470if pick_rst==false or bonus_behavior==PSHY_BONUS_BEHAVIOR_REMAIN then
2471if not delayed_player_bonuses_refresh[player_name]then
2472delayed_player_bonuses_refresh[player_name]={}
2473end
2474table.insert(delayed_player_bonuses_refresh[player_name],bonus)
2475else
2476if bonus_behavior==PSHY_BONUS_BEHAVIOR_SHARED then
2477SharedBonusTaken(bonus)
2478else
2479if not players_taken_bonuses[player_name]then
2480players_taken_bonuses[player_name]={}
2481end
2482local taken_set=players_taken_bonuses[player_name]
2483taken_set[id]=true
2484if players_image_ids[player_name]then
2485tfm.exec.removeImage(players_image_ids[player_name][id])
2486players_image_ids[player_name][id]=nil
2487end
2488end
2489end
2490end
2491function eventNewGame()
2492bonuses.list={}
2493bonuses_list=bonuses.list
2494players_image_ids={}
2495shared_image_ids={}
2496delayed_player_bonuses_refresh={}
2497taken_shared_bonuses={}
2498players_taken_bonuses={}
2499loop_count=0
2500end
2501function eventPlayerRespawn(player_name)
2502for bonus_id,bonus in pairs(bonuses.list)do
2503local bonus_behavior=bonus.behavior or bonus.type.behavior
2504if bonus_behavior==PSHY_BONUS_BEHAVIOR_RESPAWN then
2505bonuses.Enable(bonus_id,player_name)
2506end
2507end
2508end
2509function eventNewPlayer(player_name)
2510new_player_joined=true
2511local taken_set=players_taken_bonuses[player_name]
2512for bonus_id,bonus in pairs(bonuses.list)do
2513local bonus_behavior=bonus.behavior or bonus.type.behavior
2514if bonus_behavior==PSHY_BONUS_BEHAVIOR_RESPAWN then
2515elseif bonus_behavior==PSHY_BONUS_BEHAVIOR_SHARED or bonus_behavior==PSHY_BONUS_BEHAVIOR_REMAIN then
2516if not taken_shared_bonuses[bonus_id]then
2517tfm.exec.addBonus(0,bonus.x,bonus.y,bonus.id,0,false,player_name)
2518end
2519else
2520if not taken_set or not taken_set[bonus_id]then
2521bonuses.Enable(bonus_id,player_name)
2522end
2523end
2524end
2525end
2526function eventPlayerLeft(player_name)
2527players_image_ids[player_name]=nil
2528end
2529function eventLoop()
2530loop_count=loop_count+1
2531if new_player_joined then
2532new_player_joined=false
2533RefreshSharedBonusesImages()
2534end
2535for player_name,bonus_list in pairs(delayed_player_bonuses_refresh)do
2536for i_bonus,bonus in ipairs(bonus_list)do
2537tfm.exec.addBonus(0,bonus.x,bonus.y,bonus.id,0,false,player_name)
2538end
2539end
2540delayed_player_bonuses_refresh={}
2541end
2542local function CommandBonusEffect(user,bonus_type,target_player)
2543target_player=target_player or user
2544local tfm_player=tfm.get.room.playerList[target_player]
2545bonus_type.func(target_player,{x=tfm_player.x,y=tfm_player.y})
2546end
2547commands_list["bonuseffect"]={perms="admins",func=CommandBonusEffect,desc="play a bonus effect",argc_min=1,argc_max=2,arg_types={bonus_types,"player"}}
2548return bonuses
2549end
2550pshy.modules["pshy.images.list.bonuses"].load = function()
2551local images=pshy.require("pshy.images.list")
2552images["17bef4f49c5.png"]={bonus=true,w=30,h=30,desc="empty bonus"}
2553images["17bf4b75aa7.png"]={bonus=true,w=30,h=30,desc="question bonus"}
2554images["17bf4ba4ce5.png"]={bonus=true,w=30,h=30,desc="teleporter bonus"}
2555images["17bf4b9e11d.png"]={bonus=true,w=30,h=30,desc="crate bonus"}
2556images["17bf4b9af56.png"]={bonus=true,w=30,h=30,desc="high speed bonus"}
2557images["17bf4b977f5.png"]={bonus=true,w=30,h=30,desc="ice cube bonus"}
2558images["17bf4b94d8a.png"]={bonus=true,w=30,h=30,desc="snowflake bonus"}
2559images["17bf4b91c35.png"]={bonus=true,w=30,h=30,desc="broken heart bonus"}
2560images["17bf4b8f9e4.png"]={bonus=true,w=30,h=30,desc="heart bonus"}
2561images["17bf4b8c42d.png"]={bonus=true,w=30,h=30,desc="feather bonus"}
2562images["17bf4b89eba.png"]={bonus=true,w=30,h=30,desc="cross"}
2563images["17bf4b868c3.png"]={bonus=true,w=30,h=30,desc="jumping mouse bonus"}
2564images["17bf4b80fc3.png"]={bonus=true,w=30,h=30,desc="balloon bonus"}
2565images["17bef4f49c5.png"]={bonus=true,w=30,h=30,desc="empty bonus"}
2566images["17bf4b7ddd6.png"]={bonus=true,w=30,h=30,desc="triggered mouse trap"}
2567images["17bf4b7a091.png"]={bonus=true,w=30,h=30,desc="mouse trap"}
2568images["17bf4b7250e.png"]={bonus=true,w=30,h=30,desc="wings bonus"}
2569images["17bf4b6f226.png"]={bonus=true,w=30,h=30,desc="transformations bonus"}
2570images["17bf4b67579.png"]={bonus=true,w=30,h=30,desc="grow bonus"}
2571images["17bf4b63aaa.png"]={bonus=true,w=30,h=30,desc="shrink bonus"}
2572images["17bf4c421bb.png"]={bonus=true,w=30,h=30,desc="white flag bonus"}
2573images["17e59dbef1e.png"]={bonus=true,w=30,h=30,desc="racing flag bonus"}
2574images["17bf4f3f2fb.png"]={bonus=true,w=30,h=30,desc="v check"}
2575images["17e53fb43dc.png"]={bonus=true,w=30,h=30,desc="cannonball bonus"}
2576images["17e59ba43a6.png"]={bonus=true,w=30,h=30,desc="fish bonus"}
2577images["17ebfdb85bd.png"]={bonus=true,w=30,h=30,desc="mouse skull bonus"}
2578return images
2579end
2580pshy.modules["pshy.players.keyboard"].load = function()
2581pshy.require("pshy.events")
2582local players=pshy.require("pshy.players")
2583local player_list=players.list
2584local function TouchPlayer(player_name)
2585player_list[player_name].is_facing_right=true
2586system.bindKeyboard(player_name,0,true,true)
2587system.bindKeyboard(player_name,2,true,true)
2588end
2589function eventPlayerRespawn(player_name)
2590player_list[player_name].is_facing_right=true
2591end
2592function eventKeyboard(player_name,keycode,down,x,y)
2593local player=player_list[player_name]
2594if down then
2595if keycode==0 then
2596if player.is_facing_right~=false then
2597player.is_facing_right=false
2598if eventPlayerDirectionChanged then
2599eventPlayerDirectionChanged(player_name,false)
2600end
2601end
2602elseif keycode==2 then
2603if player.is_facing_right~=true then
2604player.is_facing_right=true
2605if eventPlayerDirectionChanged then
2606eventPlayerDirectionChanged(player_name,true)
2607end
2608end
2609end
2610end
2611end
2612function eventNewPlayer(player_name)
2613TouchPlayer(player_name)
2614end
2615function eventNewGame()
2616for player_name in pairs(tfm.get.room.playerList)do
2617player_list[player_name].is_facing_right=true
2618end
2619end
2620function eventInit()
2621for player_name in pairs(tfm.get.room.playerList)do
2622TouchPlayer(player_name)
2623end
2624end
2625end
2626pshy.modules["pshy.bonuses.list.mario"].load = function()
2627local bonuses=pshy.require("pshy.bonuses")
2628local bonus_types=pshy.require("pshy.bonuses.list")
2629pshy.require("pshy.events")
2630pshy.require("pshy.images.list.bonuses")
2631local players=pshy.require("pshy.players")
2632local player_list=players.list pshy.require("pshy.players.keyboard")
2633local mario_powerball_delay=3000
2634local tfm_exec_displayParticle=tfm.exec.displayParticle
2635local function TouchPlayer(player_name)
2636local player=player_list[player_name]
2637player.mario_coins=player.mario_coins or 0
2638player.mario_grown=player.mario_grown or false
2639player.mario_flower=player.mario_flower or false
2640player.powerball_type=tfm.enum.shamanObject.snowBall player.mario_thrown_powerball_id=player.mario_thrown_powerball_id or nil
2641player.mario_next_powerball_time=player.mario_next_powerball_time or nil
2642player.mario_name_color=player.mario_name_color or 0xbbbbbb
2643end
2644function bonuses.callback_MarioCoin(player_name,bonus)
2645local player=player_list[player_name]
2646player.mario_coins=player.mario_coins+1
2647tfm.exec.setPlayerScore(player_name,1,true)
2648tfm_exec_displayParticle(tfm.enum.particle.yellowGlitter,bonus.x,bonus.y-1,0,-6,0,0.4,player_name)
2649tfm_exec_displayParticle(tfm.enum.particle.yellowGlitter,bonus.x-1,bonus.y,0,-6,0,0.4,player_name)
2650tfm_exec_displayParticle(tfm.enum.particle.yellowGlitter,bonus.x,bonus.y+1,0,-6,0,0.4,player_name)
2651tfm_exec_displayParticle(tfm.enum.particle.yellowGlitter,bonus.x+1,bonus.y,0,-6,0,0.4,player_name)
2652if player.mario_coins==9 then
2653player.mario_name_color=0x6688ff elseif player.mario_coins==25 then
2654player.mario_name_color=0x00eeee elseif player.mario_coins==35 then
2655player.mario_name_color=0x77ff77 elseif player.mario_coins==55 then
2656player.mario_name_color=0xeeee00 elseif player.mario_coins==75 then
2657player.mario_name_color=0xff7700 elseif player.mario_coins==100 then
2658player.mario_name_color=0xff0000 elseif player.mario_coins==125 then
2659player.mario_name_color=0xff00bb elseif player.mario_coins==150 then
2660player.mario_name_color=0xbb00ff else
2661return
2662end
2663tfm.exec.setNameColor(player_name,player.mario_name_color)
2664end
2665bonus_types["MarioCoin"]={image="17aa6f22c53.png",func=bonuses.callback_MarioCoin}
2666function bonuses.callback_MarioMushroom(player_name,bonus)
2667local player=player_list[player_name]
2668tfm.exec.changePlayerSize(player_name,1.4)
2669player.mario_grown=true
2670tfm_exec_displayParticle(tfm.enum.particle.redGlitter,bonus.x-1,bonus.y,-1,-2,0,0.1,player_name)
2671tfm_exec_displayParticle(tfm.enum.particle.redGlitter,bonus.x+0,bonus.y,0,-2,0,0.1,player_name)
2672tfm_exec_displayParticle(tfm.enum.particle.redGlitter,bonus.x+1,bonus.y,1,-2,0,0.1,player_name)
2673end
2674bonus_types["MarioMushroom"]={image="17c431c5e88.png",func=bonuses.callback_MarioMushroom,behavior=bonuses.BEHAVIOR_RESPAWN}
2675function bonuses.callback_MarioFlower(player_name,bonus)
2676local player=player_list[player_name]
2677tfm.exec.bindKeyboard(player_name,32,true,true)
2678player.mario_flower=true
2679player.mario_next_powerball_time=os.time()
2680tfm.exec.chatMessage("<ch>Press SPACE to throw a fireball.</ch2>",player_name)
2681tfm_exec_displayParticle(tfm.enum.particle.orangeGlitter,bonus.x-1,bonus.y,-1,-2,0,0.1,player_name)
2682tfm_exec_displayParticle(tfm.enum.particle.orangeGlitter,bonus.x+0,bonus.y,0,-2,0,0.1,player_name)
2683tfm_exec_displayParticle(tfm.enum.particle.orangeGlitter,bonus.x+1,bonus.y,1,-2,0,0.1,player_name)
2684end
2685bonus_types["MarioFlower"]={image="17c41851d61.png",func=bonuses.callback_MarioFlower}
2686function eventKeyboard(player_name,key_code,down,x,y)
2687if key_code==32 and down then
2688local player=player_list[player_name]
2689if player.mario_flower and player.mario_next_powerball_time+mario_powerball_delay<os.time()then
2690if player.mario_thrown_powerball_id then
2691tfm.exec.removeObject(player.mario_thrown_powerball_id)
2692player.mario_thrown_powerball_id=nil
2693end
2694tfm.exec.playEmote(player_name,tfm.enum.emote.highfive_1,nil)
2695local speed=player.is_facing_right and 11 or-11
2696player.mario_thrown_powerball_id=tfm.exec.addShamanObject(player.powerball_type,x+speed*2,y,0,speed,0,false)
2697tfm.exec.displayParticle(tfm.enum.particle.redGlitter,x+speed*2,y,speed*0.15,-0.15)
2698tfm.exec.displayParticle(tfm.enum.particle.orangeGlitter,x+speed*2,y,speed*0.3,0)
2699tfm.exec.displayParticle(tfm.enum.particle.redGlitter,x+speed*2,y,speed*0.4,0)
2700tfm.exec.displayParticle(tfm.enum.particle.orangeGlitter,x+speed*2,y,speed*0.26,0.15)
2701player.mario_next_powerball_time=os.time()
2702end
2703end
2704end
2705function eventPlayerDied(player_name)
2706local player=player_list[player_name]
2707if player.mario_grown then
2708local death_x=tfm.get.room.playerList[player_name].x
2709local death_y=tfm.get.room.playerList[player_name].y
2710player.mario_grown=false
2711tfm.exec.changePlayerSize(player_name,1)
2712tfm.exec.respawnPlayer(player_name)
2713tfm.exec.movePlayer(player_name,death_x,death_y-30,false)
2714return false
2715end
2716end
2717local function CancelChanges()
2718for player_name,player in pairs(player_list)do
2719tfm.exec.changePlayerSize(player_name,1.0)
2720player.mario_grown=false
2721player.mario_flower=false end
2722end
2723function eventGameEnded()
2724CancelChanges()
2725end
2726function eventNewGame()
2727for player_name,player in pairs(player_list)do
2728player.mario_thrown_powerball_id=nil
2729player.mario_next_powerball_time=0
2730end
2731CancelChanges()
2732end
2733function eventNewPlayer(player_name)
2734TouchPlayer(player_name)
2735end
2736function eventInit()
2737for player_name in pairs(tfm.get.room.playerList)do
2738TouchPlayer(player_name)
2739end
2740end
2741end
2742pshy.modules["pshy.moduleswitch"].load = function()
2743local events=pshy.require("pshy.events")
2744local dummy_func=function()end
2745local function EnableModuleEvents(module_name)
2746local module=pshy.modules[module_name]
2747if not module then
2748print(string.format("<r>ERROR: EnableModule: Module `%s` not found!<n>",module_name))
2749return
2750end
2751if module.enabled==false then
2752module.enabled=true
2753for event_name,event in pairs(events.events)do
2754local module_index=event.module_indices[module_name]
2755if module_index then
2756event.functions[module_index]=event.original_functions[module_index]
2757end
2758end
2759end
2760end
2761local function DisableModuleEvents(module_name)
2762local module=pshy.modules[module_name]
2763if not module then
2764print(string.format("<r>ERROR: DisableModule: Module `%s` not found!<n>",module_name))
2765return
2766end
2767if module.enabled~=false then
2768module.enabled=false
2769for event_name,event in pairs(events.events)do
2770local module_index=event.module_indices[module_name]
2771if module_index then
2772event.functions[module_index]=dummy_func
2773end
2774end
2775end
2776end
2777local function InternalAdditiveEnableModule(module,direct)
2778assert(type(module)=="table")
2779if module.require_direct_enabling and not direct then
2780return
2781end
2782module.enable_count=(module.enable_count or 0)+1
2783for module_name,module in pairs(module.required_modules)do
2784InternalAdditiveEnableModule(module)
2785end
2786EnableModuleEvents(module.name)
2787if module.enable_count==1 then
2788module.enabled=true
2789if module.events and module.events.eventThisModuleEnabled then
2790module.events.eventThisModuleEnabled()
2791end
2792if eventModuleEnabled then
2793eventModuleEnabled(module.name)
2794end
2795end
2796end
2797local function InternalAdditiveDisableModule(module,direct)
2798assert(type(module)=="table")
2799if module.require_direct_enabling and not direct then
2800return
2801end
2802if(not module.enable_count or module.enable_count<=0)then
2803module.enable_count=0
2804print(string.format("<r>ERROR: <n>InternalAdditiveDisableModule: Module `%s` was already disabled!",module.name))
2805end
2806module.enable_count=module.enable_count-1
2807DisableModuleEvents(module.name)
2808for module_name,module in pairs(module.required_modules)do
2809InternalAdditiveDisableModule(module)
2810end
2811if module.enable_count==0 then
2812module.enabled=false
2813if module.events and module.events.eventThisModuleDisabled then
2814module.events.eventThisModuleDisabled()
2815end
2816if eventModuleDisabled then
2817eventModuleDisabled(module.name)
2818end
2819end
2820end
2821function pshy.EnableModule(module_name)
2822assert(type(module_name)=="string")
2823local module=pshy.modules[module_name]
2824InternalAdditiveEnableModule(module,true)
2825end
2826function pshy.DisableModule(module_name)
2827assert(type(module_name)=="string")
2828local module=pshy.modules[module_name]
2829InternalAdditiveDisableModule(module,true)
2830end
2831end
2832pshy.modules["pshy.commands.list.modules"].load = function()
2833local __MODULE_NAME__ = "pshy.commands.list.modules"
2834local command_list=pshy.require("pshy.commands.list")
2835local help_pages=pshy.require("pshy.help.pages")
2836pshy.require("pshy.moduleswitch")
2837local events=pshy.require("pshy.events")
2838help_pages[__MODULE_NAME__]={back="pshy",title="Modules",commands={}}
2839help_pages["pshy"].subpages[__MODULE_NAME__]=help_pages[__MODULE_NAME__]
2840local function ChatCommandModules(user,event_name)
2841tfm.exec.chatMessage("Modules (in require order):",user)
2842for i_module,module in pairs(pshy.modules_list)do
2843local status
2844if not module.loaded then
2845status="(<vi>not loaded</vi>)"
2846elseif module.event_count and module.event_count>0 then
2847if module.enabled==false then
2848status=string.format("(%d <j>disabled</j> events)",module.event_count)
2849elseif module.event_count and module.event_count>0 then
2850status=string.format("(%d %s<vp>enabled</vp> events, %d ons)",module.event_count,module.manually_enabled and"manu "or"auto ",module.enable_count)
2851end
2852elseif module.loaded then
2853status=string.format("(<v>loaded</v>, %d ons)",module.enable_count or 0)
2854end
2855tfm.exec.chatMessage(string.format(" > <n>%s %s",module.name,status),user)
2856end
2857end
2858command_list["modules"]={perms="admins",func=ChatCommandModules,desc="see a list of loaded modules having a given event",argc_min=0,argc_max=1,arg_types={"string"},arg_names={"event_name"}}
2859help_pages[__MODULE_NAME__].commands["modules"]=command_list["modules"]
2860local function ChatCommandModuleenable(user,mname,force)
2861if not pshy.modules[mname]then
2862return false,"No such module."
2863end
2864if force then
2865return pshy.EnableModule(mname)
2866else
2867local module=pshy.modules[mname]
2868if module.manually_enabled then
2869return false,"This module is already enabled."
2870else
2871module.manually_enabled=true
2872pshy.EnableModule(mname)
2873end
2874end
2875end
2876command_list["enablemodule"]={func=ChatCommandModuleenable,desc="enable a module",argc_min=1,argc_max=2,arg_types={"string","bool"}}
2877help_pages[__MODULE_NAME__].commands["enablemodule"]=command_list["enablemodule"]
2878local function ChatCommandModuledisable(user,mname,force)
2879if not pshy.modules[mname]then
2880return false,"No such module."
2881end
2882if force then
2883return pshy.DisableModule(mname)
2884else
2885local module=pshy.modules[mname]
2886if not module.manually_enabled then
2887if module.enabled then
2888return false,string.format("This module is to be disabled, but %d module(s) still need it.",module.enable_count)
2889else
2890return false,"This module is already disabled."
2891end
2892else
2893module.manually_enabled=false
2894pshy.DisableModule(mname)
2895end
2896end
2897end
2898command_list["disablemodule"]={func=ChatCommandModuledisable,desc="disable a module",argc_min=1,argc_max=2,arg_types={"string","bool"}}
2899help_pages[__MODULE_NAME__].commands["disablemodule"]=command_list["disablemodule"]
2900local function ChatCommandModulestop(user)
2901print(string.format("<j>[Modules] </j>%s Stopped the module.",user))
2902system.exit()
2903end
2904command_list["modulestop"]={perms="admins",func=ChatCommandModulestop,desc="stop the module",argc_min=0,argc_max=0}
2905help_pages[__MODULE_NAME__].commands["modulestop"]=command_list["modulestop"]
2906local function ChatCommandModulestop(user,mname)
2907local m=pshy.modules[mname]
2908if not m then
2909return false,"No such module."
2910end
2911m.value=m.load()
2912events.UpdateEventFunctions(mname)
2913end
2914command_list["modulereload"]={perms="admins",func=ChatCommandModulestop,desc="reload the module (dangerous)",argc_min=1,argc_max=1,arg_types={"string"}}
2915help_pages[__MODULE_NAME__].commands["modulereload"]=command_list["modulereload"]
2916local function ChatCommandPshyversion(user)
2917return true,string.format("Pshy repository version: <r>%s</r>",tostring(pshy.PSHY_VERSION))
2918end
2919command_list["pshyversion"]={perms="everyone",func=ChatCommandPshyversion,desc="show pshy_merge's repository version",argc_min=0,argc_max=0}
2920help_pages[__MODULE_NAME__].commands["pshyversion"]=command_list["pshyversion"]
2921local function ChatCommandScriptversion(user)
2922return true,string.format("Script repository version: <vp>%s</vp>",tostring(pshy.MAIN_VERSION or"Not repository version available."))
2923end
2924command_list["version"]={perms="everyone",func=ChatCommandScriptversion,desc="show the current script's repository version",argc_min=0,argc_max=0}
2925help_pages[__MODULE_NAME__].commands["version"]=command_list["version"]
2926local function ChatCommandBug(user)
2927tfm.exec.chatMessage(string.format("<vi><b>Report pshy_merge bugs at <bl><u>https://github.com/Pshy0/pshy_merge/issues/new/choose</u></bl></b></vi>"),user)
2928tfm.exec.chatMessage(string.format(
2929"<vi>You may need the following information:</vi>\nMain module name: %s\nModule count: %s\nScript version: %s\npshy_merge version: %s",
2930pshy.MAIN_MODULE_NAME,
2931#pshy.modules_list,
2932tostring(pshy.MAIN_VERSION or"No repository version available."),
2933tostring(pshy.PSHY_VERSION)
2934),user)
2935return true
2936end
2937command_list["bug"]={perms="everyone",func=ChatCommandBug,desc="show the link to report bugs",argc_min=0,argc_max=0}
2938help_pages[__MODULE_NAME__].commands["bug"]=command_list["bug"]
2939end
2940pshy.modules["pshy.enums.keycodes"].load = function()
2941
2942local keycodes={
2943LEFT=0;
2944UP=1;
2945RIGHT=2;
2946DOWN=3;
2947SHIFT=16;
2948CTRL=17;
2949ALT=18;
2950ARROW_LEFT=37;
2951ARROW_UP=38;
2952ARROW_RIGHT=39;
2953ARROW_DOWN=40;
2954NUMPAD_MULTIPLY=106;
2955NUMPAD_ADD=107;
2956NUMPAD_SUBTRACT=109;
2957NUMPAD_ENTER=108;
2958NUMPAD_DECIMAL=110;
2959NUMPAD_DIVIDE=111;
2960BACKSPACE=8;
2961TAB=9;
2962ENTER=13;
2963PAUSE=19;
2964CAPSLOCK=20;
2965ESCAPE=27;
2966SPACE=32;
2967PAGE_UP=33;
2968PAGE_DOWN=34;
2969END=35;
2970HOME=36;
2971INSERT=45;
2972DELETE=46;
2973SEMICOLON=186;
2974EQUALS=187;
2975COMMA=188;
2976HYPHEN=189;
2977PERIOD=190;
2978SLASH=191;
2979GRAVE=192;
2980LEFTBRACKET=219;
2981BACKSLASH=220;
2982RIGHTBRACKET=221;
2983}
2984for f_index=0,11 do
2985keycodes["F"..tostring(f_index+1)]=112+f_index
2986end
2987for i_letter=0,25 do
2988keycodes[string.char(65+i_letter)]=65+i_letter
2989end
2990for number=0,9 do
2991keycodes["NUMBER_"..tostring(number)]=48+number
2992end
2993for number=0,9 do
2994keycodes["NUMPAD_"..tostring(number)]=96+number
2995end
2996return keycodes
2997end
2998pshy.modules["pshy.help"].load = function()
2999local commands=pshy.require("pshy.commands")
3000local command_list=pshy.require("pshy.commands.list")
3001pshy.require("pshy.events")
3002pshy.require("pshy.ui.v1")
3003local perms=pshy.require("pshy.perms")
3004local pages=pshy.require("pshy.help.pages")
3005local ids=pshy.require("pshy.utils.ids")
3006local help={}
3007local text_id_page_list=ids.AllocTextAreaId()
3008local text_id_title_area=ids.AllocTextAreaId()
3009local text_id_main_body=ids.AllocTextAreaId()
3010local help_pages_lists={}
3011local pages_per_page_list=20
3012local players_page_list_index={}
3013function help.GetChatCommandDesc(chat_command_name)
3014local cmd=command_list[chat_command_name]
3015local desc=cmd.desc or"no description"
3016return desc
3017end
3018function help.GetChatCommandHelpHtml(command_name,is_admin)
3019local real_command=commands.GetCommand(command_name)
3020if not real_command then
3021return"<r>This command does not exist or is unavailable.</r>"
3022end
3023if real_command.restricted and not is_admin then
3024return"<r>You do not have permissions to view this.</r>"
3025end
3026local html="<j><i><b>"
3027local html=html..real_command.usage or"(no usage, error)"
3028html=html.."</b></i>\t - "..(real_command.desc and tostring(real_command.desc)or"no description")
3029if real_command.help then
3030html=html.."\n"..real_command.help
3031end
3032if not real_command.func then
3033html=html.."\nThis command is not handled by pshy_commands."
3034end
3035html=html.."</j>"
3036return html
3037end
3038function help.GetHelpPageHtmlTitleArea(page_name,is_admin)
3039local page=pages[page_name]or pages[""]
3040local html="<bv><p align='right'><font size='14'><b>"
3041html=html.." <bl><a href='event:pcmd man "..(page.back or"").."'> ↶ </a></bl>"
3042html=html.." <r><a href='event:pcmd closeman'> × </a></r> "
3043html=html.."</b></font></p>"
3044html=html.."<p align='center'><font size='16'>"..(page.title or page_name)..'</font></p>\n'
3045if not page.restricted or is_admin then
3046html=html.."<p align='center'>"..(page.text or"").."</p>"
3047end
3048html=html.."</bv>"
3049return html
3050end
3051function help.GetHelpPageHtml(page_name,is_admin)
3052local page=pages[page_name]
3053page=page or pages[""]
3054local html=""
3055local html=""
3056if page.restricted and not is_admin then
3057html=html.."<p align='center'><r>Access to this page is restricted.</r></p>\n"
3058return html
3059end
3060if page.details then
3061html=html.."<p align='center'><vp>"..page.details.."</vp></p>"
3062end
3063if page.commands then
3064html=html.."<bv><p align='center'><font size='16'>Commands".."</font></p>\n"
3065for cmd_name,cmd in pairs(page.commands)do
3066local m1,m2=commands.GetPermColorMarkups("!"..cmd_name)
3067html=html..m1
3068html=html.."<u>"..(cmd.usage or"(no usage, error)").."</u>"
3069html=html..m2
3070html=html.."\t - "..(cmd.desc or"no description").."\n"
3071end
3072html=html.."</bv>\n"
3073end
3074if page.examples then
3075html=html.."<rose><p align='center'><font size='16'>Examples".."</font> (click to run)</p>\n"
3076for ex_cmd,ex_desc in pairs(page.examples)do
3077html=html.."<j><i><a href='event:cmd "..ex_cmd.."'>!"..ex_cmd.."</a></i></j>\t - "..ex_desc..'\n'
3078end
3079html=html.."</rose>\n"
3080end
3081if page.subpages then
3082html=html.."<ch><p align='center'><font size='16'>Subpages:".."</font></p>\n<p align='center'><u>"
3083for subpage_name,subpage in pairs(page.subpages)do
3084if not subpage.restricted or is_admin then
3085if subpage and subpage.title then
3086html=html.."<a href='event:pcmd man "..subpage_name.."'>"..subpage.title.."</a>\n"
3087else
3088html=html.."<a href='event:pcmd man "..subpage_name.."'>"..subpage_name.."</a>\n"
3089end
3090end
3091end
3092html=html.."</u></p></ch>"
3093end
3094return html
3095end
3096local function ShowPagesList(user)
3097players_page_list_index[user]=players_page_list_index[user]or 1
3098local page_list_text=help_pages_lists[players_page_list_index[user]]
3099ui.addTextArea(text_id_page_list,page_list_text,user,30,40,150,340,0x010101,0x010101,0.95,true)
3100end
3101local function ChatCommandMan(user,page_name)
3102if page_name==nil then
3103page_name=""
3104end
3105local page=pages[page_name]
3106local title_area_text
3107local main_body_text
3108if page then
3109if not page.restricted or perms.admins[user]then
3110title_area_text=page and page.html_1 or help.GetHelpPageHtmlTitleArea(page_name,perms.admins[user])
3111main_body_text=page.html_2
3112else
3113title_area_text=page and page.html_1 or help.GetHelpPageHtmlTitleArea(page_name,perms.admins[user])
3114main_body_text="<p align='center'><font size='16'><r>This page is restricted.</r></font></p>"
3115end
3116elseif string.sub(page_name,1,1)=='!'then
3117main_body_text=help.GetChatCommandHelpHtml(string.sub(page_name,2,#page_name),perms.admins[user])
3118tfm.exec.chatMessage(main_body_text,user)
3119return true
3120elseif command_list[page_name]then
3121main_body_text=help.GetChatCommandHelpHtml(page_name)
3122tfm.exec.chatMessage(main_body_text,user)
3123return true
3124else
3125main_body_text=help.GetHelpPageHtml(page_name,perms.admins[user])
3126title_area_text=help.GetHelpPageHtmlTitleArea(page_name,perms.admins[user])
3127end
3128main_body_text="<font size='10'><b><n>"..main_body_text.."</n></b></font>"
3129if#main_body_text>2000 then
3130error("#html is too big: == "..tostring(#main_body_text))
3131end
3132ui.addTextArea(text_id_title_area,title_area_text,user,200,40,570,100,0x010101,0x010101,0.95,true)
3133ui.addTextArea(text_id_main_body,main_body_text,user,200,160,570,220,0x010101,0x010101,0.95,true)
3134ShowPagesList(user)
3135return true
3136end
3137command_list["man"]={aliases={"help"},perms="everyone",func=ChatCommandMan,desc="show a help panel",argc_min=0,argc_max=1,arg_types={"string"}}
3138local function ChatCommandCloseman(user,page_name)
3139ui.removeTextArea(text_id_page_list,user)
3140ui.removeTextArea(text_id_title_area,user)
3141ui.removeTextArea(text_id_main_body,user)
3142return true
3143end
3144command_list["closeman"]={aliases={"closehelp"},perms="everyone",func=ChatCommandCloseman,desc="hide the help panel",argc_min=0,argc_max=1,arg_types={"string"}}
3145local function ChatCommandNextmanlist(user,list_number)
3146if list_number<0 or list_number>#help_pages_lists then
3147return false,"No such pages list."
3148end
3149if list_number==#help_pages_lists and not perms.admins[user]then
3150return false,"Next pages are room-admin-only."
3151end
3152players_page_list_index[user]=list_number
3153ShowPagesList(user)
3154return true
3155end
3156command_list["nextmanlist"]={perms="everyone",func=ChatCommandNextmanlist,desc="show the next help pages list",argc_min=0,argc_max=1,arg_types={"number"}}
3157function eventInit()
3158local html_page_list_header="<vi><b>Help Pages:</b></vi>\n\n<ch><b><p align='center'>"
3159local html_page_list_footer="</p></b></ch>"
3160local html_page_list=html_page_list_header
3161local pages_in_list=0
3162for page_name,page in pairs(pages)do
3163if not page.back or page.back==""or page.back=="pshy"then
3164local line="<u><a href='event:pcmd help "..page_name.."'>"..(page.title or page_name).."</a></u>\n"
3165if not page.restricted then
3166pages_in_list=pages_in_list+1
3167html_page_list=html_page_list..line
3168if pages_in_list==pages_per_page_list then
3169html_page_list=html_page_list..html_page_list_footer
3170table.insert(help_pages_lists,html_page_list)
3171html_page_list=html_page_list_header
3172pages_in_list=0
3173end
3174end
3175end
3176end
3177for i=pages_in_list,pages_per_page_list-1 do
3178html_page_list=html_page_list.."\n"
3179end
3180html_page_list=html_page_list..html_page_list_footer
3181table.insert(help_pages_lists,html_page_list)
3182html_page_list="<vi><b>Admin Help Pages:</b></vi>\n\n<ch><b><p align='center'>"
3183pages_in_list=0
3184for page_name,page in pairs(pages)do
3185if not page.back or page.back==""or page.back=="pshy"then
3186if page.restricted then
3187local line="<u><a href='event:pcmd help "..page_name.."'>"..(page.title or page_name).."</a></u>\n"
3188html_page_list=html_page_list..line
3189pages_in_list=pages_in_list+1
3190end
3191end
3192end
3193for i=pages_in_list,pages_per_page_list-1 do
3194html_page_list=html_page_list.."\n"
3195end
3196html_page_list=html_page_list.."</p></b></ch>"
3197table.insert(help_pages_lists,html_page_list)
3198for i_page_list,page_list_text in ipairs(help_pages_lists)do
3199local footer="<p align='center'><font size='24'>"
3200if i_page_list>1 then
3201footer=footer..string.format("<a href='event:pcmd nextmanlist %d'><n> < </n></a>",i_page_list-1)
3202else
3203footer=footer.."<n2> < </n2>"
3204end
3205if i_page_list<#help_pages_lists then
3206footer=footer..string.format("<a href='event:pcmd nextmanlist %d'><n> > </n></a>",i_page_list+1)
3207else
3208footer=footer.."<n2> > </n2>"
3209end
3210footer=footer.."</font></p>"
3211help_pages_lists[i_page_list]=page_list_text..footer
3212end
3213for page_name,page in pairs(pages)do
3214page.html_1=help.GetHelpPageHtmlTitleArea(page_name,true)
3215page.html_2=help.GetHelpPageHtml(page_name,true)
3216end
3217end
3218return help
3219end
3220pshy.modules["pshy.images.addimage"].load = function()
3221local images=pshy.require("pshy.images.list")
3222local addimage={}
3223function addimage.AddImage(image_name,target,center_x,center_y,player_name,width,height,angle,alpha)
3224if image_name=="none"then
3225return nil
3226end
3227local image=images[image_name]or images["15568238225.png"]
3228if image.left then
3229width=-width
3230end
3231target=target or"!0"
3232width=width or image.w
3233height=height or image.h or image.w
3234local x=center_x+((width>0)and 0 or math.abs(width))local y=center_y+((height>0)and 0 or math.abs(height))local sx=width/(image.w)
3235local sy=height/(image.h or image.w)
3236local anchor_x,anchor_y=image.ax or 0.5,image.ay or 0.5
3237return tfm.exec.addImage(image_name,target,x,y,player_name,sx,sy,angle,alpha,anchor_x,anchor_y)
3238end
3239function addimage.AddImageMin(image_name,target,center_x,center_y,player_name,min_width,min_height,angle,alpha)
3240if image_name=="none"then
3241return nil
3242end
3243local image=images[image_name]or images["15568238225.png"]
3244if image.left then
3245width=-width
3246end
3247target=target or"!0"
3248local xsign=min_width/(math.abs(min_width))
3249local ysign=min_height/(math.abs(min_height))
3250width=min_width or image.w
3251height=min_height or image.h or image.w
3252local sx=width/(image.w)
3253local sy=height/(image.h or image.w)
3254local sboth=math.max(math.abs(sx),math.abs(sy))
3255width=image.w*sboth*xsign
3256height=(image.h or image.w)*sboth*ysign
3257local x=center_x+((width>0)and 0 or math.abs(width))local y=center_y+((height>0)and 0 or math.abs(height))local anchor_x,anchor_y=image.ax or 0.5,image.ay or 0.5
3258return tfm.exec.addImage(image_name,target,x,y,player_name,sboth*xsign,sboth,angle,alpha,anchor_x,anchor_y)
3259end
3260return addimage
3261end
3262pshy.modules["pshy.images.searchimage"].load = function()
3263local __MODULE_NAME__ = "pshy.images.searchimage"
3264local command_list=pshy.require("pshy.commands.list")
3265local help_pages=pshy.require("pshy.help.pages")
3266local images=pshy.require("pshy.images.list")
3267local utils_strings=pshy.require("pshy.utils.strings")
3268help_pages[__MODULE_NAME__]={back="pshy",title="Image Search",text="Search for an image.\n",commands={}}
3269help_pages["pshy"].subpages[__MODULE_NAME__]=help_pages[__MODULE_NAME__]
3270local searchimage={}
3271searchimage.max_search_results=20
3272function searchimage.IsOriented(image)
3273if type(image)=="string"then
3274image=images[image]
3275end
3276assert(type(image)=="table","wrong type "..type(image))
3277if image.oriented~=nil then
3278return image.oriented
3279end
3280if image.meme or image.emoticon or image.w<=30 then
3281return false
3282end
3283return true
3284end
3285function searchimage.Search(words)
3286local results={}
3287for image_name,image in pairs(images)do
3288local not_matching=false
3289for i_word,word in pairs(words)do
3290if not string.find(image.desc,word)and not image[word]then
3291not_matching=true
3292break
3293end
3294end
3295if not not_matching then
3296table.insert(results,image_name)
3297end
3298end
3299return results
3300end
3301local function ChatCommandSearchimage(user,word)
3302local words=utils_strings.Split(word,' ',5)
3303if#words>=5 then
3304return false,"You can use at most 4 words per search!"
3305end
3306if#words==1 and#words[1]<=1 then
3307return false,"Please perform a more accurate search!"
3308end
3309local image_names=searchimage.Search(words)
3310if#image_names==0 then
3311tfm.exec.chatMessage("No image found.",user)
3312else
3313for i_image,image_name in pairs(image_names)do
3314if i_image>searchimage.max_search_results then
3315tfm.exec.chatMessage("+ "..tostring(#image_names-searchimage.max_search_results),user)
3316break
3317end
3318local image=images[image_name]
3319tfm.exec.chatMessage(image_name.."\t - "..tostring(image.desc).." ("..tostring(image.w)..","..tostring(image.w or image.h)..")",user)
3320end
3321end
3322return true
3323end
3324command_list["searchimage"]={perms="cheats",func=ChatCommandSearchimage,desc="search for an image",argc_min=1,argc_max=1,arg_types={"string"}}
3325help_pages[__MODULE_NAME__].commands["searchimage"]=command_list["searchimage"]
3326return searchimage
3327end
3328pshy.modules["pshy.commands.get_target_or_error"].load = function()
3329local perms=pshy.require("pshy.perms")
3330local function GetTargetOrError(user,target,perm_prefix)
3331if not target then
3332return user
3333end
3334if target==user then
3335return user
3336elseif not perms.HavePerm(user,perm_prefix.."-others")then
3337error("You do not have permission to use this command on others.")
3338return
3339end
3340return target
3341end
3342return GetTargetOrError
3343end
3344pshy.modules["pshy.images.changeimage"].load = function()
3345local __MODULE_NAME__ = "pshy.images.changeimage"
3346local addimage=pshy.require("pshy.images.addimage")
3347local searchimage=pshy.require("pshy.images.searchimage")
3348local command_list=pshy.require("pshy.commands.list")
3349pshy.require("pshy.events")
3350local help_pages=pshy.require("pshy.help.pages")
3351local utils_strings=pshy.require("pshy.utils.strings")
3352local images=pshy.require("pshy.images.list")
3353local changeimage={}
3354help_pages[__MODULE_NAME__]={back="pshy",title="Image Change",text="Change your image.\n",commands={}}
3355help_pages["pshy"].subpages[__MODULE_NAME__]=help_pages[__MODULE_NAME__]
3356pshy.changesize_keep_changes_on_new_game=true
3357local players={}
3358local GetTarget=pshy.require("pshy.commands.get_target_or_error")
3359function changeimage.RemoveImage(player_name)
3360if players[player_name].image_id then
3361tfm.exec.removeImage(players[player_name].image_id)
3362end
3363players[player_name]=nil
3364tfm.exec.changePlayerSize(player_name,0.9)
3365tfm.exec.changePlayerSize(player_name,1.0)
3366end
3367function changeimage.UpdateImage(player_name)
3368local player=players[player_name]
3369local orientation=player.player_orientation or 1
3370if not searchimage.IsOriented(player.image_name)then
3371orientation=1
3372end
3373if player.image_id and player.image_orientation==orientation then
3374return
3375end
3376local old_image_id=player.image_id
3377player.image_id=addimage.AddImageMin(player.image_name,"%"..player_name,0,0,nil,40*orientation,30,0.0,1.0)
3378player.image_orientation=orientation
3379if old_image_id then
3380tfm.exec.removeImage(old_image_id)
3381end
3382end
3383function changeimage.ChangeImage(player_name,image_name)
3384players[player_name]=players[player_name]or{}
3385local player=players[player_name]
3386if player.image_id then
3387tfm.exec.removeImage(player.image_id)
3388player.image_id=nil
3389end
3390player.image_name=nil
3391if image_name then
3392system.bindKeyboard(player_name,0,true,true)
3393system.bindKeyboard(player_name,2,true,true)
3394player.image_name=image_name
3395player.player_orientation=(tfm.get.room.playerList[player_name].isFacingRight)and 1 or-1
3396player.available_update_count=2
3397changeimage.UpdateImage(player_name)
3398else
3399changeimage.RemoveImage(player_name)
3400end
3401end
3402function eventKeyboard(player_name,keycode,down,x,y)
3403if down and(keycode==0 or keycode==2)then
3404local player=players[player_name]
3405if not player or player.available_update_count<=0 then
3406return
3407end
3408player.available_update_count=player.available_update_count-1
3409player.player_orientation=(keycode==2)and 1 or-1
3410changeimage.UpdateImage(player_name)
3411end
3412end
3413function eventPlayerRespawn(player_name)
3414if players[player_name]then
3415changeimage.UpdateImage(player_name)
3416end
3417end
3418function eventNewGame()
3419for player_name in pairs(tfm.get.room.playerList)do
3420if players[player_name]then
3421players[player_name].image_id=nil
3422end
3423end
3424if pshy.changesize_keep_changes_on_new_game then
3425for player_name in pairs(tfm.get.room.playerList)do
3426if players[player_name]then
3427changeimage.UpdateImage(player_name)
3428end
3429end
3430end
3431end
3432function eventPlayerDied(player_name)
3433if players[player_name]then
3434players[player_name].image_id=nil
3435end
3436end
3437function eventLoop(time,time_remaining)
3438for player_name,player in pairs(players)do
3439player.available_update_count=2
3440end
3441end
3442local function ChatCommandChangeimage(user,image_name,target)
3443target=GetTarget(user,target,"!changeimage")
3444local image=images[image_name]
3445if image_name=="off"then
3446changeimage.ChangeImage(target,nil)
3447return
3448end
3449if not image then
3450return false,"Unknown or not approved image."
3451end
3452if not image.w then
3453return false,"This image cannot be used (unknown width)."
3454end
3455if image.w>400 or(image.h and image.h>400)then
3456return false,"This image is too big (w/h > 400)."
3457end
3458changeimage.ChangeImage(target,image_name)
3459return true,"Image changed!"
3460end
3461command_list["changeimage"]={perms="cheats",func=ChatCommandChangeimage,desc="change your image",argc_min=1,argc_max=2,arg_types={"string","player"}}
3462help_pages[__MODULE_NAME__].commands["changeimage"]=command_list["changeimage"]
3463local function ChatCommandRandomchangeimage(user,words)
3464words=utils_strings.Split(words,' ',4)
3465local image_names=searchimage.Search(words)
3466return ChatCommandChangeimage(user,image_names[math.random(#image_names)])
3467end
3468command_list["randomchangeimage"]={perms="cheats",func=ChatCommandRandomchangeimage,desc="change your image to a random image matching a search",argc_min=1,argc_max=1,arg_types={"string"}}
3469help_pages[__MODULE_NAME__].commands["randomchangeimage"]=command_list["randomchangeimage"]
3470local function ChatCommandRandomchangeimageeveryone(user,words)
3471local words=utils_strings.Split(words,' ',4)
3472local image_names=searchimage.Search(words)
3473local r1,r2
3474for player_name in pairs(tfm.get.room.playerList)do
3475r1,r2=ChatCommandChangeimage(player_name,image_names[math.random(#image_names)])
3476if r1==false then
3477return r1,r2
3478end
3479end
3480return true,"All images changed!"
3481end
3482command_list["randomchangeimages"]={perms="admins",func=ChatCommandRandomchangeimageeveryone,desc="change everyone's image to a random image matching a search",argc_min=1,argc_max=1,arg_types={"string"}}
3483help_pages[__MODULE_NAME__].commands["randomchangeimages"]=command_list["randomchangeimages"]
3484return changeimage
3485end
3486pshy.modules["pshy.utils.rotation"].load = function()
3487
3488local Rotation={
3489items={},next_indices={},is_random=true,}
3490Rotation.__index=Rotation
3491function Rotation:New(o)
3492assert(self==Rotation)
3493local o=o or{}
3494o.items=o.items or{}
3495o.next_indices=o.next_indices or{}
3496setmetatable(o,self)
3497return o
3498end
3499function Rotation:Reset()
3500assert(self~=Rotation)
3501self.next_indices={}
3502if#self.items>0 then
3503local table_insert=table.insert
3504local next_indices=self.next_indices
3505for i=1,#self.items do
3506table_insert(next_indices,i)
3507end
3508end
3509end
3510function Rotation:IndexOf(search_item)
3511assert(self~=Rotation)
3512for i_item,item in ipairs(self.items)do
3513if item==search_item then
3514return i_item
3515end
3516end
3517end
3518function Rotation:SkipIndex(index)
3519assert(self~=Rotation)
3520table.remove(self.next_indices,index)
3521if not self.is_random then
3522self.next_indices={}
3523if#self.items>0 then
3524local table_insert=table.insert
3525local next_indices=self.next_indices
3526for i=index+1,#self.items do
3527table_insert(next_indices,i)
3528end
3529end
3530end
3531end
3532function Rotation:SkipItem(item)
3533assert(self~=Rotation)
3534local index=self:IndexOf(item)
3535if index then
3536return self:SkipIndex(index)
3537end
3538end
3539function Rotation:Next()
3540assert(self~=Rotation)
3541if#self.items==0 then
3542return nil
3543end
3544self.next_indices=self.next_indices or{}
3545if#self.next_indices==0 then
3546self:Reset()
3547end
3548local i_index=(self.is_random==false)and 1 or math.random(#self.next_indices)
3549local item=self.items[self.next_indices[i_index]]
3550table.remove(self.next_indices,i_index)
3551return item
3552end
3553return Rotation
3554end
3555pshy.modules["pshy.maps.list"].load = function()
3556
3557local maps={}
3558maps["test"]={author="Test#0801",title="Test Map",title_color="#ff7700",background_color="#FF00FF",xml=[[<C><P F="0" shaman_tools="1,33,102,110,111,202,302,402,608,1002,2802,2,2806" MEDATA=";;;;-0;0:::1-"/><Z><S><S T="6" X="400" Y="250" L="120" H="40" P="0,0,0.3,0.2,0,0,0,0"/></S><D><F X="432" Y="218"/><P X="393" Y="230" T="11" P="0,0"/><DC X="362" Y="213"/><DS X="436" Y="107"/></D><O/><L/></Z></C>]]}
3559maps["error_map"]={author="Error",duration=20,title="an error happened",xml=7893612}
3560return maps
3561end
3562pshy.modules["pshy.rotations.list"].load = function()
3563
3564local rotations={}
3565pshy.mapdb_rotation_aliases={}
3566function pshy.mapdb_GetRotation(rotation_name)
3567while pshy.mapdb_rotation_aliases[rotation_name]do
3568rotation_name=pshy.mapdb_rotation_aliases[rotation_name]
3569end
3570return rotations[rotation_name]
3571end
3572function eventInit()
3573for rotation_name,rotation in pairs(rotations)do
3574rotation.name=rotation.name or rotation_name
3575end
3576end
3577return rotations
3578end
3579pshy.modules["pshy.rotations.list.transformice"].load = function()
3580local Rotation=pshy.require("pshy.utils.rotation")
3581local rotations=pshy.require("pshy.rotations.list")
3582local maps_vanilla={}
3583local deleted_vanilla_maps={[29]=true,[108]=true,[110]=true,[111]=true,[112]=true,[113]=true,[135]=true,[169]=true,[193]=true,[194]=true,[195]=true,[196]=true,[197]=true,[198]=true,[199]=true}
3584for i=0,227 do
3585if not deleted_vanilla_maps[i]then
3586table.insert(maps_vanilla,i)
3587end
3588end
3589rotations["vanilla"]=Rotation:New({desc="0-210",duration=120,items=maps_vanilla})
3590rotations["P0"]=Rotation:New({desc="P0 - standard",duration=120,items={"#0"}})
3591rotations["P1"]=Rotation:New({desc="P1 - protected",duration=120,items={"#1"}})
3592rotations["P4"]=Rotation:New({desc="P4 - shaman",duration=120,items={"#4"}})
3593rotations["P5"]=Rotation:New({desc="P5 - art",duration=120,items={"#5"}})
3594rotations["P6"]=Rotation:New({desc="P6 - mechanisms",duration=120,items={"#6"}})
3595rotations["P7"]=Rotation:New({desc="P7 - no shaman",duration=60,shamans=0,items={"#7"}})
3596rotations["P8"]=Rotation:New({desc="P8 - dual shaman",duration=60,shamans=0,items={"#8"}})
3597rotations["P9"]=Rotation:New({desc="P9 - miscellaneous",duration=60,shamans=0,items={"#9"}})
3598rotations["P17"]=Rotation:New({desc="P17 - racing",duration=60,shamans=0,items={"#17"}})
3599rotations["P18"]=Rotation:New({desc="P18 - defilante",duration=60,shamans=0,items={"#18"}})
3600rotations["P38"]=Rotation:New({desc="P38 - racing test",duration=60,shamans=0,items={"#38"}})
3601rotations["P66"]=Rotation:New({desc="P66 - thematic",duration=60,shamans=0,items={"#66"}})
3602rotations["transformice"]=Rotation:New({is_random=false,items={"vanilla","#4","#9","#5","#1","vanilla","#8","#6","#7","#0"}})
3603pshy.mapdb_rotation_aliases["standard"]="P0"
3604pshy.mapdb_rotation_aliases["protected"]="P1"
3605pshy.mapdb_rotation_aliases["shaman"]="P4"
3606pshy.mapdb_rotation_aliases["art"]="P5"
3607pshy.mapdb_rotation_aliases["mechanisms"]="P6"
3608pshy.mapdb_rotation_aliases["nosham"]="P7"
3609pshy.mapdb_rotation_aliases["no_shaman"]="P7"
3610pshy.mapdb_rotation_aliases["dual_shaman"]="P8"
3611pshy.mapdb_rotation_aliases["misc"]="P9"
3612pshy.mapdb_rotation_aliases["miscellaneous"]="P9"
3613pshy.mapdb_rotation_aliases["racing"]="P17"
3614pshy.mapdb_rotation_aliases["defilante"]="P18"
3615pshy.mapdb_rotation_aliases["racing_test"]="P38"
3616pshy.mapdb_rotation_aliases["thematic"]="P66"
3617return rotations
3618end
3619pshy.modules["pshy.rotations.newgame.settings_override"].load = function()
3620
3621local namespace={}
3622tfm.exec.disableAutoNewGame(true)
3623tfm.exec.disableAutoTimeLeft(true)
3624namespace.OriginalTFMDisableAutoNewGame=tfm.exec.disableAutoNewGame
3625namespace.OriginalTFMDisableAutoTimeLeft=tfm.exec.disableAutoTimeLeft
3626namespace.OriginalTFMDisableAutoShaman=tfm.exec.disableAutoShaman
3627namespace.OriginalTFMDisableAfkDeath=tfm.exec.disableAfkDeath
3628namespace.auto_new_game=true
3629namespace.auto_time_left=true
3630namespace.auto_shaman=true
3631namespace.afk_death=true
3632tfm.exec.disableAutoNewGame=function(disabled)
3633namespace.auto_new_game=((disabled~=nil)and not disabled)or false
3634end
3635tfm.exec.disableAutoTimeLeft=function(disabled)
3636namespace.auto_time_left=((disabled~=nil)and not disabled)or false
3637end
3638tfm.exec.disableAutoShaman=function(disabled)
3639namespace.auto_shaman=((disabled~=nil)and not disabled)or false
3640end
3641tfm.exec.disableAfkDeath=function(disabled)
3642namespace.afk_death=((disabled~=nil)and not disabled)or false
3643return namespace.OriginalTFMDisableAfkDeath(disabled)
3644end
3645return namespace
3646end
3647pshy.modules["pshy.rotations.newgame"].load = function()
3648local __MODULE_NAME__ = "pshy.rotations.newgame"
3649local command_list=pshy.require("pshy.commands.list")
3650pshy.require("pshy.events")
3651local help_pages=pshy.require("pshy.help.pages")
3652pshy.require("pshy.utils.print")
3653local Rotation=pshy.require("pshy.utils.rotation")
3654pshy.require("pshy.moduleswitch")
3655local utils_tables=pshy.require("pshy.utils.tables")
3656local utils_tfm=pshy.require("pshy.utils.tfm")
3657local maps=pshy.require("pshy.maps.list")
3658local rotations=pshy.require("pshy.rotations.list")
3659pshy.require("pshy.rotations.list.transformice")
3660local mapinfo=pshy.require("pshy.rotations.mapinfo",false)
3661local perms=pshy.require("pshy.perms")
3662local room=pshy.require("pshy.room")
3663local newgame_settings_override=pshy.require("pshy.rotations.newgame.settings_override")
3664local newgame={}
3665help_pages[__MODULE_NAME__]={back="pshy",title="Rotations",text="Replaces tfm.exec.newGame, adding features.\n",commands={}}
3666help_pages["pshy"].subpages[__MODULE_NAME__]=help_pages[__MODULE_NAME__]
3667newgame.default="default"rotations["default"]=Rotation:New({hidden=true,items={"transformice"}})newgame.default_rotation=rotations["default"]
3668newgame.delay_next_map=false
3669newgame.error_map="error_map"
3670newgame.update_map_name_on_new_player=true
3671local autorespawn=false
3672local respawning_players={}
3673newgame.event_new_game_triggered=false
3674local newgame_called=false
3675local players_alive_changed=false
3676local newgame_time=os.time()-3001
3677local newgame_too_early_notified=false
3678local newgame_last_call_arg=nil
3679local current_map_input=nil
3680local previous_map_input=nil
3681local player_recently_joined=false
3682newgame.loading_map_identifying_name=nil newgame.loading_map_numeric_code=nil newgame.loading_rotations={}
3683local loading_rotation_names={}newgame.loading_map=nil
3684newgame.loading_map_settings={}local map_loading_failure_displayed=false
3685newgame.current_map_identifying_name=tfm.get.room.currentMap
3686newgame.current_map_numeric_code=nil
3687newgame.current_rotations={}
3688newgame.current_map=nil
3689newgame.current_map_settings={}
3690local current_map_display_name=nil local current_map_modules=nil
3691local next_map_input=nil local force_next_map_input=false
3692local function DisableEnabledModules()
3693if current_map_modules then
3694for i,module_name in ipairs(current_map_modules)do
3695pshy.DisableModule(module_name)
3696end
3697current_map_modules=nil
3698end
3699end
3700local function EnableLoadingMapModules()
3701DisableEnabledModules()
3702if newgame.loading_map_settings.modules then
3703for i,module_name in ipairs(newgame.loading_map_settings.modules)do
3704pshy.EnableModule(module_name)
3705end
3706current_map_modules=newgame.loading_map_settings.modules
3707end
3708end
3709local tfm_exec_newGame=tfm.exec.newGame
3710local FinallyNewGame=function(mapcode,...)
3711EnableLoadingMapModules()
3712if newgame_called then
3713print_warn("newgame: tfm.exec.newGame was called while the game was already loading a new map.")
3714end
3715if type(mapcode)=="string"and string.find(mapcode,"<",1,true)~=1 and string.find(mapcode,"#",1,true)~=1 and string.find(mapcode,"@",1,true)~=1 and not tonumber(mapcode)then
3716print_warn("newgame: invalid rotation `%s`",mapcode)
3717return
3718end
3719if os.time()-newgame_time<3001 then
3720if not newgame_too_early_notified then
3721print_error("newgame: tfm.exec.newGame called < 3000ms since last call (single warn).")
3722newgame_too_early_notified=true
3723end
3724return
3725else
3726newgame_too_early_notified=false
3727end
3728newgame_time=os.time()
3729newgame_called=true
3730newgame_last_call_arg=mapcode
3731newgame.loading_map_settings.map_code=mapcode
3732return tfm_exec_newGame(mapcode,...)
3733end
3734local function CallBeginFuncs()
3735for i_rot,rot in ipairs(newgame.current_rotations)do
3736if rot.begin_func then
3737rot.begin_func(newgame.current_map_identifying_name)
3738end
3739end
3740if newgame.current_map and newgame.current_map.begin_func then
3741rot.begin_func(newgame.current_map_identifying_name)
3742end
3743end
3744local function CallEndFuncs()
3745if newgame.current_map and newgame.current_map.end_func then
3746rot.end_func(newgame.current_map_identifying_name)
3747end
3748for i_rot,rot in ipairs(newgame.current_rotations)do
3749if rot.end_func then
3750rot.end_func(newgame.current_map_identifying_name)
3751end
3752end
3753end
3754local function EndMap()
3755CallEndFuncs()
3756if eventGameEnded then
3757eventGameEnded()
3758end
3759newgame_settings_override.OriginalTFMDisableAutoShaman(not newgame_settings_override.auto_shaman)
3760DisableEnabledModules()
3761end
3762local function ResetLoading()
3763newgame_settings_override.OriginalTFMDisableAutoShaman(not newgame_settings_override.auto_shaman)
3764loading_rotation_names={}
3765newgame.loading_rotations={}
3766newgame.loading_map=nil
3767newgame.loading_map_identifying_name=nil
3768newgame.loading_map_numeric_name=nil
3769newgame.loading_map_settings={}
3770end
3771local function AbortLoading()
3772ResetLoading()
3773end
3774tfm.exec.newGame=function(mapcode,...)
3775if os.time()<=newgame_time+3000 then
3776print_error("You must wait 3000 ms before calling `tfm.exec.newGame`.")
3777return
3778end
3779EndMap()
3780newgame.event_new_game_triggered=false
3781return newgame._Next(mapcode,...)
3782end
3783local function SkipFromRotations(mapcode)
3784for i,rotation_name in ipairs(newgame.default_rotation.items)do
3785local rotation=rotations[rotation_name]
3786if rotation then
3787rotation:SkipItem(mapcode)
3788end
3789end
3790end
3791local function AddCustomMapSettings(t)
3792for p,v in pairs(t)do
3793if type(v)=="table"then
3794newgame.loading_map_settings[p]=newgame.loading_map_settings[p]or{}
3795if type(newgame.loading_map_settings[p])=="table"then
3796for i_vv,vv in ipairs(v)do
3797table.insert(newgame.loading_map_settings[p],vv)
3798end
3799end
3800else
3801newgame.loading_map_settings[p]=v
3802end
3803end
3804if t.shamans~=nil then
3805assert(t.shamans==0,"only a shaman count of 0 or nil is supported yet")
3806newgame_settings_override.OriginalTFMDisableAutoShaman(true)
3807end
3808end
3809local function LoadDBRotation(rotation_name,rotation)
3810if rotation.items==nil then
3811print_error("Empty rotation!")
3812AbortLoading()
3813return tfm.exec.newGame(newgame.error_map)
3814end
3815rotation_name=rotation.name or rotation_name if loading_rotation_names[rotation_name]then
3816print_error("Cyclic map rotation (%s)!",rotation_name)
3817AbortLoading()
3818return tfm.exec.newGame(newgame.error_map)
3819end
3820loading_rotation_names[rotation_name]=true
3821table.insert(newgame.loading_rotations,rotation)
3822AddCustomMapSettings(rotation)
3823local next_map_name=rotation:Next()
3824return newgame._Next(next_map_name)
3825end
3826local function LoadDBMap(map_name,map)
3827newgame.loading_map_numeric_code=map_name
3828newgame.loading_map=map
3829AddCustomMapSettings(map)
3830local map_xml
3831if map.xml then
3832map_xml=map.xml
3833tfm.get.room.xmlMapInfo={}
3834tfm.get.room.xmlMapInfo.author=map.author
3835else
3836map_xml=map_name
3837end
3838if newgame.loading_map_settings.replace_func then
3839local rst
3840rst,map_xml=pcall(newgame.loading_map_settings.replace_func,map_xml)
3841if not rst then
3842print_error(map_xml)
3843AbortLoading()
3844return tfm.exec.newGame(newgame.error_map)
3845end
3846end
3847return FinallyNewGame(map_xml)
3848end
3849local function NextCategoryMapCode(category)
3850newgame.loading_map_identifying_name=nil
3851newgame.loading_map_numeric_code=nil
3852FinallyNewGame(category)
3853end
3854local function LoadXMLMapCode(xml)
3855newgame.loading_map_identifying_name=nil
3856newgame.loading_map_numeric_code=nil
3857FinallyNewGame(xml)
3858end
3859local function LoadAtMapCode(at_map_code)
3860newgame.loading_map_numeric_code=tonumber(string.sub(at_map_code,2))
3861FinallyNewGame(at_map_code)
3862end
3863local function LoadNumericMapCode(numeric_map_code)
3864if numeric_map_code>=1000 then
3865newgame.loading_map_identifying_name=string.format("@%d",numeric_map_code)
3866end
3867FinallyNewGame(numeric_map_code)
3868end
3869function newgame._Next(mapcode)
3870if mapcode==nil or force_next_map_input then
3871if next_map_input then
3872mapcode=next_map_input
3873if type(mapcode)=="string"and#mapcode<64 then
3874SkipFromRotations(mapcode)
3875end
3876else
3877mapcode=newgame.default
3878end
3879end
3880force_next_map_input=false
3881next_map_input=nil
3882if string.sub(mapcode,1,1)=="<"then
3883return LoadXMLMapCode(mapcode)
3884end
3885newgame.loading_map_numeric_code=mapcode
3886newgame.loading_map_identifying_name=mapcode
3887local db_map=maps[mapcode]
3888if db_map then
3889return LoadDBMap(mapcode,db_map)
3890end
3891local db_rotation=pshy.mapdb_GetRotation(mapcode)
3892if db_rotation then
3893return LoadDBRotation(mapcode,db_rotation)
3894end
3895if string.sub(mapcode,1,1)=="@"then
3896return LoadAtMapCode(mapcode)
3897end
3898if string.sub(mapcode,1,1)=="#"then
3899return NextCategoryMapCode(mapcode)
3900end
3901local mapcode_number=tonumber(mapcode)
3902if mapcode_number then
3903return LoadNumericMapCode(mapcode_number)
3904end
3905print_error("Invalid Map!")
3906AbortLoading()
3907return tfm.exec.newGame(newgame.error_map)
3908end
3909function newgame.RefreshMapName()
3910current_map_display_name=nil
3911local author=newgame.current_map_settings.author or(mapinfo and mapinfo.mapinfo and mapinfo.mapinfo.author)or(tfm.get.room.xmlMapInfo and tfm.get.room.xmlMapInfo.author)
3912local title=newgame.current_map_settings.title or(mapinfo and mapinfo.mapinfo and mapinfo.mapinfo.title)or newgame.current_map_settings.map_name or newgame.current_map_identifying_name
3913if author or title then
3914local full_map_name=""
3915local title_color=newgame.current_map_settings.title_color or(mapinfo and mapinfo.mapinfo and mapinfo.mapinfo.title_color)
3916if author then
3917full_map_name=full_map_name..author
3918end
3919title=title or newgame.current_map_settings.map_name
3920if mapinfo and mapinfo.mapinfo and not title then
3921title=mapinfo.mapinfo.current_map
3922end
3923if title then
3924if author then
3925full_map_name=full_map_name.."<bl> - "
3926end
3927if title_color then
3928full_map_name=full_map_name..string.format('<font color="%s">',title_color)
3929end
3930full_map_name=full_map_name..title
3931if title_color then
3932full_map_name=full_map_name.."</font>"
3933end
3934end
3935current_map_display_name=full_map_name
3936ui.setMapName(current_map_display_name)
3937end
3938end
3939function newgame.SetNextMap(code,force)
3940next_map_input=code
3941force_next_map_input=force or false
3942end
3943function newgame.SetRotation(rotname)
3944if not pshy.mapdb_GetRotation(rotname)then
3945return false,string.format("Rotation %s does not exist!",rotname)
3946end
3947newgame.default_rotation.items={}
3948if rotname then
3949table.insert(newgame.default_rotation.items,rotname)
3950return true,string.format("Disabled all rotations and enabled %s.",rotname)
3951end
3952return true,"Disabled all rotations."
3953end
3954function eventNewGame()
3955map_loading_failure_displayed=false
3956respawning_players={}
3957local loaded_map_input=newgame.loading_map_identifying_name or tfm.get.room.currentMap
3958if(loaded_map_input~=current_map_input)then
3959previous_map_input=current_map_input
3960current_map_input=loaded_map_input
3961end
3962newgame.loading_map_numeric_code=nil
3963newgame_called=false
3964newgame.current_rotations=newgame.loading_rotations
3965newgame.current_map=newgame.loading_map
3966newgame.current_map_identifying_name=newgame.loading_map_identifying_name or tfm.get.room.currentMap
3967newgame.current_map_numeric_code=newgame.loading_map_numeric_code
3968newgame.current_map_settings=newgame.loading_map_settings
3969ResetLoading()
3970local current_map=tostring(tfm.get.room.currentMap)
3971if string.sub(current_map,1,1)=="@"then
3972current_map=string.sub(current_map,2)
3973end
3974current_map=tonumber(current_map)
3975if tfm.get.room.xmlMapInfo and current_map~=tfm.get.room.xmlMapInfo.mapCode then
3976tfm.get.room.xmlMapInfo=nil
3977end
3978local trusted=perms.IsTrustedMap()
3979if not newgame.event_new_game_triggered then
3980CallBeginFuncs()
3981if newgame.current_map_settings.duration then
3982tfm.exec.setGameTime(newgame.current_map_settings.duration+3,true)
3983end
3984if newgame.current_map_settings.background_color then
3985ui.setBackgroundColor(newgame.current_map_settings.background_color)
3986end
3987if mapinfo and mapinfo.mapinfo and mapinfo.mapinfo.background_images and mapinfo.mapinfo.foreground_images then
3988if trusted then
3989for i_img,img in ipairs(mapinfo.mapinfo.background_images)do
3990tfm.exec.addImage(img.image,"?0",img.x,img.y)
3991end
3992for i_img,img in ipairs(mapinfo.mapinfo.foreground_images)do
3993tfm.exec.addImage(img.image,"!0",img.x,img.y)
3994end
3995end
3996end
3997newgame.RefreshMapName()
3998else
3999print_error("TFM bypassed the newGame override, did you use `/np %s`?",tostring(tfm.get.room.currentMap))
4000EndMap()
4001if newgame.current_map_settings.map then
4002newgame_settings_override.OriginalTFMDisableAutoShaman(false)
4003end
4004end
4005newgame.event_new_game_triggered=true
4006players_alive_changed=false
4007end
4008function eventLoop(time,time_remaining)
4009if newgame_called then
4010local loading_name=newgame.loading_map_numeric_code
4011if time_remaining<=0 and not map_loading_failure_displayed then
4012print_error("Map %s may have failed to load.",(#tostring(loading_name)<=24)and tostring(loading_name)or string.format("(#%d input)",#tostring(loading_name)))
4013map_loading_failure_displayed=true
4014end
4015end
4016if time_remaining<=400 and time>3000 then
4017if(newgame.current_map_settings.autoskip~=false and newgame_settings_override.auto_new_game)or newgame.current_map_settings.autoskip then
4018tfm.exec.setGameTime(4,true)
4019tfm.exec.newGame(nil)
4020end
4021end
4022for player_name in pairs(respawning_players)do
4023tfm.exec.respawnPlayer(player_name)
4024end
4025respawning_players={}
4026if newgame_called then
4027return
4028end
4029if players_alive_changed then
4030if not autorespawn then
4031local players_alive=utils_tfm.CountPlayersAlive()
4032if players_alive==0 then
4033if(newgame.current_map_settings.autoskip~=false and newgame_settings_override.auto_new_game)or newgame.current_map_settings.autoskip then
4034tfm.exec.setGameTime(5,false)
4035if not newgame.delay_next_map then
4036tfm.exec.setGameTime(4,true)
4037tfm.exec.newGame(nil)
4038end
4039end
4040elseif players_alive<3 and newgame_settings_override.auto_time_left then
4041tfm.exec.setGameTime(20,false)
4042end
4043end
4044players_alive_changed=false
4045end
4046if player_recently_joined then
4047if newgame.update_map_name_on_new_player then
4048if newgame.current_map_settings.background_color then
4049ui.setBackgroundColor(newgame.current_map_settings.background_color)
4050end
4051if current_map_display_name then
4052ui.setMapName(current_map_display_name)
4053end
4054end
4055player_recently_joined=false
4056end
4057end
4058function eventNewPlayer(player_name)
4059player_recently_joined=true
4060if newgame.update_map_name_on_new_player then
4061if mapinfo and mapinfo.mapinfo and mapinfo.mapinfo.background_images and mapinfo.mapinfo.foreground_images then
4062for i_img,img in ipairs(mapinfo.mapinfo.background_images)do
4063tfm.exec.addImage(img.image,"?0",img.x,img.y,player_name)
4064end
4065for i_img,img in ipairs(mapinfo.mapinfo.foreground_images)do
4066tfm.exec.addImage(img.image,"!0",img.x,img.y,player_name)
4067end
4068end
4069end
4070end
4071function eventPlayerDied(player_name)
4072tfm.get.room.playerList[player_name].isDead=true
4073if autorespawn then
4074respawning_players[player_name]=true
4075return
4076else
4077players_alive_changed=true
4078end
4079end
4080function eventPlayerWon(player_name)
4081tfm.get.room.playerList[player_name].isDead=true
4082if autorespawn then
4083respawning_players[player_name]=true
4084return
4085else
4086players_alive_changed=true
4087end
4088end
4089function eventInit()
4090current_map_input=tfm.get.room.currentMap
4091end
4092local function ChatCommandNext(user,code,force)
4093newgame.SetNextMap(code,force)
4094return true,string.format("The next map or rotation will be %s.",code)
4095end
4096command_list["next"]={aliases={"np","npp"},perms="admins",func=ChatCommandNext,desc="set the next map to play (no param to cancel)",argc_min=1,argc_max=2,arg_types={"string","bool"},arg_names={"map code","force"}}
4097help_pages[__MODULE_NAME__].commands["next"]=command_list["next"]
4098local function ChatCommandPrevious(user)
4099return true,string.format("The previous non-xml map was %s.",tostring(previous_map_input))
4100end
4101command_list["previous"]={perms="everyone",func=ChatCommandPrevious,desc="get the previous map's code",argc_min=0,argc_max=0}
4102help_pages[__MODULE_NAME__].commands["previous"]=command_list["previous"]
4103local function ChatCommandSkip(user,code)
4104next_map_input=code or next_map_input
4105force_next_map_input=code~=nil
4106if not next_map_input and#newgame.default_rotation.items==0 then
4107return false,"First use !rotw to set the rotations you want to use (use !rots for a list)."
4108end
4109tfm.exec.setGameTime(0,false)
4110tfm.exec.newGame(next_map_input)
4111return true
4112end
4113command_list["skip"]={aliases={"map"},perms="admins",func=ChatCommandSkip,desc="play a different map right now",argc_min=0,argc_max=1,arg_types={"string"},arg_names={"map code"}}
4114help_pages[__MODULE_NAME__].commands["skip"]=command_list["skip"]
4115local function ChatCommandBack(user)
4116if not previous_map_input then
4117return false,"No previous map."
4118end
4119return ChatCommandSkip(user,previous_map_input)
4120end
4121command_list["back"]={perms="admins",func=ChatCommandBack,desc="go back to previous map",argc_min=0,argc_max=0}
4122help_pages[__MODULE_NAME__].commands["back"]=command_list["back"]
4123local function ChatCommandRepeat(user)
4124return ChatCommandSkip(user,current_map_input)
4125end
4126command_list["repeat"]={aliases={"r","replay","rt","retry"},perms="admins",func=ChatCommandRepeat,desc="repeat the last map",argc_min=0,argc_max=0}
4127help_pages[__MODULE_NAME__].commands["repeat"]=command_list["repeat"]
4128local function ChatCommandNextrepeat(user)
4129newgame.SetNextMap(current_map_input,false)
4130return true,"The current map will be replayed."
4131end
4132command_list["nextrepeat"]={aliases={"nr","nrt"},perms="admins",func=ChatCommandNextrepeat,desc="the next map will be the current map",argc_min=0,argc_max=0}
4133help_pages[__MODULE_NAME__].commands["nextrepeat"]=command_list["nextrepeat"]
4134local function ChatCommandRotations(user)
4135tfm.exec.chatMessage("Available rotations:",user)
4136local keys=utils_tables.SortedKeys(rotations)
4137for i_rot,rot_name in pairs(keys)do
4138local rot=pshy.mapdb_GetRotation(rot_name)
4139if rot~=newgame.default_rotation then
4140local count=utils_tables.CountValue(newgame.default_rotation.items,rot_name)
4141local s=((count>0)and"<vp>"or"<fc>")
4142s=s..((count>0)and("<b> ⚖ "..tostring(count).."</b> \t")or" - \t\t")..rot_name
4143s=s..((count>0)and"</vp>"or"</fc>")
4144s=s..": "..tostring(rot.desc).." ("..#rot.items.."#)"
4145tfm.exec.chatMessage(s,user)
4146end
4147end
4148return true
4149end
4150command_list["rotations"]={aliases={"rots"},perms="admins",func=ChatCommandRotations,desc="list available rotations",argc_min=0,argc_max=0}
4151help_pages[__MODULE_NAME__].commands["rotations"]=command_list["rotations"]
4152local function ChatCommandRotw(user,rotname,w)
4153rotname=pshy.mapdb_rotation_aliases[rotname]or rotname if not pshy.mapdb_GetRotation(rotname)then
4154return false,"Unknown rotation."
4155end
4156if rotname=="default"then
4157return false,"It's not rotationception."
4158end
4159if w==nil then
4160w=(utils_tables.CountValue(newgame.default_rotation.items,rotname)~=0)and 0 or 1
4161end
4162if w<0 then
4163return false,"Use 0 to disable the rotation."
4164end
4165if w>100 then
4166return false,"The maximum weight is 100."
4167end
4168utils_tables.ListRemoveValue(newgame.default_rotation.items,rotname)
4169if w>0 then
4170for i=1,w do
4171table.insert(newgame.default_rotation.items,rotname)
4172end
4173end
4174newgame.default_rotation:Reset()
4175return true,"Changed a map frequency."
4176end
4177command_list["rotationweigth"]={aliases={"rotw"},perms="admins",func=ChatCommandRotw,desc="set how often a rotation is to be played",argc_min=1,argc_max=2,arg_types={"string","number"},arg_names={"rotation","amount"}}
4178help_pages[__MODULE_NAME__].commands["rotationweigth"]=command_list["rotationweigth"]
4179local function ChatCommandRotc(user,rotname)
4180return newgame.SetRotation(rotname)
4181end
4182command_list["rotationclean"]={aliases={"rotc"},perms="admins",func=ChatCommandRotc,desc="clear all rotations, and optionaly set a new one",argc_min=0,argc_max=1,arg_types={"string"},arg_names={"new rotation"}}
4183help_pages[__MODULE_NAME__].commands["rotationclean"]=command_list["rotationclean"]
4184newgame.ChatCommandRotc=ChatCommandRotc
4185local function ChatCommandAutorespawn(user,enabled)
4186if enabled~=nil then
4187autorespawn=enabled
4188else
4189autorespawn=not autorespawn
4190end
4191if enabled then
4192newgame_settings_override.OriginalTFMDisableAfkDeath(true)
4193else
4194newgame_settings_override.OriginalTFMDisableAfkDeath(not newgame_settings_override.afk_death)
4195end
4196return true,string.format("Automatic respawn is now %s.",(autorespawn and"enabled"or"disabled"))
4197end
4198command_list["autorespawn"]={perms="admins",func=ChatCommandAutorespawn,desc="enable or disable automatic respawn",argc_min=0,argc_max=1,arg_types={"boolean"},arg_names={"on/off"}}
4199help_pages[__MODULE_NAME__].commands["autorespawn"]=command_list["autorespawn"]
4200return newgame
4201end
4202pshy.modules["pshy.tools.fcplatform"].load = function()
4203local __MODULE_NAME__ = "pshy.tools.fcplatform"
4204local command_list=pshy.require("pshy.commands.list")
4205pshy.require("pshy.events")
4206local help_pages=pshy.require("pshy.help.pages")
4207local ids=pshy.require("pshy.utils.ids")
4208local fcplatform={}
4209local ground_id=ids.AllocPhysicObjectId()
4210fcplatform.x=-100
4211fcplatform.y=100
4212fcplatform.w=60
4213fcplatform.h=10
4214fcplatform.friction=0.4
4215fcplatform.members={}fcplatform.jail={}fcplatform.pilots={}fcplatform.autospawn=false
4216fcplatform.color=0xff7000
4217fcplatform.spawned=false
4218local GetTarget=pshy.require("pshy.commands.get_target_or_error")
4219help_pages[__MODULE_NAME__]={back="pshy",title="FC Platform",text="Adds a platform you can teleport on to spectate.\nThe players on the platform move with it.\n"}
4220help_pages[__MODULE_NAME__].commands={}
4221help_pages["pshy"].subpages[__MODULE_NAME__]=help_pages[__MODULE_NAME__]
4222local function GetPlayersOnFcplatform()
4223if not fcplatform.spawned then
4224return{}
4225end
4226local ons={}
4227for player_name,player in pairs(tfm.get.room.playerList)do
4228if player.y<fcplatform.y-fcplatform.h/2 and player.y>fcplatform.y-fcplatform.h/2-60 and player.x>fcplatform.x-fcplatform.w/2 and player.x<fcplatform.x+fcplatform.w/2 then
4229ons[player_name]=true
4230end
4231end
4232return ons
4233end
4234local function ChatCommandFcplatform(user,x,y)
4235local ons=GetPlayersOnFcplatform()local offset_x=0
4236local offset_y=0
4237if x then
4238offset_x=x-fcplatform.x
4239fcplatform.x=x
4240end
4241if y then
4242offset_y=y-fcplatform.y
4243fcplatform.y=y
4244end
4245if fcplatform.x and fcplatform.y then
4246tfm.exec.addPhysicObject(ground_id,fcplatform.x,fcplatform.y,{type=12,width=fcplatform.w,height=fcplatform.h,foreground=false,friction=fcplatform.friction,restitution=0.0,angle=0,color=fcplatform.color,miceCollision=true,groundCollision=false})
4247fcplatform.spawned=true
4248for player_name,void in pairs(ons)do
4249tfm.exec.movePlayer(player_name,offset_x,offset_y,true,0,0,true)
4250end
4251for player_name,void in pairs(fcplatform.members)do
4252if not ons[player_name]or user==nil then
4253tfm.exec.movePlayer(player_name,fcplatform.x,fcplatform.y-20,false,0,0,false)
4254end
4255end
4256end
4257end
4258command_list["fcplatform"]={aliases={"fcp"},perms="admins",func=ChatCommandFcplatform,desc="Create a funcorp plateform.",argc_min=0,argc_max=2,arg_types={'number','number'}}
4259command_list["fcplatform"].help="Create a platform at given coordinates, or recreate the previous platform. Accept variables as arguments.\n"
4260help_pages[__MODULE_NAME__].commands["fcplatform"]=command_list["fcplatform"]
4261local function ChatCommandFcpplatformpilot(user,target)
4262target=target or user
4263if not fcplatform.pilots[target]then
4264system.bindMouse(target,true)
4265fcplatform.pilots[target]=true
4266return true,string.format("%s is now the platform's pilot!",target)
4267else
4268fcplatform.pilots[target]=nil
4269return true,string.format("%s is no longer the platform's pilot.",target)
4270end
4271end
4272command_list["fcplatformpilot"]={aliases={"fcpp"},perms="admins",func=ChatCommandFcpplatformpilot,desc="Set yourself or a player as a fcplatform pilot.",argc_min=0,argc_max=1,arg_types={'string'}}
4273help_pages[__MODULE_NAME__].commands["fcplatformpilot"]=command_list["fcplatformpilot"]
4274local function ChatCommandFcpplatformjoin(user,join,target)
4275local target=GetTarget(user,target,"!fcplatformjoin")
4276local target=target or user
4277join=join or not fcplatform.jail[target]
4278if fcplatform.jail[target]~=fcplatform.members[target]then
4279return false,"You didnt join the platform by yourself ;>"
4280end
4281if join then
4282if not fcplatform.autospawn then
4283return false,"The fcplatform needs to be spawned by room admins for you to join it."
4284end
4285fcplatform.jail[target]=true
4286fcplatform.members[target]=true
4287tfm.exec.removeCheese(target)
4288return true,"Platform joined!"
4289else
4290fcplatform.jail[target]=nil
4291fcplatform.members[target]=nil
4292tfm.exec.killPlayer(user)
4293return true,"Platform left!"
4294end
4295end
4296command_list["fcplatformjoin"]={aliases={"fcpj","fcpjoin"},perms="admins",func=ChatCommandFcpplatformjoin,desc="Join or leave the fcplatform.",argc_min=0,argc_max=2,arg_types={'bool','player'}}
4297help_pages[__MODULE_NAME__].commands["fcplatformjoin"]=command_list["fcplatformjoin"]
4298local function ChatCommandFcplatformautospawn(user,enabled)
4299if enabled==nil then
4300enabled=not fcplatform.autospawn
4301end
4302fcplatform.autospawn=enabled
4303if enabled then
4304return true,"The platform will now respawn between games."
4305else
4306return true,"The platform will no longer respawn between games."
4307end
4308end
4309command_list["fcplatformautospawn"]={aliases={"fcpautospawn"},perms="admins",func=ChatCommandFcplatformautospawn,desc="Enable or disable the platform from respawning between games.",argc_min=0,argc_max=1,arg_types={'bool'}}
4310help_pages[__MODULE_NAME__].commands["fcplatformautospawn"]=command_list["fcplatformautospawn"]
4311local function ChatCommandFcplatformcolor(user,color)
4312fcplatform.color=color
4313if fcplatform.spawned then
4314return ChatCommandFcplatform(nil)
4315else
4316return true,"The platform's color will have changed the next time you spawn it."
4317end
4318end
4319command_list["fcplatformcolor"]={aliases={"fcpcolor"},perms="admins",func=ChatCommandFcplatformcolor,desc="Set the platform's color.",argc_min=1,argc_max=1,arg_types={'color'}}
4320help_pages[__MODULE_NAME__].commands["fcplatformcolor"]=command_list["fcplatformcolor"]
4321local function ChatCommandFcplatformsize(user,width,height)
4322height=height or fcplatform.h
4323fcplatform.w=width
4324fcplatform.h=height
4325if fcplatform.spawned then
4326return ChatCommandFcplatform(nil)
4327else
4328return true,"The platform's size will have changed the next time you spawn it."
4329end
4330end
4331command_list["fcplatformsize"]={aliases={"fcpsize"},perms="admins",func=ChatCommandFcplatformsize,desc="Set the platform's size.",argc_min=1,argc_max=2,arg_types={'number','number'}}
4332help_pages[__MODULE_NAME__].commands["fcplatformsize"]=command_list["fcplatformsize"]
4333function eventNewGame()
4334fcplatform.spawned=false
4335if fcplatform.autospawn then
4336ChatCommandFcplatform(nil)
4337for player_name in pairs(fcplatform.jail)do
4338local tfm_player=tfm.get.room.playerList[player_name]
4339if tfm_player then
4340tfm.exec.movePlayer(player_name,tfm_player.x,tfm_player.y,false,0,0,true)
4341end
4342end
4343end
4344end
4345function eventLoop(currentTime,timeRemaining)
4346for player_name,void in pairs(fcplatform.jail)do
4347player=tfm.get.room.playerList[player_name]
4348if player then
4349if player.y<fcplatform.y and player.y>fcplatform.y-60 and player.x>fcplatform.x-fcplatform.w/2 and player.x<fcplatform.x+fcplatform.w/2 then
4350else
4351tfm.exec.movePlayer(player_name,fcplatform.x,fcplatform.y-20,false,0,0,false)
4352end
4353end
4354end
4355end
4356function eventMouse(playerName,xMousePosition,yMousePosition)
4357if fcplatform.pilots[playerName]then
4358ChatCommandFcplatform(playerName,xMousePosition,yMousePosition)
4359end
4360end
4361return fcplatform
4362end
4363pshy.modules["pshy.tools.motd"].load = function()
4364local __MODULE_NAME__ = "pshy.tools.motd"
4365local command_list=pshy.require("pshy.commands.list")
4366pshy.require("pshy.events")
4367local help_pages=pshy.require("pshy.help.pages")
4368local motd={}
4369motd.message=nil motd.every=-1
4370help_pages[__MODULE_NAME__]={back="pshy",title="Announcements",text="This module adds announcement features.\nThis include a MOTD displayed to joining players.\n",examples={}}
4371help_pages[__MODULE_NAME__].commands={}
4372help_pages["pshy"].subpages[__MODULE_NAME__]=help_pages[__MODULE_NAME__]
4373local message_count_since_motd=0
4374local function ChatCommandMotd(user)
4375if motd.message then
4376return true,string.format("Current motd:\n%s",motd.message)
4377else
4378return false,"No MOTD set. Use `!setmotd <motd>` to set one."
4379end
4380end
4381command_list["motd"]={perms="everyone",func=ChatCommandMotd,desc="See the current motd.",argc_min=0,argc_max=0,arg_types={}}
4382help_pages[__MODULE_NAME__].commands["motd"]=command_list["motd"]
4383local function ChatCommandSetmotd(user,message)
4384if string.sub(message,1,1)=="&"then
4385motd.message=string.gsub(string.gsub(message,"<","<"),">",">")
4386else
4387motd.message="<fc>"..message.."</fc>"
4388end
4389return ChatCommandMotd(user)
4390end
4391command_list["setmotd"]={perms="admins",func=ChatCommandSetmotd,desc="Set the motd (support html).",argc_min=1,argc_max=1,arg_types={"string"}}
4392command_list["setmotd"].help="You may also use html /!\\ BUT CLOSE MARKUPS!\n"
4393help_pages[__MODULE_NAME__].commands["setmotd"]=command_list["setmotd"]
4394local function ChatCommandAnnounce(player_name,message)
4395if string.sub(message,1,1)=="&"then
4396tfm.exec.chatMessage(string.gsub(string.gsub(message,"<","<"),">",">"),nil)
4397else
4398tfm.exec.chatMessage("<fc>"..message.."</fc>",nil)
4399end
4400return true
4401end
4402command_list["announce"]={perms="admins",func=ChatCommandAnnounce,desc="Send an orange message in the chat (support html).",argc_min=1,argc_max=1,arg_types={"string"}}
4403command_list["announce"].help="You may also use html /!\\ BUT CLOSE MARKUPS!\n"
4404help_pages[__MODULE_NAME__].commands["announce"]=command_list["announce"]
4405function eventNewPlayer(player_name)
4406if motd.message then
4407tfm.exec.chatMessage(motd.message,player_name)
4408end
4409end
4410function eventChatMessage(player_name,message)
4411if motd.message and motd.every>0 then
4412message_count_since_motd=message_count_since_motd+1
4413if message_count_since_motd>=motd.every then
4414tfm.exec.chatMessage(motd.message,nil)
4415message_count_since_motd=0
4416end
4417end
4418end
4419return motd
4420end
4421pshy.modules["pshy.games.pacmice"].load = function()
4422local __IS_MAIN_MODULE__ = true
4423local __MODULE_NAME__ = "pshy.games.pacmice"
4424pshy.require("pshy.alternatives.chat")
4425local alternative_timers=pshy.require("pshy.alternatives.timers")
4426pshy.require("pshy.anticheats.ban")
4427pshy.require("pshy.anticheats.loadersync")
4428local loopmore=pshy.require("pshy.bases.loopmore")
4429local scores=pshy.require("pshy.bases.scores")
4430local splashscreen=pshy.require("pshy.bases.splashscreen")
4431pshy.require("pshy.bases.version")
4432local bonuses=pshy.require("pshy.bonuses")
4433local bonus_types=pshy.require("pshy.bonuses.list")
4434pshy.require("pshy.bonuses.list.mario")
4435pshy.require("pshy.commands")
4436local command_list=pshy.require("pshy.commands.list")
4437pshy.require("pshy.commands.list.modules")
4438local help_pages=pshy.require("pshy.help.pages")
4439local keycodes=pshy.require("pshy.enums.keycodes")
4440pshy.require("pshy.events")
4441pshy.require("pshy.help")
4442pshy.require("pshy.images.changeimage")
4443pshy.require("pshy.rotations.newgame")
4444pshy.require("pshy.tools.fcplatform")
4445pshy.require("pshy.tools.motd")
4446local Rotation=pshy.require("pshy.utils.rotation")
4447local utils_tfm=pshy.require("pshy.utils.tfm")
4448local maps=pshy.require("pshy.maps.list")
4449local perms=pshy.require("pshy.perms")
4450local rotations=pshy.require("pshy.rotations.list")
4451local room=pshy.require("pshy.room")
4452local ids=pshy.require("pshy.utils.ids")
4453help_pages[""]={back="",title="PacMice",details="<r>Run away</r> from the <j>pacmouse</j>!\n\nEvery <ch2>food</ch2> item earns you <ch>2 points</ch>.\n<ch2>Entering the hole</ch2> earns you <ch>16 points</ch>.\nIf you dont enter the hole but <ch2>survive</ch2>, you earn <ch>10 points</ch>.\nThe player with the highest score becomes the next <j>pacmouse</j>.\n"}
4454help_pages[__MODULE_NAME__]={back="",title="PacMice Commands",text="",commands={}}
4455tfm.exec.disableAutoNewGame(true)
4456tfm.exec.disableAutoShaman(true)
4457tfm.exec.disableAfkDeath(true)
4458tfm.exec.disableAutoTimeLeft(true)
4459system.disableChatCommandDisplay(nil,true)
4460perms.auto_admin_authors=false
4461perms.authors["Nnaaaz#0000"]=true
4462perms.authors["Pshy#3752"]=true
4463splashscreen.image="17acb076edb.png"splashscreen.x=150 splashscreen.y=100 splashscreen.sx=1 splashscreen.sy=1 splashscreen.text=nil
4464splashscreen.duration=8*1000 local pacmice_help_btn_id=ids.AllocTextAreaId()
4465local killer_ground_1=121
4466local killer_ground_2=122
4467local pacmice_map=nil local pacmice_cur_pilot=nil local pacmice_cur_x=0
4468local pacmice_cur_y=0
4469local pacmice_cur_generating=false
4470local pacmice_auto_generating=false
4471local pacmice_auto_x=nil
4472local pacmice_auto_y=nil
4473local pacmice_auto_object_id=nil
4474local pacmice_pacmans={}local pacmice_auto_respawn=true
4475local pacmice_pacmouse_count=0
4476local pacmice_round_over=false
4477local pacmice_animations={}
4478pacmice_animations[1]={"17afe1cf978.png","17afe1ce20a.png"}
4479pacmice_animations[2]={"17afe2a6882.png","17afe1d18bc.png"}
4480local pacmice_map_colors={"0000ff","00ff00","ff0000","ffff00","00ffff","ff00ff","ff7700","d200ff"}
4481local pacmice_map_color_index=math.random(#pacmice_map_colors)
4482local pacmice_food_images={"17ae46fd894.png","17ae46ff007.png","17ae4700777.png","17ae4701ee9.png","17ae4703658.png","17ae4704dcc.png","17ae4706540.png","17ae4707cb0.png","17ae4709422.png","17ae470ab94.png","17ae470c307.png","17ae470da77.png","17ae470f1e8.png","17ae4710959.png","17ae47120dd.png","17ae471383b.png","17ae4714fad.png","17ae4716720.png","17ae4717e93.png","17ae4719605.png"}
4483local pacmice_maps={}pacmice_maps["pacmice_1"]={xml="pacmice_1",background_color="#010101",x=91,y=29,cell_w=26,cell_h=26,wall_size=14,web_x=-100,pac_count=1,axml=[[<C><P H="720" DS="m;170,165,610,165" MEDATA=";;;;-0;0::0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160:1-"/><Z><S><S T="12" X="168" Y="107" L="56" H="56" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="613" Y="107" L="56" H="56" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="286" Y="107" L="79" H="56" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="495" Y="107" L="79" H="56" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="247" Y="263" L="10" H="160" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="533" Y="263" L="10" H="160" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="390" Y="29" L="605" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="91" Y="130" L="10" H="210" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="690" Y="130" L="10" H="210" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="141" Y="237" L="110" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="641" Y="237" L="108" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="196" Y="276" L="10" H="87" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="586" Y="277" L="10" H="88" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="143" Y="316" L="113" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="636" Y="316" L="101" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="91" Y="343" L="10" H="60" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="689" Y="342" L="10" H="62" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="145" Y="368" L="111" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="635" Y="368" L="100" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="196" Y="408" L="10" H="83" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="586" Y="406" L="10" H="87" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="145" Y="445" L="105" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="638" Y="445" L="105" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="90" Y="575" L="10" H="270" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="690" Y="575" L="10" H="270" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="390" Y="706" L="608" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="390" Y="82" L="32" H="108" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="392" Y="186" L="180" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="391" Y="445" L="176" H="10" P="0,0,0.3,0.2,360,0,0,0"/><S T="12" X="389" Y="550" L="177" H="10" P="0,0,0.3,0.2,360,0,0,0"/><S T="12" X="234" Y="655" L="185" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="547" Y="655" L="184" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="170" Y="186" L="50" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="612" Y="186" L="50" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="390" Y="214" L="32" H="56" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="390" Y="476" L="32" H="55" P="0,0,0.5,0.2,360,0,0,0"/><S T="12" X="390" Y="603" L="32" H="103" P="0,0,0.5,0.2,360,0,0,0"/><S T="12" X="172" Y="498" L="55" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="609" Y="498" L="55" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="195" Y="549" L="10" H="107" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="586" Y="549" L="10" H="107" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="286" Y="498" L="73" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="495" Y="498" L="75" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="247" Y="420" L="10" H="55" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="533" Y="420" L="10" H="56" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="248" Y="600" L="10" H="100" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="533" Y="600" L="10" H="99" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="289" Y="238" L="75" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="493" Y="238" L="75" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="118" Y="576" L="52" H="54" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="663" Y="576" L="52" H="54" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="391" Y="393" L="190" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="480" Y="300" L="10" H="22" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="301" Y="300" L="10" H="22" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="480" Y="387" L="10" H="22" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="301" Y="387" L="10" H="22" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="325" Y="292" L="60" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="455" Y="292" L="60" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="312" Y="602" L="30" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="469" Y="602" L="30" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="390" Y="292" L="67" H="10" P="0,0,0.3,0.2,0,0,0,0" v="90000"/><S T="12" X="480" Y="342" L="67" H="10" P="0,0,0.3,0.2,90,0,0,0" v="90000"/><S T="12" X="301" Y="342" L="67" H="10" P="0,0,0.3,0.2,90,0,0,0" v="90000"/><S T="12" X="387" Y="724" L="10" H="10" P="1,0,0.3,0.2,0,1,Infinity,0" c="4" v="90000"/><S T="12" X="427" Y="724" L="10" H="10" P="1,0,0.3,0.2,0,1,Infinity,0" c="4" v="89000"/><S T="12" X="467" Y="724" L="10" H="10" P="1,0,0.3,0.2,0,1,Infinity,0" c="4" v="88000"/><S T="12" X="507" Y="724" L="10" H="10" P="1,0,0.3,0.2,0,1,Infinity,0" c="4" v="87000"/><S T="12" X="547" Y="724" L="10" H="10" P="1,0,0.3,0.2,0,1,Infinity,0" c="4" v="86000"/><S T="12" X="587" Y="724" L="10" H="10" P="1,0,0.3,0.2,0,1,Infinity,0" c="4" v="85000"/></S><D><F X="335" Y="379" D=""/><F X="445" Y="379" D=""/><T X="392" Y="387" D=""/></D><O/><L><JD c="1500fb,10,1,0" P1="91,29" P2="690,29"/><JD c="1500fb,10,1,0" P1="91,706" P2="690,706"/><JD c="1500fb,10,1,0" P1="91,30" P2="91,236"/><JD c="1500fb,10,1,0" P1="690,30" P2="690,236"/><JD c="1500fb,10,1,0" P1="91,446" P2="91,704"/><JD c="1500fb,10,1,0" P1="690,446" P2="690,704"/><JD c="1500fb,10,1,0" P1="91,237" P2="195,237"/><JD c="1500fb,10,1,0" P1="690,237" P2="586,237"/><JD c="1500fb,10,1,0" P1="149,186" P2="191,186"/><JD c="1500fb,10,1,0" P1="632,186" P2="590,186"/><JD c="1500fb,10,1,0" P1="301,292" P2="352,292"/><JD c="FFFFFF,10,1,0" M1="63" M2="63" P1="362,292" P2="418,292"/><JD c="FFFFFF,10,1,0" M1="63" M2="63" P1="480,316" P2="480,372"/><JD c="FFFFFF,10,1,0" M1="63" M2="63" P1="301,316" P2="301,372"/><JD c="1500fb,10,1,0" M1="64" M2="64" P1="362,292" P2="418,292"/><JD c="1500fb,10,1,0" M1="64" M2="64" P1="480,316" P2="480,372"/><JD c="1500fb,10,1,0" M1="64" M2="64" P1="301,316" P2="301,372"/><JD c="FFFFFF,10,1,0" M1="65" M2="65" P1="362,292" P2="418,292"/><JD c="FFFFFF,10,1,0" M1="65" M2="65" P1="480,316" P2="480,372"/><JD c="FFFFFF,10,1,0" M1="65" M2="65" P1="301,316" P2="301,372"/><JD c="1500fb,10,1,0" M1="66" M2="66" P1="362,292" P2="418,292"/><JD c="1500fb,10,1,0" M1="66" M2="66" P1="480,316" P2="480,372"/><JD c="1500fb,10,1,0" M1="66" M2="66" P1="301,316" P2="301,372"/><JD c="FFFFFF,10,1,0" M1="67" M2="67" P1="362,292" P2="418,292"/><JD c="FFFFFF,10,1,0" M1="67" M2="67" P1="480,316" P2="480,372"/><JD c="FFFFFF,10,1,0" M1="67" M2="67" P1="301,316" P2="301,372"/><JD c="1500fb,10,1,0" M1="68" M2="68" P1="362,292" P2="418,292"/><JD c="1500fb,10,1,0" M1="68" M2="68" P1="480,316" P2="480,372"/><JD c="1500fb,10,1,0" M1="68" M2="68" P1="301,316" P2="301,372"/><JD c="1500fb,10,1,0" P1="480,292" P2="429,292"/><JD c="1500fb,10,1,0" P1="249,238" P2="322,238"/><JD c="1500fb,10,1,0" P1="532,238" P2="459,238"/><JD c="1500fb,10,1,0" P1="92,316" P2="195,316"/><JD c="1500fb,10,1,0" P1="689,316" P2="586,316"/><JD c="1500fb,10,1,0" P1="92,368" P2="195,368"/><JD c="1500fb,10,1,0" P1="689,368" P2="586,368"/><JD c="1500fb,10,1,0" P1="91,445" P2="195,445"/><JD c="1500fb,10,1,0" P1="690,445" P2="586,445"/><JD c="1500fb,10,1,0" P1="307,445" P2="476,445"/><JD c="1500fb,10,1,0" P1="302,393" P2="479,393"/><JD c="1500fb,10,1,0" P1="307,186" P2="478,186"/><JD c="1500fb,10,1,0" P1="305,550" P2="474,550"/><JD c="1500fb,10,1,0" P1="145,655" P2="323,655"/><JD c="1500fb,10,1,0" P1="636,655" P2="458,655"/><JD c="000000,6,1,0" P1="91,30" P2="91,236"/><JD c="000000,6,1,0" P1="690,30" P2="690,236"/><JD c="000000,6,1,0" P1="91,706" P2="690,706"/><JD c="1500fb,10,1,0" P1="148,498" P2="195,498"/><JD c="1500fb,10,1,0" P1="633,498" P2="586,498"/><JD c="1500fb,10,1,0" P1="254,498" P2="318,498"/><JD c="1500fb,10,1,0" P1="527,498" P2="463,498"/><JD c="1500fb,10,1,0" P1="301,602" P2="322,602"/><JD c="1500fb,10,1,0" P1="480,602" P2="459,602"/><JD c="1500fb,10,1,0" P1="195.5,237.5" P2="195.5,315.5"/><JD c="1500fb,10,1,0" P1="585.5,237.5" P2="585.5,315.5"/><JD c="1500fb,10,1,0" P1="480,294" P2="480,306"/><JD c="1500fb,10,1,0" P1="301,294" P2="301,306"/><JD c="1500fb,10,1,0" P1="480,381" P2="480,393"/><JD c="1500fb,10,1,0" P1="301,381" P2="301,393"/><JD c="1500fb,10,1,0" P1="247.5,186.5" P2="247.5,338.5"/><JD c="1500fb,10,1,0" P1="533.5,186.5" P2="533.5,338.5"/><JD c="1500fb,10,1,0" P1="195.5,368" P2="195.5,445"/><JD c="1500fb,10,1,0" P1="585.5,368" P2="585.5,445"/><JD c="000000,6,1,0" P1="91,446" P2="91,704"/><JD c="000000,6,1,0" P1="690,446" P2="690,704"/><JD c="1500fb,10,1,0" P1="247.5,397" P2="247.5,443"/><JD c="1500fb,10,1,0" P1="533.5,397" P2="533.5,443"/><JD c="1500fb,10,1,0" P1="195.5,498" P2="195.5,600"/><JD c="1500fb,10,1,0" P1="585.5,498" P2="585.5,600"/><JD c="1500fb,10,1,0" P1="247.5,553" P2="247.5,655"/><JD c="1500fb,10,1,0" P1="533.5,553" P2="533.5,655"/><JD c="1500fb,10,1,0" P1="91.5,316" P2="91.5,367"/><JD c="1500fb,10,1,0" P1="689.5,316" P2="689.5,367"/><JD c="000000,6,1,0" P1="91,237" P2="195,237"/><JD c="000000,6,1,0" P1="690,237" P2="586,237"/><JD c="000000,6,1,0" P1="149,186" P2="191,186"/><JD c="000000,6,1,0" P1="632,186" P2="590,186"/><JD c="000000,6,1,0" P1="301,292" P2="352,292"/><JD c="000000,6,1,0" M1="63" M2="63" P1="362,292" P2="418,292"/><JD c="000000,6,1,0" M1="63" M2="63" P1="480,316" P2="480,372"/><JD c="000000,6,1,0" M1="63" M2="63" P1="301,316" P2="301,372"/><JD c="000000,6,1,0" P1="480,292" P2="429,292"/><JD c="000000,6,1,0" P1="249,238" P2="322,238"/><JD c="000000,6,1,0" P1="532,238" P2="459,238"/><JD c="000000,6,1,0" P1="92,316" P2="195,316"/><JD c="000000,6,1,0" P1="689,316" P2="586,316"/><JD c="000000,6,1,0" P1="92,368" P2="195,368"/><JD c="000000,6,1,0" P1="689,368" P2="586,368"/><JD c="000000,6,1,0" P1="91,445" P2="195,445"/><JD c="000000,6,1,0" P1="690,445" P2="586,445"/><JD c="000000,6,1,0" P1="307,445" P2="476,445"/><JD c="000000,6,1,0" P1="302,393" P2="479,393"/><JD c="000000,6,1,0" P1="145,655" P2="323,655"/><JD c="000000,6,1,0" P1="636,655" P2="458,655"/><JD c="000000,6,1,0" P1="148,498" P2="195,498"/><JD c="000000,6,1,0" P1="633,498" P2="586,498"/><JD c="000000,6,1,0" P1="254,498" P2="318,498"/><JD c="000000,6,1,0" P1="527,498" P2="463,498"/><JD c="000000,6,1,0" P1="301,602" P2="322,602"/><JD c="000000,6,1,0" P1="480,602" P2="459,602"/><JD c="000000,6,1,0" P1="195.5,237.5" P2="195.5,315.5"/><JD c="000000,6,1,0" P1="585.5,237.5" P2="585.5,315.5"/><JD c="000000,6,1,0" P1="480,294" P2="480,306"/><JD c="000000,6,1,0" P1="301,294" P2="301,306"/><JD c="000000,6,1,0" P1="480,381" P2="480,393"/><JD c="000000,6,1,0" P1="301,381" P2="301,393"/><JD c="000000,6,1,0" P1="247.5,186.5" P2="247.5,338.5"/><JD c="000000,6,1,0" P1="533.5,186.5" P2="533.5,338.5"/><JD c="000000,6,1,0" P1="195.5,368" P2="195.5,445"/><JD c="000000,6,1,0" P1="585.5,368" P2="585.5,445"/><JD c="000000,6,1,0" P1="247.5,397" P2="247.5,443"/><JD c="000000,6,1,0" P1="533.5,397" P2="533.5,443"/><JD c="000000,6,1,0" P1="195.5,498" P2="195.5,600"/><JD c="000000,6,1,0" P1="585.5,498" P2="585.5,600"/><JD c="000000,6,1,0" P1="247.5,553" P2="247.5,655"/><JD c="000000,6,1,0" P1="533.5,553" P2="533.5,655"/><JD c="000000,6,1,0" P1="91.5,316" P2="91.5,367"/><JD c="000000,6,1,0" P1="689.5,316" P2="689.5,367"/><JD c="1500fb,3,1,0" P1="141,80" P2="195,80"/><JD c="1500fb,3,1,0" P1="640,80" P2="586,80"/><JD c="1500fb,3,1,0" P1="248,80" P2="324,80"/><JD c="1500fb,3,1,0" P1="533,80" P2="457,80"/><JD c="1500fb,3,1,0" P1="195,81" P2="195,134"/><JD c="1500fb,3,1,0" P1="586,81" P2="586,134"/><JD c="1500fb,3,1,0" P1="324,81" P2="324,134"/><JD c="1500fb,3,1,0" P1="375,33" P2="375,134"/><JD c="1500fb,3,1,0" P1="375,189" P2="375,240"/><JD c="1500fb,3,1,0" P1="375,450" P2="375,502"/><JD c="1500fb,3,1,0" P1="375,553" P2="375,653"/><JD c="1500fb,3,1,0" P1="405,33" P2="405,134"/><JD c="1500fb,3,1,0" P1="405,189" P2="405,240"/><JD c="1500fb,3,1,0" P1="404.88,450" P2="404.88,502"/><JD c="1500fb,3,1,0" P1="405,553" P2="405,653"/><JD c="1500fb,3,1,0" P1="457,81" P2="457,134"/><JD c="1500fb,3,1,0" P1="141,81" P2="141,134"/><JD c="1500fb,3,1,0" P1="640,81" P2="640,134"/><JD c="1500fb,3,1,0" P1="248,81" P2="248,134"/><JD c="000000,6,1,0" P1="307,186" P2="478,186"/><JD c="1500fb,3,1,0" P1="533,81" P2="533,134"/><JD c="1500fb,3,1,0" P1="141,134" P2="195,134"/><JD c="1500fb,3,1,0" P1="640,134" P2="586,134"/><JD c="1500fb,3,1,0" P1="248,134.5" P2="324,134.5"/><JD c="1500fb,3,1,0" P1="375,134.5" P2="405,134.5"/><JD c="000000,6,1,0" P1="305,550" P2="474,550"/><JD c="1500fb,3,1,0" P1="375,240.5" P2="405,240.5"/><JD c="1500fb,3,1,0" P1="375,502.5" P2="405,502.5"/><JD c="000000,6,1,0" P1="91,29" P2="690,29"/><JD c="1500fb,3,1,0" P1="375,653.5" P2="405,653.5"/><JD c="1500fb,3,1,0" P1="533,134" P2="457,134"/><JD c="1500fb,3,1,0" P1="96,551" P2="143,551"/><JD c="1500fb,3,1,0" P1="685,551" P2="638,551"/><JD c="1500fb,3,1,0" P1="96,601" P2="143,601"/><JD c="1500fb,3,1,0" P1="685,601" P2="638,601"/><JD c="1500fb,3,1,0" P1="143,551" P2="143,601"/><JD c="1500fb,3,1,0" P1="638,551" P2="638,601"/><JD c="000000,5,1,0" P1="379,449" P2="401,449"/><JD c="000000,5,1,0" P1="379,554" P2="401,554"/><JD c="000000,5,1,0" P1="379,190" P2="401,190"/><JD c="000000,5,1,0" P1="379,33" P2="401,33"/><JD c="000000,5,1,0" P1="686,555" P2="686,597"/><JD c="000000,5,1,0" P1="95,555" P2="95,597"/></L></Z></C>]]}
4484pacmice_maps["pacmice_1"].pathes={{1,1},{2,1},{3,1},{4,1},{5,1},{6,1},{7,1},{8,1},{9,1},{10,1},{13,1},{14,1},{15,1},{16,1},{17,1},{18,1},{19,1},{20,1},{21,1},{22,1},{1,2},{5,2},{10,2},{13,2},{18,2},{22,2},{1,3},{5,3},{10,3},{13,3},{18,3},{22,3},{1,4},{5,4},{10,4},{13,4},{18,4},{22,4},{1,5},{2,5},{3,5},{4,5},{5,5},{6,5},{7,5},{8,5},{9,5},{10,5},{11,5},{12,5},{13,5},{14,5},{15,5},{16,5},{17,5},{18,5},{19,5},{20,5},{21,5},{22,5},{1,6},{5,6},{7,6},{16,6},{18,6},{22,6},{1,7},{2,7},{3,7},{4,7},{5,7},{7,7},{8,7},{9,7},{10,7},{13,7},{14,7},{15,7},{16,7},{18,7},{19,7},{20,7},{21,7},{22,7},{5,8},{10,8},{13,8},{18,8},{5,9},{7,9},{8,9},{9,9},{10,9},{11,9},{12,9},{13,9},{14,9},{15,9},{16,9},{18,9},{5,10},{7,10},{16,10},{18,10},{5,11},{7,11},{16,11},{18,11},{1,12},{2,12},{3,12},{4,12},{5,12},{7,12},{16,12},{18,12},{19,12},{20,12},{21,12},{22,12},{5,13},{6,13},{7,13},{16,13},{17,13},{18,13},{5,14},{7,14},{16,14},{18,14},{5,15},{7,15},{8,15},{9,15},{10,15},{11,15},{12,15},{13,15},{14,15},{15,15},{16,15},{18,15},{5,16},{7,16},{16,16},{18,16},{1,17},{2,17},{3,17},{4,17},{5,17},{6,17},{7,17},{8,17},{9,17},{10,17},{13,17},{14,17},{15,17},{16,17},{17,17},{18,17},{19,17},{20,17},{21,17},{22,17},{1,18},{5,18},{10,18},{13,18},{18,18},{22,18},{1,19},{2,19},{3,19},{5,19},{6,19},{7,19},{8,19},{9,19},{10,19},{11,19},{12,19},{13,19},{14,19},{15,19},{16,19},{17,19},{18,19},{20,19},{21,19},{22,19},{3,20},{5,20},{7,20},{16,20},{18,20},{20,20},{3,21},{5,21},{7,21},{8,21},{9,21},{10,21},{13,21},{14,21},{15,21},{16,21},{18,21},{20,21},{3,22},{5,22},{7,22},{10,22},{13,22},{16,22},{18,22},{20,22},{1,23},{2,23},{3,23},{4,23},{5,23},{7,23},{8,23},{9,23},{10,23},{13,23},{14,23},{15,23},{16,23},{18,23},{19,23},{20,23},{21,23},{22,23},{1,24},{10,24},{13,24},{22,24},{1,25},{2,25},{3,25},{4,25},{5,25},{6,25},{7,25},{8,25},{9,25},{10,25},{11,25},{12,25},{13,25},{14,25},{15,25},{16,25},{17,25},{18,25},{19,25},{20,25},{21,25},{22,25}}
4485pacmice_maps["pacmice_1"].foods={{x=285,y=58},{x=495,y=58},{x=390,y=161},{x=274,y=214},{x=502,y=216},{x=389,y=269},{x=117,y=343},{x=117,y=527},{x=218,y=682},{x=390,y=420},{x=390,y=527},{x=352,y=578},{x=427,y=578},{x=561,y=682},{x=667,y=527},{x=661,y=343}}
4486pacmice_maps["pacmice_2"]={xml="pacmice_2",background_color="#010101",x=91,y=39,cell_w=26,cell_h=26,wall_size=14,web_x=-100,pac_count=1,axml=[[<C><P H="720" DS="m;210,175,570,175" MEDATA=";;;;-0;0::0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208:1-"/><Z><S><S T="12" X="168" Y="91" L="56" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="612" Y="91" L="56" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="288" Y="91" L="84" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="492" Y="91" L="84" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="236" Y="142" L="84" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="544" Y="142" L="84" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="247" Y="536" L="58" H="10" P="0,0,0.3,0.2,-90,0,0,0"/><S T="12" X="533" Y="536" L="58" H="10" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="208" Y="244" L="34" H="103" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="572" Y="244" L="34" H="103" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="120" Y="222" L="52" H="55" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="660" Y="222" L="52" H="55" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="390" Y="39" L="605" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="91" Y="91" L="10" H="114" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="91" Y="433" L="10" H="569" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="690" Y="91" L="10" H="113" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="690" Y="433" L="10" H="574" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="390" Y="716" L="608" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="390" Y="168" L="27" H="162" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="391" Y="234" L="137" H="32" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="325" Y="128" L="10" H="80" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="455" Y="128" L="10" H="80" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="273" Y="193" L="10" H="110" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="507" Y="193" L="10" H="109" P="0,0,0.5,0.2,0,0,0,0"/><S T="12" X="285" Y="560" L="10" H="84" P="0,0,0.5,0.2,-90,0,0,0"/><S T="12" X="495" Y="560" L="10" H="84" P="0,0,0.5,0.2,90,0,0,0"/><S T="12" X="119" Y="143" L="50" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="661" Y="143" L="50" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="390" Y="483" L="30" H="55" P="0,0,0.5,0.2,360,0,0,0"/><S T="12" X="390" Y="613" L="32" H="103" P="0,0,0.5,0.2,360,0,0,0"/><S T="12" X="173" Y="417" L="50" H="31" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="607" Y="417" L="50" H="31" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="118" Y="545" L="50" H="35" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="662" Y="545" L="50" H="35" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="181" Y="611" L="81" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="599" Y="611" L="81" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="237" Y="664" L="81" H="10" P="0,0,0.3,0.2,180,0,0,0"/><S T="12" X="543" Y="664" L="81" H="10" P="0,0,0.3,0.2,-180,0,0,0"/><S T="12" X="107" Y="325" L="23" H="60" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="673" Y="325" L="23" H="60" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="210" Y="351" L="81" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="570" Y="351" L="81" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="247" Y="401" L="10" H="107" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="532" Y="401" L="10" H="107" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="390" Y="507" L="10" H="183" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="284" Y="454" L="10" H="83" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="496" Y="454" L="10" H="83" P="0,0,0.3,0.2,-90,0,0,0"/><S T="12" X="143" Y="443" L="10" H="83" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="637" Y="443" L="10" H="83" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="195" Y="521" L="10" H="80" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="585" Y="521" L="10" H="80" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="143" Y="637" L="10" H="60" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="637" Y="637" L="10" H="60" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="273" Y="638" L="10" H="59" P="0,0,0.3,0.2,180,0,0,0"/><S T="12" X="507" Y="638" L="10" H="59" P="0,0,0.3,0.2,-180,0,0,0"/><S T="12" X="325" Y="662" L="10" H="105" P="0,0,0.3,0.2,180,0,0,0"/><S T="12" X="455" Y="662" L="10" H="105" P="0,0,0.3,0.2,-180,0,0,0"/><S T="12" X="209" Y="299" L="78" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="571" Y="299" L="78" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="391" Y="403" L="190" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="480" Y="308" L="10" H="18" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="300" Y="308" L="10" H="18" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="480" Y="397" L="10" H="18" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="300" Y="397" L="10" H="18" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="325" Y="302" L="60" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="455" Y="302" L="60" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="390" Y="302" L="67" H="10" P="0,0,0.3,0.2,0,0,0,0" v="90000"/><S T="12" X="480" Y="352" L="67" H="10" P="0,0,0.3,0.2,90,0,0,0" v="90000"/><S T="12" X="300" Y="352" L="67" H="10" P="0,0,0.3,0.2,90,0,0,0" v="90000"/><S T="12" X="400" Y="735" L="10" H="10" P="1,0,0.3,0.2,0,1,Infinity,0" c="4" v="90000"/><S T="12" X="400" Y="735" L="10" H="10" P="1,0,0.3,0.2,0,1,Infinity,0" c="4" v="89000"/><S T="12" X="400" Y="735" L="10" H="10" P="1,0,0.3,0.2,0,1,Infinity,0" c="4" v="88000"/><S T="12" X="400" Y="735" L="10" H="10" P="1,0,0.3,0.2,0,1,Infinity,0" c="4" v="87000"/><S T="12" X="400" Y="735" L="10" H="10" P="1,0,0.3,0.2,0,1,Infinity,0" c="4" v="86000"/><S T="12" X="400" Y="735" L="10" H="10" P="1,0,0.3,0.2,0,1,Infinity,0" c="4" v="85000"/></S><D><F X="335" Y="390" D=""/><F X="445" Y="390" D=""/><T X="392" Y="397" D=""/></D><O/><L><JD c="1500fb,10,1,0" P1="91,39" P2="689,39"/><JD c="1500fb,10,1,0" P1="91,716" P2="689,716"/><JD c="1500fb,10,1,0" P1="91,40" P2="91,143"/><JD c="1500fb,10,1,0" P1="689,40" P2="689,143"/><JD c="1500fb,10,1,0" P1="91,199" P2="91,713"/><JD c="1500fb,10,1,0" P1="689,199" P2="689,713"/><JD c="1500fb,10,1,0" P1="273,143" P2="273,244"/><JD c="1500fb,10,1,0" P1="507,143" P2="507,244"/><JD c="1500fb,10,1,0" P1="325,91" P2="325,163"/><JD c="1500fb,10,1,0" P1="455,91" P2="455,163"/><JD c="1500fb,10,1,0" P1="272,142" P2="199,142"/><JD c="1500fb,10,1,0" P1="508,142" P2="581,142"/><JD c="1500fb,10,1,0" P1="244,299" P2="174,299"/><JD c="FFFFFF,10,1,0" M1="69" M2="69" P1="419,302" P2="361,302"/><JD c="FFFFFF,10,1,0" M1="69" M2="69" P1="480,382" P2="480,324"/><JD c="FFFFFF,10,1,0" M1="69" M2="69" P1="300,382" P2="300,324"/><JD c="1500fb,10,1,0" M1="70" M2="70" P1="419,302" P2="361,302"/><JD c="1500fb,10,1,0" M1="70" M2="70" P1="480,382" P2="480,324"/><JD c="1500fb,10,1,0" M1="70" M2="70" P1="300,382" P2="300,324"/><JD c="FFFFFF,10,1,0" M1="71" M2="71" P1="419,302" P2="361,302"/><JD c="FFFFFF,10,1,0" M1="71" M2="71" P1="480,382" P2="480,324"/><JD c="FFFFFF,10,1,0" M1="71" M2="71" P1="300,382" P2="300,324"/><JD c="1500fb,10,1,0" M1="72" M2="72" P1="419,302" P2="361,302"/><JD c="1500fb,10,1,0" M1="72" M2="72" P1="480,382" P2="480,324"/><JD c="1500fb,10,1,0" M1="72" M2="72" P1="300,382" P2="300,324"/><JD c="FFFFFF,10,1,0" M1="73" M2="73" P1="419,302" P2="361,302"/><JD c="FFFFFF,10,1,0" M1="73" M2="73" P1="480,382" P2="480,324"/><JD c="FFFFFF,10,1,0" M1="73" M2="73" P1="300,382" P2="300,324"/><JD c="1500fb,10,1,0" M1="74" M2="74" P1="419,302" P2="361,302"/><JD c="1500fb,10,1,0" M1="74" M2="74" P1="480,382" P2="480,324"/><JD c="1500fb,10,1,0" M1="74" M2="74" P1="300,382" P2="300,324"/><JD c="1500fb,10,1,0" P1="536,299" P2="606,299"/><JD c="1500fb,10,1,0" P1="245,351" P2="174,351"/><JD c="1500fb,10,1,0" P1="535,351" P2="606,351"/><JD c="1500fb,10,1,0" P1="321,454" P2="249,454"/><JD c="1500fb,10,1,0" P1="478,507" P2="302,507"/><JD c="1500fb,10,1,0" P1="479,403" P2="301,403"/><JD c="1500fb,10,1,0" P1="459,454" P2="531,454"/><JD c="1500fb,10,1,0" P1="322,560" P2="249,560"/><JD c="1500fb,10,1,0" P1="458,560" P2="531,560"/><JD c="1500fb,10,1,0" P1="218,611" P2="144,611"/><JD c="1500fb,10,1,0" P1="562,611" P2="636,611"/><JD c="1500fb,10,1,0" P1="273,664" P2="200,664"/><JD c="1500fb,10,1,0" P1="507,664" P2="580,664"/><JD c="1500fb,10,1,0" P1="323,91" P2="250,91"/><JD c="1500fb,10,1,0" P1="457,91" P2="530,91"/><JD c="1500fb,10,1,0" P1="192,91" P2="144,91"/><JD c="1500fb,10,1,0" P1="588,91" P2="636,91"/><JD c="1500fb,10,1,0" P1="351,302" P2="301,302"/><JD c="1500fb,10,1,0" P1="429,302" P2="479,302"/><JD c="1500fb,10,1,0" P1="140,143" P2="92,143"/><JD c="1500fb,10,1,0" P1="640,143" P2="688,143"/><JD c="1500fb,10,1,0" P1="480,302" P2="480,314"/><JD c="1500fb,10,1,0" P1="300,302" P2="300,314"/><JD c="1500fb,10,1,0" P1="480,391" P2="480,402"/><JD c="1500fb,10,1,0" P1="300,391" P2="300,402"/><JD c="1500fb,10,1,0" P1="247,351" P2="247,454"/><JD c="1500fb,10,1,0" P1="533,351" P2="533,454"/><JD c="1500fb,10,1,0" P1="195,485" P2="195,557"/><JD c="1500fb,10,1,0" P1="585,485" P2="585,557"/><JD c="1500fb,10,1,0" P1="143,406" P2="143,479"/><JD c="1500fb,10,1,0" P1="637,406" P2="637,479"/><JD c="1500fb,10,1,0" P1="247,511" P2="247,560"/><JD c="1500fb,10,1,0" P1="533,511" P2="533,560"/><JD c="1500fb,10,1,0" P1="273,613" P2="273,664"/><JD c="1500fb,10,1,0" P1="507,613" P2="507,664"/><JD c="1500fb,10,1,0" P1="143,612" P2="143,663"/><JD c="1500fb,10,1,0" P1="637,612" P2="637,663"/><JD c="1500fb,10,1,0" P1="325,613" P2="325,716"/><JD c="1500fb,10,1,0" P1="455,613" P2="455,716"/><JD c="000000,6,1,0" P1="91,40" P2="91,143"/><JD c="000000,6,1,0" P1="689,40" P2="689,143"/><JD c="000000,6,1,0" P1="91,198" P2="91,713"/><JD c="000000,6,1,0" P1="689,198" P2="689,713"/><JD c="000000,6,1,0" P1="273,143" P2="273,244"/><JD c="000000,6,1,0" P1="507,143" P2="507,244"/><JD c="000000,6,1,0" P1="325,91" P2="325,163"/><JD c="000000,6,1,0" P1="455,91" P2="455,163"/><JD c="000000,6,1,0" P1="272,142" P2="199,142"/><JD c="000000,6,1,0" P1="508,142" P2="581,142"/><JD c="000000,6,1,0" P1="244,299" P2="174,299"/><JD c="000000,6,1,0" M1="69" M2="69" P1="419,302" P2="361,302"/><JD c="000000,6,1,0" M1="69" M2="69" P1="480,382" P2="480,324"/><JD c="000000,6,1,0" M1="69" M2="69" P1="300,382" P2="300,324"/><JD c="000000,6,1,0" P1="536,299" P2="606,299"/><JD c="000000,6,1,0" P1="245,351" P2="174,351"/><JD c="000000,6,1,0" P1="535,351" P2="606,351"/><JD c="1500fb,3,1,0" P1="141,403" P2="197,403"/><JD c="000000,6,1,0" P1="91,716" P2="689,716"/><JD c="1500fb,3,1,0" P1="639,403" P2="583,403"/><JD c="1500fb,3,1,0" P1="96,529" P2="142,529"/><JD c="1500fb,3,1,0" P1="684,529" P2="638,529"/><JD c="000000,6,1,0" P1="321,454" P2="249,454"/><JD c="000000,6,1,0" P1="478,507" P2="302,507"/><JD c="000000,6,1,0" P1="479,403" P2="301,403"/><JD c="000000,6,1,0" P1="459,454" P2="531,454"/><JD c="000000,6,1,0" P1="322,560" P2="249,560"/><JD c="000000,6,1,0" P1="458,560" P2="531,560"/><JD c="000000,6,1,0" P1="218,611" P2="144,611"/><JD c="000000,6,1,0" P1="562,611" P2="636,611"/><JD c="000000,6,1,0" P1="273,664" P2="200,664"/><JD c="000000,6,1,0" P1="507,664" P2="580,664"/><JD c="000000,6,1,0" P1="323,91" P2="250,91"/><JD c="000000,6,1,0" P1="457,91" P2="530,91"/><JD c="000000,6,1,0" P1="192,91" P2="144,91"/><JD c="000000,6,1,0" P1="588,91" P2="636,91"/><JD c="000000,6,1,0" P1="351,302" P2="301,302"/><JD c="000000,6,1,0" P1="429,302" P2="479,302"/><JD c="000000,6,1,0" P1="140,143" P2="92,143"/><JD c="000000,6,1,0" P1="640,143" P2="688,143"/><JD c="000000,6,1,0" P1="480,302" P2="480,314"/><JD c="000000,6,1,0" P1="300,302" P2="300,314"/><JD c="000000,6,1,0" P1="480,391" P2="480,402"/><JD c="000000,6,1,0" P1="300,391" P2="300,402"/><JD c="000000,6,1,0" P1="247,351" P2="247,454"/><JD c="000000,6,1,0" P1="533,351" P2="533,454"/><JD c="000000,6,1,0" P1="195,485" P2="195,557"/><JD c="000000,6,1,0" P1="585,485" P2="585,557"/><JD c="000000,6,1,0" P1="143,408" P2="143,479"/><JD c="000000,6,1,0" P1="637,407" P2="637,479"/><JD c="000000,6,1,0" P1="247,511" P2="247,560"/><JD c="000000,6,1,0" P1="533,511" P2="533,560"/><JD c="000000,6,1,0" P1="273,613" P2="273,664"/><JD c="000000,6,1,0" P1="507,613" P2="507,664"/><JD c="000000,6,1,0" P1="143,612" P2="143,663"/><JD c="000000,6,1,0" P1="637,612" P2="637,663"/><JD c="000000,6,1,0" P1="325,613" P2="325,716"/><JD c="000000,6,1,0" P1="455,613" P2="455,716"/><JD c="1500fb,3,1,0" P1="88,196" P2="144,196"/><JD c="1500fb,3,1,0" P1="692,196" P2="636,196"/><JD c="1500fb,3,1,0" P1="193,195" P2="223,195"/><JD c="1500fb,3,1,0" P1="376,563" P2="404,563"/><JD c="000000,6,1,0" P1="91,39" P2="689,39"/><JD c="1500fb,3,1,0" P1="376,457" P2="404,457"/><JD c="1500fb,3,1,0" P1="376,663" P2="404,663"/><JD c="1500fb,3,1,0" P1="587,195" P2="557,195"/><JD c="1500fb,3,1,0" P1="402,89" P2="378,89"/><JD c="1500fb,3,1,0" P1="458,220" P2="402,220"/><JD c="1500fb,3,1,0" P1="378,220" P2="324,220"/><JD c="1500fb,3,1,0" P1="458,249" P2="324,249"/><JD c="1500fb,3,1,0" P1="96,297" P2="117,297"/><JD c="1500fb,3,1,0" P1="684,297" P2="663,297"/><JD c="1500fb,3,1,0" P1="148,431" P2="196,431"/><JD c="1500fb,3,1,0" P1="632,431" P2="584,431"/><JD c="1500fb,3,1,0" P1="96,561" P2="142,561"/><JD c="1500fb,3,1,0" P1="684,561" P2="638,561"/><JD c="1500fb,3,1,0" P1="96,353" P2="117,353"/><JD c="1500fb,3,1,0" P1="684,353" P2="663,353"/><JD c="1500fb,3,1,0" P1="96,248" P2="144,248"/><JD c="1500fb,3,1,0" P1="684,248" P2="636,248"/><JD c="1500fb,3,1,0" P1="144,197" P2="144,248"/><JD c="1500fb,3,1,0" P1="324,220" P2="324,248"/><JD c="1500fb,3,1,0" P1="458,220" P2="458,248"/><JD c="1500fb,3,1,0" P1="636,197" P2="636,248"/><JD c="1500fb,3,1,0" P1="117,297" P2="117,353"/><JD c="1500fb,3,1,0" P1="663,297" P2="663,353"/><JD c="1500fb,3,1,0" P1="197,403" P2="197,431"/><JD c="1500fb,3,1,0" P1="404,457" P2="404,502"/><JD c="1500fb,3,1,0" P1="376,457" P2="376,502"/><JD c="1500fb,3,1,0" P1="583,403" P2="583,431"/><JD c="1500fb,3,1,0" P1="142.17,529" P2="142.17,560"/><JD c="1500fb,3,1,0" P1="637.83,529" P2="637.83,560"/><JD c="1500fb,3,1,0" P1="193,195" P2="193,294"/><JD c="1500fb,3,1,0" P1="376,563" P2="376,662"/><JD c="1500fb,3,1,0" P1="587,195" P2="587,294"/><JD c="1500fb,3,1,0" P1="401.79,89" P2="401.79,218"/><JD c="1500fb,3,1,0" P1="223,195" P2="223,294"/><JD c="1500fb,3,1,0" P1="404,563" P2="404,662"/><JD c="1500fb,3,1,0" P1="557,195" P2="557,294"/><JD c="1500fb,3,1,0" P1="378,89" P2="378,218"/><JD c="000000,3,1,0" P1="560,298.16" P2="560,274.75"/><JD c="000000,3,1,0" P1="196,298.16" P2="196,274.75"/><JD c="000000,3,1,0" P1="379,506.16" P2="379,482.75"/><JD c="000000,3,1,0" P1="561,295" P2="583,295"/><JD c="000000,3,1,0" P1="197,295" P2="219,295"/><JD c="000000,3,1,0" P1="379,503" P2="400,503"/><JD c="000000,3,1,0" P1="685,556" P2="685,534"/><JD c="000000,3,1,0" P1="633,428" P2="633,408"/><JD c="000000,3,1,0" P1="147,428" P2="147,408"/><JD c="000000,3,1,0" P1="95,556" P2="95,534"/><JD c="000000,3,1,0" P1="685,348" P2="685,300"/><JD c="000000,3,1,0" P1="95,348" P2="95,300"/><JD c="000000,3,1,0" P1="685,244" P2="685,199"/><JD c="000000,3,1,0" P1="95,244" P2="95,199"/><JD c="000000,3,1,0" P1="584,298.16" P2="584,274.75"/><JD c="000000,3,1,0" P1="220,298.16" P2="220,274.75"/><JD c="000000,3,1,0" P1="401,506.16" P2="401,482.75"/><JD c="000000,3,1,0" P1="687,532" P2="664,532"/><JD c="000000,3,1,0" P1="635,406" P2="612,406"/><JD c="000000,3,1,0" P1="143,406" P2="168,406"/><JD c="000000,3,1,0" P1="93,532" P2="116,532"/><JD c="000000,3,1,0" P1="687,300" P2="673,300"/><JD c="000000,3,1,0" P1="93,300" P2="107,300"/><JD c="000000,3,1,0" P1="687,199" P2="673,199"/><JD c="000000,3,1,0" P1="93,199" P2="107,199"/><JD c="000000,3,1,0" P1="695,193" P2="681,193"/><JD c="000000,3,1,0" P1="85,193" P2="99,193"/><JD c="000000,3,1,0" P1="687,558" P2="664,558"/><JD c="000000,3,1,0" P1="635,428" P2="612,428"/><JD c="000000,3,1,0" P1="145,428" P2="168,428"/><JD c="000000,3,1,0" P1="93,558" P2="116,558"/><JD c="000000,3,1,0" P1="687,350" P2="673,350"/><JD c="000000,3,1,0" P1="93,350" P2="107,350"/><JD c="1500fb,10,1,0" P1="91,189" P2="91,153"/><JD c="1500fb,10,1,0" P1="689,189" P2="689,153"/><JD c="000000,3,1,0" P1="687,245" P2="673,245"/><JD c="000000,3,1,0" P1="93,245" P2="107,245"/><JD c="000000,6,1,0" P1="91,189" P2="91,153"/><JD c="000000,6,1,0" P1="689,189" P2="689,153"/></L></Z></C>]]}
4487pacmice_maps["pacmice_2"].pathes={{1,1},{2,1},{3,1},{4,1},{5,1},{6,1},{7,1},{8,1},{9,1},{10,1},{11,1},{12,1},{13,1},{14,1},{15,1},{16,1},{17,1},{18,1},{19,1},{20,1},{21,1},{22,1},{1,2},{5,2},{10,2},{13,2},{18,2},{22,2},{1,3},{2,3},{3,3},{4,3},{5,3},{6,3},{7,3},{8,3},{10,3},{13,3},{15,3},{16,3},{17,3},{18,3},{19,3},{20,3},{21,3},{22,3},{3,4},{8,4},{10,4},{13,4},{15,4},{20,4},{1,5},{2,5},{3,5},{4,5},{5,5},{6,5},{8,5},{10,5},{13,5},{15,5},{17,5},{18,5},{19,5},{20,5},{21,5},{22,5},{3,6},{6,6},{8,6},{9,6},{10,6},{13,6},{14,6},{15,6},{17,6},{20,6},{3,7},{6,7},{8,7},{15,7},{17,7},{20,7},{3,8},{6,8},{8,8},{15,8},{17,8},{20,8},{1,9},{2,9},{3,9},{6,9},{7,9},{8,9},{9,9},{10,9},{11,9},{12,9},{13,9},{14,9},{15,9},{16,9},{17,9},{20,9},{21,9},{22,9},{2,10},{7,10},{16,10},{21,10},{2,11},{3,11},{4,11},{5,11},{6,11},{7,11},{16,11},{17,11},{18,11},{19,11},{20,11},{21,11},{2,12},{7,12},{16,12},{21,12},{1,13},{2,13},{3,13},{4,13},{5,13},{7,13},{16,13},{18,13},{19,13},{20,13},{21,13},{22,13},{1,14},{5,14},{7,14},{16,14},{18,14},{22,14},{1,15},{5,15},{7,15},{8,15},{9,15},{10,15},{11,15},{12,15},{13,15},{14,15},{15,15},{16,15},{18,15},{22,15},{1,16},{3,16},{4,16},{5,16},{10,16},{13,16},{18,16},{19,16},{20,16},{22,16},{1,17},{3,17},{5,17},{6,17},{7,17},{8,17},{9,17},{10,17},{13,17},{14,17},{15,17},{16,17},{17,17},{18,17},{20,17},{22,17},{1,18},{2,18},{3,18},{5,18},{7,18},{16,18},{18,18},{20,18},{21,18},{22,18},{3,19},{5,19},{7,19},{8,19},{9,19},{10,19},{11,19},{12,19},{13,19},{14,19},{15,19},{16,19},{18,19},{20,19},{3,20},{5,20},{10,20},{13,20},{18,20},{20,20},{1,21},{2,21},{3,21},{4,21},{5,21},{6,21},{7,21},{8,21},{9,21},{10,21},{13,21},{14,21},{15,21},{16,21},{17,21},{18,21},{19,21},{20,21},{21,21},{22,21},{1,22},{6,22},{8,22},{10,22},{13,22},{15,22},{17,22},{22,22},{1,23},{3,23},{4,23},{5,23},{6,23},{8,23},{10,23},{13,23},{15,23},{17,23},{18,23},{19,23},{20,23},{22,23},{1,24},{3,24},{8,24},{10,24},{13,24},{15,24},{20,24},{22,24},{1,25},{2,25},{3,25},{4,25},{5,25},{6,25},{7,25},{8,25},{10,25},{11,25},{12,25},{13,25},{15,25},{16,25},{17,25},{18,25},{19,25},{20,25},{21,25},{22,25}}
4488pacmice_maps["pacmice_2"].foods={{x=170,y=65},{x=390,y=65},{x=607,y=65},{x=347,y=201},{x=432,y=201},{x=390,y=278},{x=203,y=326},{x=574,y=326},{x=170,y=454},{x=345,y=487},{x=390,y=537},{x=435,y=487},{x=607,y=454},{x=170,y=638},{x=235,y=690},{x=390,y=690},{x=540,y=690},{x=607,y=642}}
4489pacmice_maps["pacmice_3"]={xml="pacmice_3",background_color="#010101",x=10,y=27,cell_w=26,cell_h=26,grid_w=31,grid_h=15,wall_size=14,web_x=-100,pac_count=1,axml=[[<C><P DS="m;360,85,440,85" MEDATA=";;;;-0;0::0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131:1-"/><Z><S><S T="12" X="190" Y="157" L="58" H="10" P="0,0,0.3,0.2,180,0,0,0"/><S T="12" X="612" Y="157" L="58" H="10" P="0,0,0.3,0.2,-180,0,0,0"/><S T="12" X="788" Y="208" L="369" H="10" P="0,0,0.6,0.2,90,0,0,0"/><S T="12" X="400" Y="27" L="10" H="781" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="400" Y="391" L="10" H="781" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="10" Y="208" L="372" H="10" P="0,0,0.6,0.2,90,0,0,0"/><S T="12" X="166" Y="119" L="10" H="84" P="0,0,0.6,0.2,180,0,0,0"/><S T="12" X="219" Y="69" L="10" H="84" P="0,0,0.6,0.2,180,0,0,0"/><S T="12" X="583" Y="69" L="10" H="84" P="0,0,0.6,0.2,180,0,0,0"/><S T="12" X="636" Y="119" L="10" H="84" P="0,0,0.6,0.2,-180,0,0,0"/><S T="12" X="401" Y="326" L="32" H="157" P="0,0,0.3,0.2,-450,0,0,0"/><S T="12" X="400" Y="44" L="32" H="157" P="0,0,0.3,0.2,-450,0,0,0"/><S T="12" X="258" Y="305" L="73" H="31" P="0,0,0.6,0.2,90,0,0,0"/><S T="12" X="158" Y="326" L="73" H="31" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="644" Y="326" L="73" H="31" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="544" Y="306" L="75" H="31" P="0,0,0.6,0.2,-90,0,0,0"/><S T="12" X="114" Y="223" L="81" H="10" P="0,0,0.6,0.2,90,0,0,0"/><S T="12" X="687" Y="223" L="81" H="10" P="0,0,0.6,0.2,-90,0,0,0"/><S T="12" X="62" Y="167" L="81" H="10" P="0,0,0.6,0.2,-90,0,0,0"/><S T="12" X="740" Y="167" L="81" H="10" P="0,0,0.6,0.2,90,0,0,0"/><S T="12" X="738" Y="327" L="34" H="10" P="0,0,0.6,0.2,90,0,0,0"/><S T="12" X="62" Y="327" L="34" H="10" P="0,0,0.6,0.2,-90,0,0,0"/><S T="12" X="322" Y="157" L="10" H="110" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="477" Y="157" L="10" H="108" P="0,0,0.3,0.2,-90,0,0,0"/><S T="12" X="271" Y="117" L="10" H="83" P="0,0,0.6,0.2,0,0,0,0"/><S T="12" X="400" Y="70" L="10" H="83" P="0,0,0.6,0.2,0,0,0,0"/><S T="12" X="530" Y="120" L="10" H="83" P="0,0,0.6,0.2,0,0,0,0"/><S T="12" X="219" Y="263" L="10" H="108" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="116" Y="351" L="10" H="82" P="0,0,0.6,0.2,0,0,0,0"/><S T="12" X="686" Y="350" L="10" H="78" P="0,0,0.6,0.2,0,0,0,0"/><S T="12" X="582" Y="263" L="10" H="107" P="0,0,0.3,0.2,-90,0,0,0"/><S T="12" X="217" Y="209" L="10" H="105" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="583" Y="209" L="10" H="106" P="0,0,0.3,0.2,-90,0,0,0"/><S T="12" X="66" Y="261" L="10" H="106" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="733" Y="261" L="10" H="99" P="0,0,0.3,0.2,-90,0,0,0"/><S T="12" X="89" Y="131" L="10" H="59" P="0,0,0.3,0.2,-90,0,0,0"/><S T="12" X="714" Y="131" L="10" H="59" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="65" Y="79" L="10" H="105" P="0,0,0.3,0.2,-90,0,0,0"/><S T="12" X="738" Y="79" L="10" H="105" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="400" Y="260" L="166" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="400" Y="106" L="162" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="342" Y="212" L="47" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="459" Y="212" L="47" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="400" Y="212" L="67" H="10" P="0,0,0.3,0.2,0,0,0,0" v="90000"/><S T="12" X="479" Y="236" L="54" H="10" P="0,0,0.3,0.2,90,0,0,0" v="90000"/><S T="12" X="322" Y="236" L="54" H="10" P="0,0,0.3,0.2,90,0,0,0" v="90000"/><S T="12" X="400" Y="410" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="90000"/><S T="12" X="400" Y="410" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="89000"/><S T="12" X="400" Y="410" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="88000"/><S T="12" X="400" Y="410" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="87000"/><S T="12" X="400" Y="410" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="86000"/><S T="12" X="400" Y="410" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="85000"/></S><D><F X="351" Y="248" D=""/><F X="450" Y="247" D=""/><T X="399" Y="254" D=""/></D><O/><L><JD c="1500fb,10,1,0" P1="788,27" P2="788,391"/><JD c="1500fb,10,1,0" P1="10,27" P2="10,391"/><JD c="1500fb,10,1,0" P1="787,27" P2="12,27"/><JD c="1500fb,10,1,0" P1="787,391" P2="12,391"/><JD c="1500fb,10,1,0" P1="478,106" P2="323,106"/><JD c="1500fb,10,1,0" P1="400,29" P2="400,106"/><JD c="FFFFFF,10,1,0" M1="46" M2="46" P1="429,212.41" P2="371,212.41"/><JD c="FFFFFF,10,1,0" M1="46" M2="46" P1="478.59,259" P2="478.59,213"/><JD c="FFFFFF,10,1,0" M1="46" M2="46" P1="321.59,259" P2="321.59,213"/><JD c="1500fb,10,1,0" M1="47" M2="47" P1="429,212.41" P2="371,212.41"/><JD c="1500fb,10,1,0" M1="47" M2="47" P1="478.59,259" P2="478.59,213"/><JD c="1500fb,10,1,0" M1="47" M2="47" P1="321.59,259" P2="321.59,213"/><JD c="FFFFFF,10,1,0" M1="48" M2="48" P1="429,212.41" P2="371,212.41"/><JD c="FFFFFF,10,1,0" M1="48" M2="48" P1="478.59,259" P2="478.59,213"/><JD c="FFFFFF,10,1,0" M1="48" M2="48" P1="321.59,259" P2="321.59,213"/><JD c="1500fb,10,1,0" M1="49" M2="49" P1="429,212.41" P2="371,212.41"/><JD c="1500fb,10,1,0" M1="49" M2="49" P1="478.59,259" P2="478.59,213"/><JD c="1500fb,10,1,0" M1="49" M2="49" P1="321.59,259" P2="321.59,213"/><JD c="FFFFFF,10,1,0" M1="50" M2="50" P1="429,212.41" P2="371,212.41"/><JD c="FFFFFF,10,1,0" M1="50" M2="50" P1="478.59,259" P2="478.59,213"/><JD c="FFFFFF,10,1,0" M1="50" M2="50" P1="321.59,259" P2="321.59,213"/><JD c="1500fb,10,1,0" M1="51" M2="51" P1="429,212.41" P2="371,212.41"/><JD c="1500fb,10,1,0" M1="51" M2="51" P1="478.59,259" P2="478.59,213"/><JD c="1500fb,10,1,0" M1="51" M2="51" P1="321.59,259" P2="321.59,213"/><JD c="1500fb,10,1,0" P1="738,314" P2="738,339"/><JD c="1500fb,10,1,0" P1="62,314" P2="62,339"/><JD c="1500fb,10,1,0" P1="478,260" P2="322,260"/><JD c="1500fb,10,1,0" P1="271,80" P2="271,156"/><JD c="1500fb,10,1,0" P1="530,83" P2="530,155"/><JD c="1500fb,10,1,0" P1="166,82" P2="166,155"/><JD c="1500fb,10,1,0" P1="219,28" P2="219,105"/><JD c="1500fb,10,1,0" P1="583,28" P2="583,105"/><JD c="1500fb,10,1,0" P1="636,82" P2="636,155"/><JD c="1500fb,10,1,0" P1="114,186" P2="114,260"/><JD c="1500fb,10,1,0" P1="687,186" P2="687,260"/><JD c="1500fb,10,1,0" P1="62,131" P2="62,204"/><JD c="1500fb,10,1,0" P1="740,131" P2="740,204"/><JD c="1500fb,10,1,0" P1="361,212" P2="322,212"/><JD c="1500fb,10,1,0" P1="439,212" P2="478,212"/><JD c="1500fb,10,1,0" P1="372,157" P2="271,157"/><JD c="1500fb,10,1,0" P1="428,157" P2="530,157"/><JD c="1500fb,10,1,0" P1="266,209" P2="168,209"/><JD c="1500fb,3,1,0" P1="323,31" P2="323,58"/><JD c="1500fb,10,1,0" P1="533,209" P2="632,209"/><JD c="1500fb,10,1,0" P1="269,263" P2="169,263"/><JD c="1500fb,3,1,0" P1="477,31" P2="477,58"/><JD c="1500fb,10,1,0" P1="116.45,314.92" P2="116.45,389.92"/><JD c="1500fb,10,1,0" P1="686.05,314.92" P2="686.05,389.92"/><JD c="1500fb,10,1,0" P1="534,263" P2="632,263"/><JD c="1500fb,10,1,0" P1="215,157" P2="166,157"/><JD c="1500fb,10,1,0" P1="587,157" P2="636,157"/><JD c="1500fb,10,1,0" P1="113,131" P2="62,131"/><JD c="1500fb,10,1,0" P1="689,131" P2="740,131"/><JD c="1500fb,10,1,0" P1="113,261" P2="10,261"/><JD c="1500fb,10,1,0" P1="688,261" P2="787,261"/><JD c="1500fb,10,1,0" P1="113,79" P2="10,79"/><JD c="1500fb,10,1,0" P1="689,79" P2="788,79"/><JD c="1500fb,3,1,0" P1="323,58" P2="477,58"/><JD c="000000,6,1,0" P1="787,27" P2="12,27"/><JD c="000000,6,1,0" P1="787,391" P2="12,391"/><JD c="000000,6,1,0" P1="478,106" P2="323,106"/><JD c="000000,6,1,0" P1="400,29" P2="400,106"/><JD c="000000,6,1,0" M1="46" M2="46" P1="429,212.41" P2="371,212.41"/><JD c="000000,6,1,0" M1="46" M2="46" P1="478.59,259" P2="478.59,213"/><JD c="000000,6,1,0" M1="46" M2="46" P1="321.59,259" P2="321.59,213"/><JD c="000000,6,1,0" P1="738,314" P2="738,339"/><JD c="000000,6,1,0" P1="62,314" P2="62,339"/><JD c="1500fb,3,1,0" P1="272,261" P2="272,340"/><JD c="1500fb,3,1,0" P1="114.45,311.92" P2="193.45,311.92"/><JD c="1500fb,3,1,0" P1="688.05,311.92" P2="609.05,311.92"/><JD c="1500fb,3,1,0" P1="530,261" P2="530,342"/><JD c="000000,6,1,0" P1="10,27" P2="10,391"/><JD c="000000,6,1,0" P1="478,260" P2="322,260"/><JD c="000000,6,1,0" P1="271,80" P2="271,156"/><JD c="000000,6,1,0" P1="530,83" P2="530,155"/><JD c="000000,6,1,0" P1="166,82" P2="166,155"/><JD c="000000,6,1,0" P1="219,28" P2="219,105"/><JD c="000000,6,1,0" P1="583,28" P2="583,105"/><JD c="000000,6,1,0" P1="636,82" P2="636,155"/><JD c="000000,6,1,0" P1="114,186" P2="114,260"/><JD c="000000,6,1,0" P1="687,186" P2="687,260"/><JD c="000000,6,1,0" P1="62,131" P2="62,204"/><JD c="000000,6,1,0" P1="740,131" P2="740,204"/><JD c="000000,6,1,0" P1="361,212" P2="322,212"/><JD c="000000,6,1,0" P1="439,212" P2="478,212"/><JD c="000000,6,1,0" P1="372,157" P2="271,157"/><JD c="000000,6,1,0" P1="428,157" P2="530,157"/><JD c="000000,6,1,0" P1="266,209" P2="168,209"/><JD c="000000,6,1,0" P1="533,209" P2="632,209"/><JD c="000000,6,1,0" P1="267,263" P2="169,263"/><JD c="000000,6,1,0" P1="116.45,316.92" P2="116.45,389.92"/><JD c="000000,6,1,0" P1="686.05,316.92" P2="686.05,389.92"/><JD c="000000,6,1,0" P1="535,263" P2="632,263"/><JD c="000000,6,1,0" P1="215,157" P2="166,157"/><JD c="000000,6,1,0" P1="587,157" P2="636,157"/><JD c="000000,6,1,0" P1="113,131" P2="62,131"/><JD c="000000,6,1,0" P1="689,131" P2="740,131"/><JD c="000000,6,1,0" P1="113,261" P2="10,261"/><JD c="000000,6,1,0" P1="688,261" P2="787,261"/><JD c="000000,6,1,0" P1="113,79" P2="10,79"/><JD c="000000,6,1,0" P1="689,79" P2="788,79"/><JD c="1500fb,3,1,0" P1="324,312" P2="324,340"/><JD c="000000,6,1,0" P1="788,27" P2="788,391"/><JD c="1500fb,3,1,0" P1="478,312" P2="478,340"/><JD c="1500fb,3,1,0" P1="244,268" P2="244,340"/><JD c="1500fb,3,1,0" P1="121.45,339.92" P2="193.45,339.92"/><JD c="1500fb,3,1,0" P1="681.05,339.92" P2="609.05,339.92"/><JD c="1500fb,3,1,0" P1="558,268" P2="558,342"/><JD c="1500fb,3,1,0" P1="272,340" P2="244,340"/><JD c="1500fb,3,1,0" P1="193.45,311.92" P2="193.45,339.92"/><JD c="1500fb,3,1,0" P1="609.05,311.92" P2="609.05,339.92"/><JD c="1500fb,3,1,0" P1="530,342" P2="558,342"/><JD c="1500fb,3,1,0" P1="324,312" P2="478,312"/><JD c="1500fb,3,1,0" P1="324,340" P2="478,340"/><JD c="000000,3,1,0" P1="247,267" P2="267,267"/><JD c="000000,3,1,0" P1="326,31" P2="473,31"/><JD c="000000,3,1,0" P1="390,55" P2="410,55"/><JD c="000000,3,1,0" P1="120.45,336.92" P2="120.45,316.92"/><JD c="000000,3,1,0" P1="682.05,336.92" P2="682.05,316.92"/><JD c="000000,3,1,0" P1="555,267" P2="535,267"/><JD c="000000,3,1,0" P1="269,263" P2="269,288"/><JD c="000000,3,1,0" P1="404,29" P2="404,54"/><JD c="000000,3,1,0" P1="116.45,314.92" P2="141.45,314.92"/><JD c="000000,3,1,0" P1="686.05,314.92" P2="661.05,314.92"/><JD c="000000,3,1,0" P1="533,263" P2="533,288"/><JD c="000000,3,1,0" P1="247,265" P2="247,288"/><JD c="000000,3,1,0" P1="396,30" P2="396,53"/><JD c="000000,3,1,0" P1="474,31" P2="474,54"/><JD c="000000,3,1,0" P1="326,31" P2="326,54"/><JD c="000000,3,1,0" P1="118.45,336.92" P2="141.45,336.92"/><JD c="000000,3,1,0" P1="684.05,336.92" P2="661.05,336.92"/><JD c="000000,3,1,0" P1="555,265" P2="555,288"/></L></Z></C>]]}
4490pacmice_maps["pacmice_3"].pathes={{1,1},{2,1},{3,1},{4,1},{5,1},{6,1},{7,1},{9,1},{10,1},{11,1},{19,1},{20,1},{21,1},{23,1},{24,1},{25,1},{26,1},{27,1},{28,1},{29,1},{5,2},{7,2},{9,2},{11,2},{12,2},{13,2},{14,2},{16,2},{17,2},{18,2},{19,2},{21,2},{23,2},{25,2},{1,3},{2,3},{3,3},{4,3},{5,3},{7,3},{9,3},{11,3},{19,3},{21,3},{23,3},{25,3},{26,3},{27,3},{28,3},{29,3},{1,4},{5,4},{7,4},{8,4},{9,4},{11,4},{12,4},{13,4},{14,4},{15,4},{16,4},{17,4},{18,4},{19,4},{21,4},{22,4},{23,4},{25,4},{29,4},{1,5},{3,5},{4,5},{5,5},{9,5},{15,5},{21,5},{25,5},{26,5},{27,5},{29,5},{1,6},{3,6},{5,6},{6,6},{7,6},{8,6},{9,6},{10,6},{11,6},{12,6},{13,6},{14,6},{15,6},{16,6},{17,6},{18,6},{19,6},{20,6},{21,6},{22,6},{23,6},{24,6},{25,6},{27,6},{29,6},{1,7},{3,7},{5,7},{11,7},{19,7},{25,7},{27,7},{29,7},{1,8},{2,8},{3,8},{5,8},{6,8},{7,8},{8,8},{9,8},{10,8},{11,8},{19,8},{20,8},{21,8},{22,8},{23,8},{24,8},{25,8},{27,8},{28,8},{29,8},{5,9},{11,9},{19,9},{25,9},{1,10},{2,10},{3,10},{4,10},{5,10},{6,10},{7,10},{8,10},{11,10},{12,10},{13,10},{14,10},{15,10},{16,10},{17,10},{18,10},{19,10},{22,10},{23,10},{24,10},{25,10},{26,10},{27,10},{28,10},{29,10},{1,11},{3,11},{8,11},{11,11},{19,11},{22,11},{27,11},{29,11},{1,12},{3,12},{8,12},{11,12},{19,12},{22,12},{27,12},{29,12},{1,13},{2,13},{3,13},{5,13},{6,13},{7,13},{8,13},{9,13},{10,13},{11,13},{12,13},{13,13},{14,13},{15,13},{16,13},{17,13},{18,13},{19,13},{20,13},{21,13},{22,13},{23,13},{24,13},{25,13},{27,13},{28,13},{29,13}}
4491pacmice_maps["pacmice_3"].foods={{x=35,y=53},{x=191,y=130},{x=62,y=235},{x=35,y=364},{x=145,y=364},{x=250,y=235},{x=400,y=189},{x=400,y=364},{x=545,y=235},{x=605,y=130},{x=657,y=364},{x=765,y=364},{x=740,y=235},{x=765,y=53}}
4492pacmice_maps["pacmice_4"]={xml="pacmice_4",background_color="#010101",x=10,y=27,cell_w=26,cell_h=26,grid_w=31,grid_h=15,wall_size=14,web_x=-100,pac_count=1,axml=[[<C><P DS="m;258,58,545,58" MEDATA=";;;;-0;0::0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128:1-"/><Z><S><S T="12" X="190" Y="259" L="58" H="10" P="0,0,0.3,0.2,720,0,0,0"/><S T="12" X="610" Y="260" L="58" H="10" P="0,0,0.3,0.2,360,0,0,0"/><S T="12" X="788" Y="210" L="369" H="10" P="0,0,0.6,0.2,630,0,0,0"/><S T="12" X="400" Y="27" L="10" H="781" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="400" Y="391" L="10" H="781" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="10" Y="210" L="372" H="10" P="0,0,0.6,0.2,630,0,0,0"/><S T="12" X="166" Y="297" L="10" H="84" P="0,0,0.6,0.2,720,0,0,0"/><S T="12" X="218" Y="347" L="10" H="84" P="0,0,0.6,0.2,720,0,0,0"/><S T="12" X="582" Y="347" L="10" H="84" P="0,0,0.6,0.2,720,0,0,0"/><S T="12" X="634" Y="298" L="10" H="84" P="0,0,0.6,0.2,360,0,0,0"/><S T="12" X="401" Y="90" L="32" H="157" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="400" Y="377" L="32" H="157" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="258" Y="111" L="73" H="31" P="0,0,0.6,0.2,630,0,0,0"/><S T="12" X="157" Y="91" L="73" H="31" P="0,0,0.3,0.2,540,0,0,0"/><S T="12" X="645" Y="91" L="73" H="31" P="0,0,0.3,0.2,540,0,0,0"/><S T="12" X="544" Y="110" L="75" H="31" P="0,0,0.6,0.2,450,0,0,0"/><S T="12" X="114" Y="193" L="81" H="10" P="0,0,0.6,0.2,630,0,0,0"/><S T="12" X="687" Y="193" L="81" H="10" P="0,0,0.6,0.2,450,0,0,0"/><S T="12" X="62" Y="249" L="81" H="10" P="0,0,0.6,0.2,450,0,0,0"/><S T="12" X="739" Y="250" L="81" H="10" P="0,0,0.6,0.2,630,0,0,0"/><S T="12" X="738" Y="89" L="34" H="10" P="0,0,0.6,0.2,630,0,0,0"/><S T="12" X="62" Y="89" L="34" H="10" P="0,0,0.6,0.2,450,0,0,0"/><S T="12" X="285" Y="261" L="34" H="10" P="0,0,0.6,0.2,540,0,0,0"/><S T="12" X="518" Y="262" L="34" H="10" P="0,0,0.6,0.2,540,0,0,0"/><S T="12" X="400" Y="260" L="10" H="110" P="0,0,0.3,0.2,630,0,0,0"/><S T="12" X="271" Y="300" L="10" H="83" P="0,0,0.6,0.2,540,0,0,0"/><S T="12" X="530" Y="298" L="10" H="83" P="0,0,0.6,0.2,540,0,0,0"/><S T="12" X="219" Y="157" L="10" H="108" P="0,0,0.3,0.2,630,0,0,0"/><S T="12" X="115" Y="66" L="10" H="82" P="0,0,0.6,0.2,540,0,0,0"/><S T="12" X="687" Y="67" L="10" H="78" P="0,0,0.6,0.2,540,0,0,0"/><S T="12" X="582" Y="157" L="10" H="107" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="217" Y="207" L="10" H="105" P="0,0,0.3,0.2,630,0,0,0"/><S T="12" X="583" Y="207" L="10" H="106" P="0,0,0.3,0.2,450,0,0,0"/><S T="12" X="66" Y="155" L="10" H="106" P="0,0,0.3,0.2,630,0,0,0"/><S T="12" X="733" Y="155" L="10" H="99" P="0,0,0.3,0.2,450,0,0,0"/><S T="12" X="89" Y="285" L="10" H="59" P="0,0,0.3,0.2,450,0,0,0"/><S T="12" X="713" Y="286" L="10" H="59" P="0,0,0.3,0.2,630,0,0,0"/><S T="12" X="65" Y="338" L="10" H="105" P="0,0,0.3,0.2,450,0,0,0"/><S T="12" X="738" Y="337" L="10" H="105" P="0,0,0.3,0.2,630,0,0,0"/><S T="12" X="400" Y="206" L="166" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="400" Y="312" L="162" H="10" P="0,0,0.3,0.2,540,0,0,0"/><S T="12" X="479" Y="181" L="10" H="49" P="0,0,0.6,0.2,0,0,0,0" v="90000"/><S T="12" X="323" Y="181" L="10" H="49" P="0,0,0.6,0.2,0,0,0,0" v="90000"/><S T="12" X="342" Y="158" L="47" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="459" Y="158" L="47" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="400" Y="158" L="67" H="10" P="0,0,0.3,0.2,0,0,0,0" v="90000"/><S T="12" X="400" Y="408" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="85000"/><S T="12" X="400" Y="448" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="85000"/><S T="12" X="400" Y="408" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="86000"/><S T="12" X="400" Y="448" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="86000"/><S T="12" X="400" Y="407" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="87000"/><S T="12" X="400" Y="447" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="87000"/><S T="12" X="400" Y="408" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="88000"/><S T="12" X="400" Y="448" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="88000"/><S T="12" X="400" Y="408" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="89000"/><S T="12" X="400" Y="448" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="89000"/><S T="12" X="400" Y="408" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="90000"/><S T="12" X="400" Y="448" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="90000"/></S><D><F X="352" Y="195" D=""/><F X="452" Y="195" D=""/><T X="402" Y="201" D=""/></D><O/><L><JD c="1500fb,10,1,0" P1="788,391" P2="788,27"/><JD c="1500fb,10,1,0" P1="10,391" P2="10,27"/><JD c="1500fb,10,1,0" P1="787,27" P2="12,27"/><JD c="1500fb,10,1,0" P1="787,391" P2="12,391"/><JD c="1500fb,10,1,0" P1="477,312" P2="324,312"/><JD c="FFFFFF,10,1,0" M1="56" M2="56" P1="431,159" P2="373,159"/><JD c="1500fb,10,1,0" M1="54" M2="54" P1="431,159" P2="373,159"/><JD c="FFFFFF,10,1,0" M1="52" M2="52" P1="431,159" P2="373,159"/><JD c="1500fb,10,1,0" M1="50" M2="50" P1="431,159" P2="373,159"/><JD c="FFFFFF,10,1,0" M1="48" M2="48" P1="431,159" P2="373,159"/><JD c="1500fb,10,1,0" M1="46" M2="46" P1="431,159" P2="373,159"/><JD c="1500fb,10,1,0" P1="738,102" P2="738,77"/><JD c="1500fb,10,1,0" P1="62,102" P2="62,77"/><JD c="1500fb,10,1,0" P1="272,261" P2="297,261"/><JD c="1500fb,10,1,0" P1="505,262" P2="530,262"/><JD c="1500fb,10,1,0" P1="480,207" P2="324,207"/><JD c="1500fb,10,1,0" P1="271,337" P2="271,261"/><JD c="1500fb,10,1,0" P1="530,335" P2="530,263"/><JD c="1500fb,10,1,0" P1="166,334" P2="166,261"/><JD c="1500fb,10,1,0" P1="218,388" P2="218,311"/><JD c="1500fb,10,1,0" P1="582,388" P2="582,311"/><JD c="1500fb,10,1,0" P1="634,335" P2="634,262"/><JD c="1500fb,10,1,0" P1="114,230" P2="114,156"/><JD c="1500fb,10,1,0" P1="687,230" P2="687,156"/><JD c="1500fb,10,1,0" P1="62,285" P2="62,212"/><JD c="1500fb,10,1,0" P1="739,286" P2="739,213"/><JD c="1500fb,10,1,0" P1="363,159" P2="324,159"/><JD c="1500fb,10,1,0" P1="441,159" P2="480,159"/><JD c="FFFFFF,10,1,0" M1="57" M2="57" P1="480,159" P2="480,206"/><JD c="FFFFFF,10,1,0" M1="57" M2="57" P1="323,159" P2="323,206"/><JD c="1500fb,10,1,0" M1="55" M2="55" P1="480,159" P2="480,206"/><JD c="1500fb,10,1,0" M1="55" M2="55" P1="323,159" P2="323,206"/><JD c="FFFFFF,10,1,0" M1="53" M2="53" P1="480,159" P2="480,206"/><JD c="FFFFFF,10,1,0" M1="53" M2="53" P1="323,159" P2="323,206"/><JD c="1500fb,10,1,0" M1="51" M2="51" P1="480,159" P2="480,206"/><JD c="1500fb,10,1,0" M1="51" M2="51" P1="323,159" P2="323,206"/><JD c="FFFFFF,10,1,0" M1="49" M2="49" P1="480,159" P2="480,206"/><JD c="FFFFFF,10,1,0" M1="49" M2="49" P1="323,159" P2="323,206"/><JD c="1500fb,10,1,0" M1="47" M2="47" P1="480,159" P2="480,206"/><JD c="1500fb,10,1,0" M1="47" M2="47" P1="323,159" P2="323,206"/><JD c="1500fb,10,1,0" P1="450,260" P2="349,260"/><JD c="1500fb,10,1,0" P1="266,207" P2="168,207"/><JD c="1500fb,3,1,0" P1="323,390" P2="323,363"/><JD c="1500fb,10,1,0" P1="533,207" P2="632,207"/><JD c="1500fb,10,1,0" P1="268,157" P2="169,157"/><JD c="1500fb,3,1,0" P1="477,390" P2="477,363"/><JD c="1500fb,10,1,0" P1="115.45,102.08" P2="115.45,27.08"/><JD c="1500fb,10,1,0" P1="687.05,102.08" P2="687.05,27.08"/><JD c="1500fb,10,1,0" P1="534,157" P2="632,157"/><JD c="1500fb,10,1,0" P1="215,259" P2="166,259"/><JD c="1500fb,10,1,0" P1="585,260" P2="634,260"/><JD c="1500fb,10,1,0" P1="113,285" P2="62,285"/><JD c="1500fb,10,1,0" P1="688,286" P2="739,286"/><JD c="1500fb,10,1,0" P1="113,155" P2="10,155"/><JD c="1500fb,10,1,0" P1="688,155" P2="787,155"/><JD c="1500fb,10,1,0" P1="113,338" P2="10,338"/><JD c="1500fb,10,1,0" P1="689,337" P2="788,337"/><JD c="1500fb,3,1,0" P1="323,363" P2="477,363"/><JD c="000000,6,1,0" P1="787,27" P2="12,27"/><JD c="000000,6,1,0" P1="787,391" P2="12,391"/><JD c="000000,6,1,0" P1="477,312" P2="324,312"/><JD c="000000,6,1,0" M1="56" M2="56" P1="431,159" P2="373,159"/><JD c="000000,6,1,0" P1="738,102" P2="738,77"/><JD c="000000,6,1,0" P1="62,102" P2="62,77"/><JD c="000000,6,1,0" P1="272,261" P2="297,261"/><JD c="000000,6,1,0" P1="505,262" P2="530,262"/><JD c="1500fb,3,1,0" P1="272,158" P2="272,75"/><JD c="1500fb,3,1,0" P1="113.45,105.08" P2="192.45,105.08"/><JD c="1500fb,3,1,0" P1="689.05,105.08" P2="610.05,105.08"/><JD c="1500fb,3,1,0" P1="530,156" P2="530,74"/><JD c="000000,6,1,0" P1="10,391" P2="10,27"/><JD c="000000,6,1,0" P1="480,207" P2="324,207"/><JD c="000000,6,1,0" P1="271,337" P2="271,261"/><JD c="000000,6,1,0" P1="530,335" P2="530,263"/><JD c="000000,6,1,0" P1="166,334" P2="166,261"/><JD c="000000,6,1,0" P1="218,388" P2="218,311"/><JD c="000000,6,1,0" P1="582,388" P2="582,311"/><JD c="000000,6,1,0" P1="634,335" P2="634,262"/><JD c="000000,6,1,0" P1="114,230" P2="114,156"/><JD c="000000,6,1,0" P1="687,230" P2="687,156"/><JD c="000000,6,1,0" P1="62,285" P2="62,212"/><JD c="000000,6,1,0" P1="739,286" P2="739,213"/><JD c="000000,6,1,0" P1="363,159" P2="324,159"/><JD c="000000,6,1,0" P1="441,159" P2="480,159"/><JD c="000000,6,1,0" M1="57" M2="57" P1="480,159" P2="480,206"/><JD c="000000,6,1,0" M1="57" M2="57" P1="323,159" P2="323,206"/><JD c="000000,6,1,0" P1="450,260" P2="349,260"/><JD c="000000,6,1,0" P1="266,207" P2="168,207"/><JD c="000000,6,1,0" P1="533,207" P2="632,207"/><JD c="000000,6,1,0" P1="268,157" P2="169,157"/><JD c="000000,6,1,0" P1="115.45,100.08" P2="115.45,27.08"/><JD c="000000,6,1,0" P1="687.05,100.08" P2="687.05,27.08"/><JD c="000000,6,1,0" P1="535,157" P2="632,157"/><JD c="000000,6,1,0" P1="215,259" P2="166,259"/><JD c="000000,6,1,0" P1="585,260" P2="634,260"/><JD c="000000,6,1,0" P1="113,285" P2="62,285"/><JD c="000000,6,1,0" P1="688,286" P2="739,286"/><JD c="000000,6,1,0" P1="113,155" P2="10,155"/><JD c="000000,6,1,0" P1="688,155" P2="787,155"/><JD c="000000,6,1,0" P1="113,338" P2="10,338"/><JD c="000000,6,1,0" P1="689,337" P2="788,337"/><JD c="1500fb,3,1,0" P1="324,104" P2="324,76"/><JD c="000000,6,1,0" P1="788,391" P2="788,27"/><JD c="1500fb,3,1,0" P1="478,104" P2="478,76"/><JD c="1500fb,3,1,0" P1="244,152" P2="244,76"/><JD c="1500fb,3,1,0" P1="120.45,77.08" P2="192.45,77.08"/><JD c="1500fb,3,1,0" P1="682.05,77.08" P2="610.05,77.08"/><JD c="1500fb,3,1,0" P1="558,152" P2="558,74"/><JD c="1500fb,3,1,0" P1="272,76" P2="244,76"/><JD c="1500fb,3,1,0" P1="192.45,105.08" P2="192.45,77.08"/><JD c="1500fb,3,1,0" P1="610.05,105.08" P2="610.05,77.08"/><JD c="1500fb,3,1,0" P1="530,74" P2="558,74"/><JD c="1500fb,3,1,0" P1="324,104" P2="478,104"/><JD c="1500fb,3,1,0" P1="324,76" P2="478,76"/><JD c="000000,3,1,0" P1="247,153" P2="267,153"/><JD c="000000,3,1,0" P1="326,387" P2="474,387"/><JD c="000000,3,1,0" P1="119.45,80.08" P2="119.45,100.08"/><JD c="000000,3,1,0" P1="683.05,80.08" P2="683.05,100.08"/><JD c="000000,3,1,0" P1="555,153" P2="535,153"/><JD c="000000,3,1,0" P1="269,157" P2="269,132"/><JD c="000000,3,1,0" P1="474,391" P2="474,368"/><JD c="000000,3,1,0" P1="115.45,102.08" P2="140.45,102.08"/><JD c="000000,3,1,0" P1="687.05,102.08" P2="662.05,102.08"/><JD c="000000,3,1,0" P1="533,157" P2="533,132"/><JD c="000000,3,1,0" P1="247,155" P2="247,132"/><JD c="000000,3,1,0" P1="326,389" P2="326,368"/><JD c="000000,3,1,0" P1="117.45,80.08" P2="140.45,80.08"/><JD c="000000,3,1,0" P1="685.05,80.08" P2="662.05,80.08"/><JD c="000000,3,1,0" P1="555,155" P2="555,132"/></L></Z></C>]]}
4493pacmice_maps["pacmice_4"].pathes={{1,1},{2,1},{3,1},{5,1},{6,1},{7,1},{8,1},{9,1},{10,1},{11,1},{12,1},{13,1},{14,1},{15,1},{16,1},{17,1},{18,1},{19,1},{20,1},{21,1},{22,1},{23,1},{24,1},{25,1},{27,1},{28,1},{29,1},{1,2},{3,2},{8,2},{11,2},{19,2},{22,2},{27,2},{29,2},{1,3},{3,3},{8,3},{11,3},{19,3},{22,3},{27,3},{29,3},{1,4},{2,4},{3,4},{4,4},{5,4},{6,4},{7,4},{8,4},{11,4},{12,4},{13,4},{14,4},{15,4},{16,4},{17,4},{18,4},{19,4},{22,4},{23,4},{24,4},{25,4},{26,4},{27,4},{28,4},{29,4},{5,5},{11,5},{19,5},{25,5},{1,6},{2,6},{3,6},{5,6},{6,6},{7,6},{8,6},{9,6},{10,6},{11,6},{19,6},{20,6},{21,6},{22,6},{23,6},{24,6},{25,6},{27,6},{28,6},{29,6},{1,7},{3,7},{5,7},{11,7},{19,7},{25,7},{27,7},{29,7},{1,8},{3,8},{5,8},{6,8},{7,8},{8,8},{9,8},{10,8},{11,8},{12,8},{13,8},{14,8},{15,8},{16,8},{17,8},{18,8},{19,8},{20,8},{21,8},{22,8},{23,8},{24,8},{25,8},{27,8},{29,8},{1,9},{3,9},{4,9},{5,9},{9,9},{12,9},{18,9},{21,9},{25,9},{26,9},{27,9},{29,9},{1,10},{5,10},{7,10},{8,10},{9,10},{11,10},{12,10},{13,10},{14,10},{15,10},{16,10},{17,10},{18,10},{19,10},{21,10},{22,10},{23,10},{25,10},{29,10},{1,11},{2,11},{3,11},{4,11},{5,11},{7,11},{9,11},{11,11},{19,11},{21,11},{23,11},{25,11},{26,11},{27,11},{28,11},{29,11},{5,12},{7,12},{9,12},{11,12},{12,12},{13,12},{14,12},{15,12},{16,12},{17,12},{18,12},{19,12},{21,12},{23,12},{25,12},{1,13},{2,13},{3,13},{4,13},{5,13},{6,13},{7,13},{9,13},{10,13},{11,13},{19,13},{20,13},{21,13},{23,13},{24,13},{25,13},{26,13},{27,13},{28,13},{29,13}}
4494pacmice_maps["pacmice_4"].foods={{x=60,y=55},{x=400,y=55},{x=735,y=55},{x=400,y=130},{x=218,y=182},{x=579,y=182},{x=35,y=240},{x=400,y=240},{x=763,y=240},{x=195,y=285},{x=605,y=285},{x=35,y=365},{x=400,y=335},{x=763,y=365}}
4495pacmice_maps["pacmice_5"]={xml="pacmice_5",background_color="#010101",x=10,y=35,cell_w=26,cell_h=26,grid_w=31,grid_h=24,wall_size=14,web_x=-100,pac_count=2,axml=[[<C><P H="640" DS="m;205,120,595,120" MEDATA=";;;;-0;0::0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226:1-"/><Z><S><S T="12" X="191" Y="191" L="58" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="612" Y="191" L="58" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="190" Y="477" L="58" H="10" P="0,0,0.3,0.2,180,0,0,0"/><S T="12" X="612" Y="477" L="58" H="10" P="0,0,0.3,0.2,-180,0,0,0"/><S T="12" X="788" Y="334" L="605" H="10" P="0,0,0.7,0.2,90,0,0,0"/><S T="12" X="400" Y="35" L="10" H="781" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="686" Y="634" L="10" H="213" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="294" Y="634" L="10" H="574" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="10" Y="334" L="608" H="10" P="0,0,0.7,0.2,90,0,0,0"/><S T="12" X="166" Y="229" L="10" H="84" P="0,0,0.7,0.2,0,0,0,0"/><S T="12" X="636" Y="229" L="10" H="84" P="0,0,0.7,0.2,0,0,0,0"/><S T="12" X="166" Y="439" L="10" H="84" P="0,0,0.7,0.2,180,0,0,0"/><S T="12" X="636" Y="439" L="10" H="84" P="0,0,0.7,0.2,-180,0,0,0"/><S T="12" X="243" Y="334" L="30" H="55" P="0,0,0.3,0.2,450,0,0,0"/><S T="12" X="334" Y="364" L="30" H="32" P="0,0,0.3,0.2,450,0,0,0"/><S T="12" X="465" Y="364" L="30" H="32" P="0,0,0.3,0.2,450,0,0,0"/><S T="12" X="558" Y="334" L="30" H="55" P="0,0,0.3,0.2,-450,0,0,0"/><S T="12" X="114" Y="334" L="32" H="107" P="0,0,0.3,0.2,450,0,0,0"/><S T="12" X="686" Y="334" L="32" H="107" P="0,0,0.3,0.2,-450,0,0,0"/><S T="12" X="309" Y="117" L="50" H="31" P="0,0,0.7,0.2,90,0,0,0"/><S T="12" X="493" Y="117" L="50" H="31" P="0,0,0.7,0.2,-90,0,0,0"/><S T="12" X="308" Y="553" L="50" H="31" P="0,0,0.7,0.2,90,0,0,0"/><S T="12" X="491" Y="554" L="50" H="31" P="0,0,0.7,0.2,-90,0,0,0"/><S T="12" X="181" Y="62" L="50" H="35" P="0,0,0.7,0.2,90,0,0,0"/><S T="12" X="621" Y="62" L="50" H="35" P="0,0,0.7,0.2,-90,0,0,0"/><S T="12" X="180" Y="606" L="50" H="35" P="0,0,0.7,0.2,90,0,0,0"/><S T="12" X="621" Y="606" L="50" H="35" P="0,0,0.7,0.2,-90,0,0,0"/><S T="12" X="115" Y="125" L="81" H="10" P="0,0,0.7,0.2,90,0,0,0"/><S T="12" X="687" Y="125" L="81" H="10" P="0,0,0.7,0.2,-90,0,0,0"/><S T="12" X="115" Y="543" L="81" H="10" P="0,0,0.7,0.2,90,0,0,0"/><S T="12" X="687" Y="543" L="81" H="10" P="0,0,0.7,0.2,-90,0,0,0"/><S T="12" X="62" Y="181" L="81" H="10" P="0,0,0.7,0.2,270,0,0,0"/><S T="12" X="740" Y="181" L="81" H="10" P="0,0,0.7,0.2,-270,0,0,0"/><S T="12" X="62" Y="487" L="81" H="10" P="0,0,0.7,0.2,-90,0,0,0"/><S T="12" X="740" Y="487" L="81" H="10" P="0,0,0.7,0.2,90,0,0,0"/><S T="12" X="400" Y="51" L="23" H="60" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="400" Y="617" L="23" H="60" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="375" Y="154" L="81" H="10" P="0,0,0.7,0.2,90,0,0,0"/><S T="12" X="426" Y="154" L="81" H="10" P="0,0,0.7,0.2,-90,0,0,0"/><S T="12" X="374" Y="519" L="85" H="10" P="0,0,0.7,0.2,90,0,0,0"/><S T="12" X="426" Y="518" L="89" H="10" P="0,0,0.7,0.2,-90,0,0,0"/><S T="12" X="326" Y="191" L="10" H="107" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="477" Y="191" L="10" H="107" P="0,0,0.3,0.2,-90,0,0,0"/><S T="12" X="320" Y="480" L="10" H="107" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="477" Y="477" L="10" H="108" P="0,0,0.3,0.2,-90,0,0,0"/><S T="12" X="219" Y="334" L="10" H="183" P="0,0,0.7,0.2,180,0,0,0"/><S T="12" X="582" Y="334" L="10" H="183" P="0,0,0.7,0.2,-180,0,0,0"/><S T="12" X="272" Y="227" L="10" H="83" P="0,0,0.7,0.2,180,0,0,0"/><S T="12" X="530" Y="228" L="10" H="83" P="0,0,0.3,0.2,-180,0,0,0"/><S T="12" X="271" Y="440" L="10" H="83" P="0,0,0.7,0.2,0,0,0,0"/><S T="12" X="400" Y="390" L="10" H="83" P="0,0,0.7,0.2,0,0,0,0"/><S T="12" X="530" Y="440" L="10" H="83" P="0,0,0.7,0.2,0,0,0,0"/><S T="12" X="284" Y="87" L="10" H="83" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="519" Y="87" L="10" H="83" P="0,0,0.3,0.2,-90,0,0,0"/><S T="12" X="283" Y="583" L="10" H="83" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="517" Y="584" L="10" H="83" P="0,0,0.3,0.2,-90,0,0,0"/><S T="12" X="205" Y="139" L="10" H="80" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="597" Y="139" L="10" H="80" P="0,0,0.3,0.2,-90,0,0,0"/><S T="12" X="205" Y="529" L="10" H="80" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="597" Y="529" L="10" H="80" P="0,0,0.3,0.2,-90,0,0,0"/><S T="12" X="89" Y="87" L="10" H="60" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="713" Y="87" L="10" H="60" P="0,0,0.3,0.2,-90,0,0,0"/><S T="12" X="90" Y="581" L="10" H="60" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="713" Y="581" L="10" H="60" P="0,0,0.3,0.2,-90,0,0,0"/><S T="12" X="88" Y="217" L="10" H="59" P="0,0,0.3,0.2,270,0,0,0"/><S T="12" X="714" Y="217" L="10" H="59" P="0,0,0.3,0.2,-270,0,0,0"/><S T="12" X="89" Y="451" L="10" H="59" P="0,0,0.3,0.2,-90,0,0,0"/><S T="12" X="714" Y="451" L="10" H="59" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="65" Y="269" L="10" H="105" P="0,0,0.3,0.2,270,0,0,0"/><S T="12" X="738" Y="269" L="10" H="105" P="0,0,0.3,0.2,-270,0,0,0"/><S T="12" X="65" Y="399" L="10" H="105" P="0,0,0.3,0.2,-90,0,0,0"/><S T="12" X="738" Y="399" L="10" H="105" P="0,0,0.3,0.2,90,0,0,0"/><S T="12" X="400" Y="297" L="166" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="400" Y="428" L="162" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="342" Y="249" L="47" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="459" Y="249" L="47" H="10" P="0,0,0.3,0.2,0,0,0,0"/><S T="12" X="401" Y="249" L="67" H="10" P="0,0,0.3,0.2,0,0,0,0" v="90000"/><S T="12" X="478" Y="273" L="56" H="10" P="0,0,0.3,0.2,90,0,0,0" v="90000"/><S T="12" X="322" Y="273" L="56" H="10" P="0,0,0.3,0.2,90,0,0,0" v="90000"/><S T="12" X="400" Y="650" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="90000"/><S T="12" X="400" Y="650" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="89000"/><S T="12" X="400" Y="650" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="88000"/><S T="12" X="400" Y="650" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="87000"/><S T="12" X="400" Y="650" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="86000"/><S T="12" X="400" Y="650" L="10" H="10" P="1,0,0.3,0.2,90,1,Infinity,0" c="4" v="85000"/></S><D><F X="351" Y="285" D=""/><F X="450" Y="284" D=""/><T X="399" Y="291" D=""/></D><O/><L><JD c="1500fb,10,1,0" P1="788,35" P2="788,633"/><JD c="1500fb,10,1,0" P1="10,35" P2="10,633"/><JD c="1500fb,10,1,0" P1="787,35" P2="12,35"/><JD c="1500fb,10,1,0" P1="788,633" P2="13,633"/><JD c="1500fb,10,1,0" P1="478,428" P2="323,428"/><JD c="1500fb,10,1,0" P1="400,353" P2="400,426"/><JD c="FFFFFF,10,1,0" M1="79" M2="79" P1="429,249" P2="371,249"/><JD c="FFFFFF,10,1,0" M1="79" M2="79" P1="478,296" P2="478,250"/><JD c="FFFFFF,10,1,0" M1="79" M2="79" P1="322,296" P2="322,250"/><JD c="1500fb,10,1,0" M1="80" M2="80" P1="429,249" P2="371,249"/><JD c="1500fb,10,1,0" M1="80" M2="80" P1="478,296" P2="478,250"/><JD c="1500fb,10,1,0" M1="80" M2="80" P1="322,296" P2="322,250"/><JD c="FFFFFF,10,1,0" M1="81" M2="81" P1="429,249" P2="371,249"/><JD c="FFFFFF,10,1,0" M1="81" M2="81" P1="478,296" P2="478,250"/><JD c="FFFFFF,10,1,0" M1="81" M2="81" P1="322,296" P2="322,250"/><JD c="1500fb,10,1,0" M1="82" M2="82" P1="429,249" P2="371,249"/><JD c="1500fb,10,1,0" M1="82" M2="82" P1="478,296" P2="478,250"/><JD c="1500fb,10,1,0" M1="82" M2="82" P1="322,296" P2="322,250"/><JD c="FFFFFF,10,1,0" M1="83" M2="83" P1="429,249" P2="371,249"/><JD c="FFFFFF,10,1,0" M1="83" M2="83" P1="478,296" P2="478,250"/><JD c="FFFFFF,10,1,0" M1="83" M2="83" P1="322,296" P2="322,250"/><JD c="1500fb,10,1,0" M1="84" M2="84" P1="429,249" P2="371,249"/><JD c="1500fb,10,1,0" M1="84" M2="84" P1="478,296" P2="478,250"/><JD c="1500fb,10,1,0" M1="84" M2="84" P1="322,296" P2="322,250"/><JD c="1500fb,10,1,0" P1="375,189" P2="375,118"/><JD c="1500fb,10,1,0" P1="426,189" P2="426,118"/><JD c="1500fb,10,1,0" P1="374,480" P2="374,559"/><JD c="1500fb,10,1,0" P1="426,478" P2="426,559"/><JD c="1500fb,10,1,0" P1="272,265" P2="272,193"/><JD c="1500fb,10,1,0" P1="530,265" P2="530,193"/><JD c="1500fb,10,1,0" P1="219,422" P2="219,246"/><JD c="1500fb,10,1,0" P1="582,422" P2="582,246"/><JD c="1500fb,10,1,0" P1="478,297" P2="322,297"/><JD c="1500fb,10,1,0" P1="271,403" P2="271,479"/><JD c="1500fb,10,1,0" P1="530,403" P2="530,475"/><JD c="1500fb,10,1,0" P1="166,266" P2="166,193"/><JD c="1500fb,10,1,0" P1="636,266" P2="636,193"/><JD c="1500fb,10,1,0" P1="166,402" P2="166,475"/><JD c="1500fb,10,1,0" P1="636,402" P2="636,475"/><JD c="1500fb,10,1,0" P1="115,162" P2="115,88"/><JD c="1500fb,10,1,0" P1="687,162" P2="687,88"/><JD c="1500fb,10,1,0" P1="115,506" P2="115,580"/><JD c="1500fb,10,1,0" P1="687,506" P2="687,580"/><JD c="1500fb,10,1,0" P1="62,217" P2="62,144"/><JD c="1500fb,10,1,0" P1="740,217" P2="740,144"/><JD c="1500fb,10,1,0" P1="62,451" P2="62,524"/><JD c="1500fb,10,1,0" P1="740,451" P2="740,524"/><JD c="1500fb,10,1,0" P1="361,249" P2="322,249"/><JD c="1500fb,10,1,0" P1="439,249" P2="478,249"/><JD c="1500fb,10,1,0" P1="375,191" P2="272,191"/><JD c="1500fb,10,1,0" P1="427,191" P2="530,191"/><JD c="1500fb,10,1,0" P1="374,480" P2="271,480"/><JD c="1500fb,10,1,0" P1="426,477" P2="530,477"/><JD c="1500fb,10,1,0" P1="241,139" P2="169,139"/><JD c="1500fb,10,1,0" P1="561,139" P2="633,139"/><JD c="1500fb,10,1,0" P1="241,529" P2="169,529"/><JD c="1500fb,10,1,0" P1="561,529" P2="633,529"/><JD c="1500fb,10,1,0" P1="320,87" P2="247,87"/><JD c="1500fb,10,1,0" P1="483,87" P2="555,87"/><JD c="1500fb,10,1,0" P1="319,583" P2="246,583"/><JD c="1500fb,10,1,0" P1="481,584" P2="552,584"/><JD c="1500fb,10,1,0" P1="215,191" P2="166,191"/><JD c="1500fb,10,1,0" P1="587,191" P2="636,191"/><JD c="1500fb,10,1,0" P1="215,477" P2="166,477"/><JD c="1500fb,10,1,0" P1="587,477" P2="636,477"/><JD c="1500fb,10,1,0" P1="113,217" P2="62,217"/><JD c="1500fb,10,1,0" P1="689,217" P2="740,217"/><JD c="1500fb,10,1,0" P1="113,451" P2="62,451"/><JD c="1500fb,10,1,0" P1="689,451" P2="740,451"/><JD c="1500fb,10,1,0" P1="114,87" P2="63,87"/><JD c="1500fb,10,1,0" P1="688,87" P2="739,87"/><JD c="1500fb,10,1,0" P1="114,581" P2="63,581"/><JD c="1500fb,10,1,0" P1="688,581" P2="739,581"/><JD c="1500fb,10,1,0" P1="113,269" P2="10,269"/><JD c="1500fb,10,1,0" P1="689,269" P2="788,269"/><JD c="1500fb,10,1,0" P1="113,399" P2="10,399"/><JD c="1500fb,10,1,0" P1="689,399" P2="788,399"/><JD c="000000,6,1,0" P1="787,35" P2="12,35"/><JD c="000000,6,1,0" P1="788,633" P2="13,633"/><JD c="000000,6,1,0" P1="478,428" P2="323,428"/><JD c="000000,6,1,0" P1="400,353" P2="400,426"/><JD c="000000,6,1,0" M1="79" M2="79" P1="429,249" P2="371,249"/><JD c="000000,6,1,0" M1="79" M2="79" P1="478,296" P2="478,250"/><JD c="000000,6,1,0" M1="79" M2="79" P1="322,296" P2="322,250"/><JD c="000000,6,1,0" P1="375,189" P2="375,118"/><JD c="000000,6,1,0" P1="426,189" P2="426,118"/><JD c="000000,6,1,0" P1="374,480" P2="374,559"/><JD c="000000,6,1,0" P1="426,478" P2="426,559"/><JD c="1500fb,3,1,0" P1="323,85" P2="323,141"/><JD c="1500fb,3,1,0" P1="479,85" P2="479,141"/><JD c="000000,6,1,0" P1="10,35" P2="10,633"/><JD c="1500fb,3,1,0" P1="322,585" P2="322,529"/><JD c="1500fb,3,1,0" P1="477,586" P2="477,530"/><JD c="1500fb,3,1,0" P1="197,40" P2="197,86"/><JD c="1500fb,3,1,0" P1="605,40" P2="605,86"/><JD c="1500fb,3,1,0" P1="196,628" P2="196,582"/><JD c="1500fb,3,1,0" P1="605,628" P2="605,582"/><JD c="000000,6,1,0" P1="272,265" P2="272,193"/><JD c="000000,6,1,0" P1="530,265" P2="530,193"/><JD c="000000,6,1,0" P1="219,422" P2="219,246"/><JD c="000000,6,1,0" P1="582,422" P2="582,246"/><JD c="000000,6,1,0" P1="478,297" P2="322,297"/><JD c="000000,6,1,0" P1="271,403" P2="271,479"/><JD c="000000,6,1,0" P1="530,403" P2="530,475"/><JD c="000000,6,1,0" P1="166,266" P2="166,193"/><JD c="000000,6,1,0" P1="636,266" P2="636,193"/><JD c="000000,6,1,0" P1="166,402" P2="166,475"/><JD c="000000,6,1,0" P1="636,402" P2="636,475"/><JD c="000000,6,1,0" P1="115,162" P2="115,88"/><JD c="000000,6,1,0" P1="687,162" P2="687,88"/><JD c="000000,6,1,0" P1="115,506" P2="115,580"/><JD c="000000,6,1,0" P1="687,506" P2="687,580"/><JD c="000000,6,1,0" P1="62,217" P2="62,144"/><JD c="000000,6,1,0" P1="740,217" P2="740,144"/><JD c="000000,6,1,0" P1="62,451" P2="62,524"/><JD c="000000,6,1,0" P1="740,451" P2="740,524"/><JD c="000000,6,1,0" P1="361,249" P2="322,249"/><JD c="000000,6,1,0" P1="439,249" P2="478,249"/><JD c="000000,6,1,0" P1="375,191" P2="272,191"/><JD c="000000,6,1,0" P1="427,191" P2="530,191"/><JD c="000000,6,1,0" P1="374,480" P2="271,480"/><JD c="000000,6,1,0" P1="426,477" P2="530,477"/><JD c="000000,6,1,0" P1="241,139" P2="169,139"/><JD c="000000,6,1,0" P1="561,139" P2="633,139"/><JD c="000000,6,1,0" P1="241,529" P2="169,529"/><JD c="000000,6,1,0" P1="561,529" P2="633,529"/><JD c="000000,6,1,0" P1="318,87" P2="247,87"/><JD c="000000,6,1,0" P1="484,87" P2="555,87"/><JD c="000000,6,1,0" P1="318,583" P2="246,583"/><JD c="000000,6,1,0" P1="482,584" P2="551.57,584"/><JD c="000000,6,1,0" P1="215,191" P2="166,191"/><JD c="000000,6,1,0" P1="587,191" P2="636,191"/><JD c="000000,6,1,0" P1="215,477" P2="166,477"/><JD c="000000,6,1,0" P1="587,477" P2="636,477"/><JD c="000000,6,1,0" P1="113,217" P2="62,217"/><JD c="000000,6,1,0" P1="689,217" P2="740,217"/><JD c="000000,6,1,0" P1="113,451" P2="62,451"/><JD c="000000,6,1,0" P1="689,451" P2="740,451"/><JD c="000000,6,1,0" P1="114,87" P2="63,87"/><JD c="000000,6,1,0" P1="688,87" P2="739,87"/><JD c="000000,6,1,0" P1="114,581" P2="63,581"/><JD c="000000,6,1,0" P1="688,581" P2="739,581"/><JD c="000000,6,1,0" P1="113,269" P2="10,269"/><JD c="000000,6,1,0" P1="689,269" P2="788,269"/><JD c="000000,6,1,0" P1="113,399" P2="10,399"/><JD c="000000,6,1,0" P1="689,399" P2="788,399"/><JD c="1500fb,3,1,0" P1="166,320" P2="166,348"/><JD c="1500fb,3,1,0" P1="634,320" P2="634,348"/><JD c="1500fb,3,1,0" P1="450,350" P2="450,378"/><JD c="1500fb,3,1,0" P1="319,350" P2="319,378"/><JD c="000000,6,1,0" P1="788,35" P2="788,633"/><JD c="1500fb,3,1,0" P1="269,320" P2="269,348"/><JD c="1500fb,3,1,0" P1="532,320" P2="532,348"/><JD c="1500fb,3,1,0" P1="62,320" P2="62,348"/><JD c="1500fb,3,1,0" P1="738,320" P2="738,348"/><JD c="1500fb,3,1,0" P1="480,350" P2="480,378"/><JD c="1500fb,3,1,0" P1="349,350" P2="349,378"/><JD c="1500fb,3,1,0" P1="429,40" P2="429,61"/><JD c="1500fb,3,1,0" P1="372,40" P2="372,61"/><JD c="1500fb,3,1,0" P1="429,628" P2="429,607"/><JD c="1500fb,3,1,0" P1="372,628" P2="372,607"/><JD c="1500fb,3,1,0" P1="295,92" P2="295,140"/><JD c="1500fb,3,1,0" P1="507,92" P2="507,140"/><JD c="1500fb,3,1,0" P1="294,578" P2="294,530"/><JD c="1500fb,3,1,0" P1="505,579" P2="505,531"/><JD c="1500fb,3,1,0" P1="165,40" P2="165,86"/><JD c="1500fb,3,1,0" P1="637,40" P2="637,86"/><JD c="1500fb,3,1,0" P1="164,628" P2="164,582"/><JD c="1500fb,3,1,0" P1="637,628" P2="637,582"/><JD c="1500fb,3,1,0" P1="429,61" P2="373,61"/><JD c="1500fb,3,1,0" P1="429,607" P2="373,607"/><JD c="1500fb,3,1,0" P1="323,141" P2="295,141"/><JD c="1500fb,3,1,0" P1="479,141" P2="507,141"/><JD c="1500fb,3,1,0" P1="269,348" P2="224,348"/><JD c="1500fb,3,1,0" P1="532,348" P2="577,348"/><JD c="1500fb,3,1,0" P1="269,320" P2="224,320"/><JD c="1500fb,3,1,0" P1="532,320" P2="577,320"/><JD c="1500fb,3,1,0" P1="322,529" P2="294,529"/><JD c="1500fb,3,1,0" P1="477,530" P2="505,530"/><JD c="1500fb,3,1,0" P1="197,86.17" P2="166,86.17"/><JD c="1500fb,3,1,0" P1="605,86.17" P2="636,86.17"/><JD c="1500fb,3,1,0" P1="196,581.83" P2="165,581.83"/><JD c="1500fb,3,1,0" P1="605,581.83" P2="636,581.83"/><JD c="1500fb,3,1,0" P1="166,320" P2="63,320"/><JD c="1500fb,3,1,0" P1="634,320" P2="737,320"/><JD c="1500fb,3,1,0" P1="450,350" P2="480,350"/><JD c="1500fb,3,1,0" P1="319,350" P2="349,350"/><JD c="1500fb,3,1,0" P1="166,348" P2="63,348"/><JD c="1500fb,3,1,0" P1="634,348" P2="737,348"/><JD c="1500fb,3,1,0" P1="450,378" P2="480,378"/><JD c="1500fb,3,1,0" P1="319,378" P2="349,378"/><JD c="000000,3,1,0" P1="219.84,323" P2="243.25,323"/><JD c="000000,3,1,0" P1="581.16,323" P2="557.75,323"/><JD c="000000,3,1,0" P1="223,323" P2="223,344"/><JD c="000000,3,1,0" P1="578,323" P2="578,344"/><JD c="000000,3,1,0" P1="169,629" P2="191,629"/><JD c="000000,3,1,0" P1="632,629" P2="610,629"/><JD c="000000,3,1,0" P1="297,579" P2="317,579"/><JD c="000000,3,1,0" P1="502,580" P2="482,580"/><JD c="000000,3,1,0" P1="298,91" P2="318,91"/><JD c="000000,3,1,0" P1="504,91" P2="484,91"/><JD c="000000,3,1,0" P1="170,39" P2="192,39"/><JD c="000000,3,1,0" P1="632,39" P2="610,39"/><JD c="000000,3,1,0" P1="377,629" P2="425,629"/><JD c="000000,3,1,0" P1="377,39" P2="425,39"/><JD c="000000,3,1,0" P1="219.84,345" P2="243.25,345"/><JD c="000000,3,1,0" P1="581.16,345" P2="557.75,345"/><JD c="000000,3,1,0" P1="193,631" P2="193,608"/><JD c="000000,3,1,0" P1="608,631" P2="608,608"/><JD c="000000,3,1,0" P1="319,581" P2="319,558"/><JD c="000000,3,1,0" P1="480,583" P2="480,560"/><JD c="000000,3,1,0" P1="320,87" P2="320,112"/><JD c="000000,3,1,0" P1="482,87" P2="482,112"/><JD c="000000,3,1,0" P1="194,37" P2="194,60"/><JD c="000000,3,1,0" P1="608,37" P2="608,60"/><JD c="000000,3,1,0" P1="426,631" P2="426,617"/><JD c="000000,3,1,0" P1="375,631" P2="375,617"/><JD c="000000,3,1,0" P1="426,37" P2="426,51"/><JD c="000000,3,1,0" P1="375,37" P2="375,51"/><JD c="000000,3,1,0" P1="167,631" P2="167,608"/><JD c="000000,3,1,0" P1="634,631" P2="634,608"/><JD c="000000,3,1,0" P1="297,581" P2="297,558"/><JD c="000000,3,1,0" P1="502,582" P2="502,559"/><JD c="000000,3,1,0" P1="298,89" P2="298,112"/><JD c="000000,3,1,0" P1="504,89" P2="504,112"/><JD c="000000,3,1,0" P1="168,37" P2="168,60"/><JD c="000000,3,1,0" P1="634,37" P2="634,60"/></L></Z></C>]]}
4496pacmice_maps["pacmice_5"].pathes={{1,1},{2,1},{3,1},{4,1},{5,1},{8,1},{9,1},{10,1},{11,1},{12,1},{13,1},{17,1},{18,1},{19,1},{20,1},{21,1},{22,1},{25,1},{26,1},{27,1},{28,1},{29,1},{1,2},{5,2},{8,2},{13,2},{14,2},{15,2},{16,2},{17,2},{22,2},{25,2},{29,2},{1,3},{2,3},{3,3},{5,3},{6,3},{7,3},{8,3},{9,3},{10,3},{13,3},{15,3},{17,3},{20,3},{21,3},{22,3},{23,3},{24,3},{25,3},{27,3},{28,3},{29,3},{1,4},{3,4},{5,4},{10,4},{13,4},{15,4},{17,4},{20,4},{25,4},{27,4},{29,4},{1,5},{3,5},{5,5},{6,5},{7,5},{8,5},{9,5},{10,5},{11,5},{12,5},{13,5},{15,5},{17,5},{18,5},{19,5},{20,5},{21,5},{22,5},{23,5},{24,5},{25,5},{27,5},{29,5},{1,6},{3,6},{4,6},{5,6},{9,6},{15,6},{21,6},{25,6},{26,6},{27,6},{29,6},{1,7},{5,7},{7,7},{8,7},{9,7},{11,7},{12,7},{13,7},{14,7},{15,7},{16,7},{17,7},{18,7},{19,7},{21,7},{22,7},{23,7},{25,7},{29,7},{1,8},{2,8},{3,8},{4,8},{5,8},{7,8},{9,8},{11,8},{19,8},{21,8},{23,8},{25,8},{26,8},{27,8},{28,8},{29,8},{5,9},{7,9},{9,9},{11,9},{19,9},{21,9},{23,9},{25,9},{1,10},{2,10},{3,10},{4,10},{5,10},{6,10},{7,10},{9,10},{10,10},{11,10},{19,10},{20,10},{21,10},{23,10},{24,10},{25,10},{26,10},{27,10},{28,10},{29,10},{1,11},{7,11},{11,11},{12,11},{13,11},{14,11},{15,11},{16,11},{17,11},{18,11},{19,11},{23,11},{29,11},{1,12},{7,12},{11,12},{14,12},{16,12},{19,12},{23,12},{29,12},{1,13},{2,13},{3,13},{4,13},{5,13},{6,13},{7,13},{9,13},{10,13},{11,13},{14,13},{16,13},{19,13},{20,13},{21,13},{23,13},{24,13},{25,13},{26,13},{27,13},{28,13},{29,13},{5,14},{7,14},{9,14},{11,14},{12,14},{13,14},{14,14},{16,14},{17,14},{18,14},{19,14},{21,14},{23,14},{25,14},{1,15},{2,15},{3,15},{4,15},{5,15},{7,15},{9,15},{11,15},{19,15},{21,15},{23,15},{25,15},{26,15},{27,15},{28,15},{29,15},{1,16},{5,16},{7,16},{8,16},{9,16},{11,16},{12,16},{13,16},{14,16},{15,16},{16,16},{17,16},{18,16},{19,16},{21,16},{22,16},{23,16},{25,16},{29,16},{1,17},{3,17},{4,17},{5,17},{9,17},{15,17},{21,17},{25,17},{26,17},{27,17},{29,17},{1,18},{3,18},{5,18},{6,18},{7,18},{8,18},{9,18},{10,18},{11,18},{12,18},{13,18},{15,18},{17,18},{18,18},{19,18},{20,18},{21,18},{22,18},{23,18},{24,18},{25,18},{27,18},{29,18},{1,19},{3,19},{5,19},{10,19},{13,19},{15,19},{17,19},{20,19},{25,19},{27,19},{29,19},{1,20},{2,20},{3,20},{5,20},{6,20},{7,20},{8,20},{9,20},{10,20},{13,20},{15,20},{17,20},{20,20},{21,20},{22,20},{23,20},{24,20},{25,20},{27,20},{28,20},{29,20},{1,21},{5,21},{8,21},{13,21},{14,21},{15,21},{16,21},{17,21},{22,21},{25,21},{29,21},{1,22},{2,22},{3,22},{4,22},{5,22},{8,22},{9,22},{10,22},{11,22},{12,22},{13,22},{17,22},{18,22},{19,22},{20,22},{21,22},{22,22},{25,22},{26,22},{27,22},{28,22},{29,22}}
4497pacmice_maps["pacmice_5"].foods={{x=87,y=61},{x=282,y=61},{x=517,y=61},{x=716,y=61},{x=400,y=88},{x=400,y=218},{x=400,y=330},{x=400,y=522},{x=87,y=195},{x=716,y=195},{x=36,y=330},{x=245,y=373},{x=193,y=452},{x=87,y=517},{x=281,y=610},{x=512,y=610},{x=712,y=519},{x=609,y=452},{x=546,y=373},{x=762,y=330}}
4498rotations["pacmice"]=Rotation:New({items={}})
4499local function GetMap(mapname)
4500pacmice_map=pacmice_maps[mapname]
4501local xml=pacmice_map.axml
4502pacmice_map_color_index=(pacmice_map_color_index%#pacmice_map_colors)+1
4503return string.gsub(xml,"1500fb",pacmice_map_colors[pacmice_map_color_index])
4504end
4505for i_map,map in pairs(pacmice_maps)do
4506local mapname="pacmice_"..tostring(i_map)
4507maps[mapname]=pacmice_maps[i_map]
4508map.replace_func=GetMap
4509map.autoskip=false
4510table.insert(rotations["pacmice"].items,mapname)
4511end
4512local function FoodGrabbedCallback(player_name,bonus)
4513scores.Add(player_name,2)
4514end
4515for i_image,image_name in pairs(pacmice_food_images)do
4516bonus_types[image_name]={image=image_name,func=FoodGrabbedCallback}
4517end
4518local function TouchPlayer(player_name)
4519ui.addTextArea(pacmice_help_btn_id,"<p align='center'><font size='12'><a href='event:pcmd help'>help</a></font></p>",player_name,5,25,40,20,0x111111,0xFFFF00,0.2,true)
4520end
4521local function CountMiceAlive()
4522local count=0
4523for player_name,player in pairs(tfm.get.room.playerList)do
4524if not player.isDead and not pacmice_pacmans[player_name]then
4525count=count+1
4526end
4527end
4528return count
4529end
4530local function PopBestScorePlayer()
4531local best_player_name=nil
4532for player_name in pairs(tfm.get.room.playerList)do
4533if not best_player_name or scores.scores[player_name]>scores.scores[best_player_name]then
4534best_player_name=player_name
4535end
4536end
4537return best_player_name
4538end
4539local function HidePacmicePlayers()
4540tfm.exec.addPhysicObject(24,pacmice_map.web_x,200,{type=tfm.enum.ground.rectangle,width=200,height=4000,foreground=true,color=0x010101,miceCollision=false})
4541end
4542local function DestroyPacman(player_name)
4543if pacmice_pacmans[player_name]then
4544local pacman=pacmice_pacmans[player_name]
4545if pacman.image_id then
4546tfm.exec.removeImage(pacman.image_id)
4547end
4548pacmice_pacmans[player_name]=nil
4549pacmice_pacmouse_count=pacmice_pacmouse_count-1
4550if not pacmice_round_over then
4551tfm.exec.killPlayer(player_name)
4552end
4553tfm.get.room.playerList[player_name].isDead=true
4554tfm.exec.removePhysicObject(killer_ground_1+pacman.pacman_index)
4555scores.Set(player_name,0)
4556tfm.exec.setPlayerGravityScale(player_name,1,1)
4557end
4558end
4559local function CreatePacman(player_name)
4560if pacmice_pacmans[player_name]then
4561DestroyPacman(player_name)
4562end
4563pacmice_pacmans[player_name]={}
4564local pacman=pacmice_pacmans[player_name]
4565pacman.player_name=player_name
4566pacman.cell_x=pacmice_map.pathes[#pacmice_map.pathes][1]
4567pacman.cell_y=pacmice_map.pathes[#pacmice_map.pathes][2]
4568pacman.cell_vx=-1
4569pacman.cell_vy=0
4570pacman.wish_vx=-1
4571pacman.wish_vy=0
4572pacman.image_id=nil
4573pacman.direction=0
4574pacman.speed=50
4575pacman.size=50
4576pacman.image_animation_number=pacmice_pacmouse_count%#pacmice_animations+1
4577pacman.image_animation_index=0
4578pacman.pacman_index=pacmice_pacmouse_count
4579tfm.exec.setShaman(player_name,false)
4580tfm.exec.removeCheese(player_name)
4581tfm.exec.respawnPlayer(player_name)
4582tfm.exec.freezePlayer(player_name,true)
4583tfm.exec.movePlayer(player_name,pacmice_map.web_x,pacman.cell_y*pacmice_map.cell_h+pacmice_map.y,false,1,1,false)
4584tfm.exec.movePlayer(player_name,0,0,true,-1,-1,true)
4585tfm.exec.setPlayerGravityScale(player_name,0,0)
4586pacmice_pacmouse_count=pacmice_pacmouse_count+1
4587system.bindMouse(player_name,true)
4588system.bindKeyboard(player_name,keycodes.UP,true,true)
4589system.bindKeyboard(player_name,keycodes.DOWN,true,true)
4590system.bindKeyboard(player_name,keycodes.LEFT,true,true)
4591system.bindKeyboard(player_name,keycodes.RIGHT,true,true)
4592end
4593local function GetCellDrawCoords(x,y)
4594local x=x*pacmice_map.cell_w+pacmice_map.x
4595local y=y*pacmice_map.cell_h+pacmice_map.y
4596return x,y
4597end
4598local function DrawPacman(player_name)
4599local pacman=pacmice_pacmans[player_name]
4600local x,y=GetCellDrawCoords(pacman.cell_x,pacman.cell_y)
4601local animation=pacmice_animations[pacman.image_animation_number]
4602pacman.image_animation_index=(pacman.image_animation_index+1)%#animation
4603local image_code=(animation)[pacman.image_animation_index+1]local old_image_id=pacman.image_id
4604local size=(pacmice_map.cell_w*2)-pacmice_map.wall_size
4605pacman.image_id=tfm.exec.addImage(image_code,"!0",x,y,nil,1.0,1.0,pacman.direction,1.0,0.5,0.5)
4606if old_image_id then
4607tfm.exec.removeImage(old_image_id)
4608end
4609local ground_id=killer_ground_1+pacman.pacman_index
4610tfm.exec.addPhysicObject(killer_ground_1+pacman.pacman_index,x,y,{type=tfm.enum.ground.invisible,width=size,height=size,foreground=false,miceCollision=true,groundCollision=true,contactListener=true})
4611tfm.exec.movePlayer(player_name,0,0,true,0,(y-tfm.get.room.playerList[player_name].y)/5+pacman.cell_vy*25,false)
4612end
4613local function GridGet(x,y)
4614if x>pacmice_map.grid_w or y>pacmice_map.grid_h then
4615return false
4616end
4617return pacmice_map.linear_grid[y*pacmice_map.grid_w+x]
4618end
4619local function GridSet(x,y,value)
4620pacmice_map.linear_grid[y*pacmice_map.grid_w+x]=value
4621end
4622local function DrawCursor()
4623local x=pacmice_cur_x*pacmice_map.cell_w+pacmice_map.x
4624local y=pacmice_cur_y*pacmice_map.cell_h+pacmice_map.y
4625if pacmice_cur_pilot then
4626tfm.exec.addPhysicObject(23,x+pacmice_map.cell_w/2,y,{type=tfm.enum.ground.rectangle,width=5,height=2000,foreground=false,color=0xdd4400,miceCollision=false,groundCollision=false})
4627tfm.exec.addPhysicObject(24,x-pacmice_map.cell_w/2,y,{type=tfm.enum.ground.rectangle,width=5,height=2000,foreground=false,color=0xdd4400,miceCollision=false,groundCollision=false})
4628tfm.exec.addPhysicObject(25,x,y+pacmice_map.cell_h/2,{type=tfm.enum.ground.rectangle,width=2000,height=5,foreground=false,color=0xdd4400,miceCollision=false,groundCollision=false})
4629tfm.exec.addPhysicObject(26,x,y-pacmice_map.cell_h/2,{type=tfm.enum.ground.rectangle,width=2000,height=5,foreground=false,color=0xdd4400,miceCollision=false,groundCollision=false})
4630else
4631tfm.exec.removeObject(23)
4632tfm.exec.removeObject(24)
4633tfm.exec.removeObject(25)
4634tfm.exec.removeObject(26)
4635end
4636end
4637local function MoveCursor(x,y)
4638if not pacmice_cur_generating then
4639if x<0 or y<0 or x>=pacmice_map.grid_w or y>=pacmice_map.grid_h then
4640print("out of bounds")
4641return
4642end
4643if not GridGet(x,y)then
4644return
4645end
4646end
4647pacmice_cur_x=x
4648pacmice_cur_y=y
4649if pacmice_cur_generating then
4650GridSet(x,y,true)
4651end
4652end
4653local function KeycodeToVector(keycode)
4654if keycode==keycodes.UP then
4655return 0,-1
4656elseif keycode==keycodes.DOWN then
4657return 0,1
4658elseif keycode==keycodes.LEFT then
4659return-1,0
4660elseif keycode==keycodes.RIGHT then
4661return 1,0
4662end
4663end
4664local function VectorToDirection(x,y)
4665if x==1 and y==0 then
4666return 0
4667elseif x==0 and y==1 then
4668return(math.pi/2)*1
4669elseif x==-1 and y==0 then
4670return(math.pi/2)*2
4671elseif x==0 and y==-1 then
4672return(math.pi/2)*3
4673end
4674error("unexpected")
4675end
4676local function GetGridCoords(x,y)
4677x=math.floor((x-pacmice_map.x)/pacmice_map.cell_w+0.5)
4678y=math.floor((y-pacmice_map.y)/pacmice_map.cell_h+0.5)
4679return x,y
4680end
4681local function GridExportPathes(player_name)
4682local total="{"
4683for y=0,(pacmice_map.grid_h-1)do
4684for x=0,(pacmice_map.grid_w-1)do
4685if GridGet(x,y)then
4686if#total>1 then
4687total=total..", "
4688end
4689total=total.."{"..tostring(x)..", "..tostring(y).."}"
4690end
4691end
4692end
4693total=total.."}"
4694while#total>0 do
4695subtotal=string.sub(total,1,180)
4696tfm.exec.chatMessage(subtotal,player_name)
4697total=string.sub(total,181,#total)
4698end
4699end
4700function eventNewGame()
4701loopmore.SetInterval(250)
4702ui.setMapName("PAC-MICE")
4703tfm.exec.addPhysicObject(21,pacmice_map.web_x-20,200,{type=tfm.enum.ground.invisible,width=10,height=5000,foreground=false,color=0x1,miceCollision=true})
4704tfm.exec.addPhysicObject(22,pacmice_map.web_x+20,200,{type=tfm.enum.ground.invisible,width=10,height=5000,foreground=false,color=0x1,miceCollision=true})
4705tfm.exec.addPhysicObject(23,pacmice_map.web_x,pacmice_map.y+pacmice_map.grid_h*pacmice_map.cell_h,{type=tfm.enum.ground.rectangle,width=200,height=20,foreground=true,color=0xff0000,miceCollision=true})
4706HidePacmicePlayers()
4707pacmice_round_over=false
4708if pacmice_cur_generating or pacmice_cur_pilot then
4709return
4710end
4711if CountMiceAlive()>=1 then
4712local pacmouse_player=PopBestScorePlayer()
4713CreatePacman(pacmouse_player)
4714if pacmice_map.pac_count==1 or CountMiceAlive()<=1 then
4715tfm.exec.chatMessage("<b><fc>The pacmouse is now <j>"..utils_tfm.GetPlayerNick(pacmouse_player).."</j></fc></b>",nil)
4716ui.setShamanName(utils_tfm.GetPlayerNick(pacmouse_player))
4717else
4718old_score=scores.scores[pacmouse_player]
4719scores.scores[pacmouse_player]=0
4720local pacmouse_player_2=PopBestScorePlayer()
4721scores.scores[pacmouse_player]=old_score
4722CreatePacman(pacmouse_player_2)
4723tfm.exec.chatMessage("<b><fc>The pacmice are now <j>"..utils_tfm.GetPlayerNick(pacmouse_player).."</j> and <j>"..utils_tfm.GetPlayerNick(pacmouse_player_2).."</j></fc></b>",nil)
4724pacmice_pacmans[pacmouse_player_2].image_animation_number=2
4725ui.setShamanName(utils_tfm.GetPlayerNick(pacmouse_player).." and "..utils_tfm.GetPlayerNick(pacmouse_player_2))
4726end
4727end
4728for i_bonus,bonus in pairs(pacmice_map.foods)do
4729local bonus_type=pacmice_food_images[math.random(#pacmice_food_images)]
4730bonuses.AddNoCopy({type_name=bonus_type,x=bonus.x,y=bonus.y})
4731end
4732end
4733function eventMouse(player_name,x,y)
4734if player_name==pacmice_cur_pilot then
4735x,y=GetGridCoords(x,y)
4736MoveCursor(x,y)
4737DrawCursor()
4738return true
4739end
4740end
4741function eventKeyboard(player_name,keycode,down,x,y)
4742if player_name==pacmice_cur_pilot and(keycode==0 or keycode==1 or keycode==2 or keycode==3)then
4743vx,vy=KeycodeToVector(keycode)
4744MoveCursor(pacmice_cur_x+vx,pacmice_cur_y+vy)
4745DrawCursor()
4746end
4747local pacman=pacmice_pacmans[player_name]
4748if pacman and(keycode==0 or keycode==1 or keycode==2 or keycode==3)then
4749pacman.wish_vx,pacman.wish_vy=KeycodeToVector(keycode)
4750end
4751if room.is_tribehouse then
4752alternative_timers.RunTimers()
4753end
4754end
4755function eventLoop(time,time_remaining)
4756if pacmice_auto_generating then
4757if pacmice_auto_object_id and pacmice_auto_x then
4758local tfm_object=tfm.get.room.objectList[pacmice_auto_object_id]
4759if tfm_object and tfm_object.id==pacmice_auto_object_id then
4760local spawn_x,spawn_y=GetCellDrawCoords(pacmice_auto_x,pacmice_auto_y)
4761if spawn_x==tfm_object.x and spawn_y==tfm_object.y and tfm_object.angle==0 and tfm_object.vx==0 and tfm_object.vy==0 then
4762GridSet(pacmice_auto_x,pacmice_auto_y,true)
4763else
4764GridSet(pacmice_auto_x,pacmice_auto_y,false)
4765end
4766else
4767return
4768end
4769end
4770if not pacmice_auto_x then
4771pacmice_auto_x=0 pacmice_auto_y=1 else
4772pacmice_auto_x=pacmice_auto_x+1
4773if pacmice_auto_x>=pacmice_map.grid_w then
4774pacmice_auto_x=0
4775pacmice_auto_y=pacmice_auto_y+1
4776tfm.exec.chatMessage("Generating... "..tostring(math.floor(pacmice_auto_y/pacmice_map.grid_h*100).."%"))
4777if pacmice_auto_y>=pacmice_map.grid_h then
4778pacmice_auto_x=nil
4779pacmice_auto_y=nil
4780pacmice_auto_generating=false
4781tfm.exec.chatMessage("Finished generating!")
4782return
4783end
4784end
4785end
4786local spawn_x,spawn_y=GetCellDrawCoords(pacmice_auto_x,pacmice_auto_y)
4787if not pacmice_auto_object_id then
4788pacmice_auto_object_id=tfm.exec.addShamanObject(tfm.enum.shamanObject.ball,spawn_x,spawn_y,0,0,0,true)
4789else
4790tfm.exec.moveObject(pacmice_auto_object_id,spawn_x,spawn_y,false,0,0,false,0,0)
4791end
4792end
4793if pacmice_cur_generating or pacmice_cur_pilot then
4794return
4795end
4796if time_remaining<=1 then
4797for player_name,player in pairs(tfm.get.room.playerList)do
4798if not player.isDead then
4799tfm.exec.playerVictory(player_name)
4800scores.Add(player_name,10)
4801end
4802end
4803end
4804if time_remaining<=0 then
4805pacmice_round_over=true
4806local pacmans_names={}
4807for player_name in pairs(pacmice_pacmans)do
4808pacmans_names[player_name]=true
4809end
4810for player_name in pairs(pacmans_names)do
4811DestroyPacman(player_name)
4812end
4813tfm.exec.setGameTime(4,false)
4814tfm.exec.newGame("pacmice")
4815elseif CountMiceAlive()<=0 then
4816tfm.exec.setGameTime(8,false)
4817else
4818local is_pacmouse=false
4819for player_name in pairs(pacmice_pacmans)do
4820is_pacmouse=true
4821end
4822if not is_pacmouse then
4823tfm.exec.setGameTime(8,false)
4824end
4825end
4826end
4827function eventLoopMore(time,time_remaining)
4828for player_name,pacman in pairs(pacmice_pacmans)do
4829local wish_x=pacman.cell_x+pacman.wish_vx
4830local wish_y=pacman.cell_y+pacman.wish_vy
4831if GridGet(wish_x,wish_y)then
4832pacman.cell_vx=pacman.wish_vx
4833pacman.cell_vy=pacman.wish_vy
4834end
4835if pacman.cell_vx~=0 or pacman.cell_vy~=0 then
4836local seen_x=pacman.cell_x+pacman.cell_vx
4837local seen_y=pacman.cell_y+pacman.cell_vy
4838if GridGet(seen_x,seen_y)then
4839pacman.cell_x=seen_x
4840pacman.cell_y=seen_y
4841pacman.direction=VectorToDirection(pacman.cell_vx,pacman.cell_vy)
4842else
4843pacman.cell_vx=0
4844pacman.cell_vy=0
4845end
4846end
4847DrawPacman(player_name)
4848end
4849end
4850function eventNewPlayer(player_name)
4851if auto_respawn and not pacmice_pacmans[player_name]then
4852tfm.exec.respawnPlayer(player_name)
4853end
4854TouchPlayer(player_name)
4855ui.setMapName("PAC-MICE")
4856HidePacmicePlayers()
4857end
4858function eventPlayerWon(player_name)
4859if not pacmice_pacmans[player_name]then
4860if pacmice_round_over then
4861scores.Add(player_name,10)
4862else
4863scores.Add(player_name,16)
4864end
4865end
4866end
4867function eventPlayerDied(player_name)
4868if pacmice_pacmans[player_name]then
4869DestroyPacman(player_name)
4870elseif auto_respawn then
4871tfm.exec.respawnPlayer(player_name)
4872else
4873if not pacmice_round_over then
4874scores.Add(player_name,1)
4875end
4876end
4877end
4878function eventContactListener(player_name,ground_id)
4879if ground_id==killer_ground_1 or ground_id==killer_ground_2 then
4880tfm.exec.killPlayer(player_name)
4881end
4882end
4883local function ChatCommandPacmouse(user,target)
4884target=target or user
4885if target~=user then
4886if target~=user and not perms.HavePerm(user,"!pacmouse-others")then
4887return false,"You cant use this command on others :c"
4888end
4889local reason
4890target,reason=utils_tfm.FindPlayerName(target)
4891if not target then
4892return false,reason
4893end
4894end
4895if pacmice_pacmans[target]then
4896DestroyPacman(target)
4897else
4898if pacmice_pacmouse_count>=2 then
4899return false,"Too many pacmice :c"
4900end
4901CreatePacman(target)
4902end
4903end
4904command_list["pacmouse"]={perms="admins",func=ChatCommandPacmouse,desc="turn into a pacmouse",argc_min=0,argc_max=1,arg_types={"string"},arg_names={"Target#0000"}}
4905help_pages[__MODULE_NAME__].commands["pacmouse"]=command_list["pacmouse"]
4906local function ChatCommandGeneratepathes(user,target)
4907target=target or user
4908if target~=user and not perms.HavePerm(user,"!pacmouse-others")then
4909return false,"You cant use this command on others :c"
4910end
4911if pacmice_cur_pilot~=target or not pacmice_cur_generating then
4912pacmice_cur_pilot=target
4913pacmice_cur_generating=true
4914system.bindMouse(target,true)
4915system.bindKeyboard(target,keycodes.UP,true,true)
4916system.bindKeyboard(target,keycodes.DOWN,true,true)
4917system.bindKeyboard(target,keycodes.LEFT,true,true)
4918system.bindKeyboard(target,keycodes.RIGHT,true,true)
4919tfm.exec.freezePlayer(target,true)
4920tfm.exec.chatMessage("Generating!",user)
4921else
4922pacmice_cur_generating=false
4923GridExportPathes(target)
4924tfm.exec.freezePlayer(target,false)
4925tfm.exec.chatMessage("No longer generating.",user)
4926end
4927end
4928command_list["generatepathes"]={perms="admins",func=ChatCommandGeneratepathes,desc="generate the new map's pathes (see source)",argc_min=0,argc_max=1,arg_types={"player"},arg_names={"Target#0000"}}
4929local function ChatCommandAutogeneratepathes(user)
4930local target=user
4931if pacmice_cur_pilot~=target or not pacmice_auto_generating then
4932pacmice_cur_pilot=target
4933pacmice_auto_generating=true
4934tfm.exec.setWorldGravity(0,0)
4935tfm.exec.chatMessage("Auto generating!",user)
4936else
4937pacmice_auto_generating=false
4938GridExportPathes(target)
4939tfm.exec.chatMessage("No longer auto generating.",user)
4940end
4941end
4942command_list["autogeneratepathes"]={perms="admins",func=ChatCommandAutogeneratepathes,desc="autogenerate the new map's pathes (see source)",argc_min=0,argc_max=0}
4943local function ChatCommandSkip(user)
4944tfm.exec.setGameTime(1)
4945end
4946command_list["skip"]={perms="admins",func=ChatCommandSkip,desc="skip the map",argc_min=0,argc_max=0}
4947help_pages[__MODULE_NAME__].commands["skip"]=command_list["skip"]
4948local function ChatCommandFastpacmouse(user,delay)
4949delay=delay or 200
4950if delay<100 or delay>500 then
4951return false,"The delay must be between 100 (fastest) and 500 (slowest)."
4952end
4953loopmore.SetInterval(delay)
4954end
4955command_list["fasterpacmice"]={aliases={"fast"},perms="admins",func=ChatCommandFastpacmouse,desc="makes pacmice temporarily faster",argc_min=0,argc_max=1,arg_types={"number"}}
4956help_pages[__MODULE_NAME__].commands["fasterpacmice"]=command_list["fasterpacmice"]
4957for i_map,map in pairs(pacmice_maps)do
4958pacmice_map=map
4959map.linear_grid={}
4960if not map.grid_w then
4961local max_grid_x,max_grid_y=1,1
4962for i_path,path in ipairs(map.pathes)do
4963max_grid_x=math.max(max_grid_x,path[1])
4964max_grid_y=math.max(max_grid_y,path[2])
4965end
4966map.grid_w=max_grid_x+1
4967map.grid_h=max_grid_y+1
4968end
4969for i_path,path in ipairs(map.pathes)do
4970GridSet(path[1],path[2],true)
4971end
4972end
4973pacmice_map=pacmice_maps[1]
4974for player_name in pairs(tfm.get.room.playerList)do
4975TouchPlayer(player_name)
4976end
4977tfm.exec.newGame("pacmice")
4978end
4979pshy.require("pshy.patches.old_movephysicobject")
4980pshy.require("pshy.games.pacmice")
4981pshy.require("pshy.events").CreateFunctions()
4982pshy.EnableModule("pshy.patches.old_movephysicobject")
4983pshy.EnableModule("pshy.games.pacmice")
4984print(string.format("<v>Loaded <ch2>%d files</ch2> in <vp>%d ms</vp>.", #pshy.modules_list, os.time() - pshy.INIT_TIME))
4985end
4986local __PSHY_PASTED__ = true
4987