4112e223 by Barry

memory use improvements.

1 parent bb158dfa
...@@ -41,12 +41,15 @@ class CommandHandler(object): ...@@ -41,12 +41,15 @@ class CommandHandler(object):
41 command = cmd 41 command = cmd
42 ldict = locals() 42 ldict = locals()
43 with open('commands/{}.txt'.format(cmd), 'r', encoding='utf-8') as f: 43 with open('commands/{}.txt'.format(cmd), 'r', encoding='utf-8') as f:
44 exec(f.read(), globals(), ldict) 44 command_text = f.read()
45 exec(command_text, globals(), ldict)
46 del command_text
45 if ldict['next_command'] != None: 47 if ldict['next_command'] != None:
46 locals()['tokens'] = [] 48 locals()['tokens'] = []
47 tokens = [] 49 tokens = []
48 with open('commands/{}.txt'.format(ldict['next_command']), 'r', encoding='utf-8') as f: 50 with open('commands/{}.txt'.format(ldict['next_command']), 'r', encoding='utf-8') as f:
49 exec(f.read()) 51 exec(f.read())
52 del ldict
50 return True 53 return True
51 # except Exception as e: 54 # except Exception as e:
52 # print('Something happened...') 55 # print('Something happened...')
......
...@@ -24,3 +24,4 @@ def drop(id, tokens, players, mud): ...@@ -24,3 +24,4 @@ def drop(id, tokens, players, mud):
24 mud.send_message(id, 'You do not have {} in your inventory.'.format(tokens[0])) 24 mud.send_message(id, 'You do not have {} in your inventory.'.format(tokens[0]))
25 25
26 drop(id, tokens, players, mud) 26 drop(id, tokens, players, mud)
27 del drop
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -9,6 +9,9 @@ def get(id, tokens, players, mud): ...@@ -9,6 +9,9 @@ def get(id, tokens, players, mud):
9 players[id]['inventory'][tokens[0]] += 1 9 players[id]['inventory'][tokens[0]] += 1
10 else: 10 else:
11 players[id]['inventory'][tokens[0]] = 1 11 players[id]['inventory'][tokens[0]] = 1
12 room_data['inventory'][tokens[0]] -= 1
13 if room_data['inventory'][tokens[0]] <= 0:
14 del room_data['inventory'][tokens[0]]
12 for pid, pl in players.items(): 15 for pid, pl in players.items():
13 # if they're in the same room as the player 16 # if they're in the same room as the player
14 if players[pid]["room"] == players[id]["room"]: 17 if players[pid]["room"] == players[id]["room"]:
...@@ -16,6 +19,7 @@ def get(id, tokens, players, mud): ...@@ -16,6 +19,7 @@ def get(id, tokens, players, mud):
16 mud.send_message(pid, "{} picked up a {}.".format( 19 mud.send_message(pid, "{} picked up a {}.".format(
17 players[id]["name"], tokens[0])) 20 players[id]["name"], tokens[0]))
18 utils.save_object_to_file(players[id], "players/{}.json".format(players[id]["name"])) 21 utils.save_object_to_file(players[id], "players/{}.json".format(players[id]["name"]))
22 utils.save_object_to_file(room_data, 'rooms/' + room_name + '.json')
19 else: 23 else:
20 mud.send_message(id, 'There is no {} here to get.'.format(tokens[0])) 24 mud.send_message(id, 'There is no {} here to get.'.format(tokens[0]))
21 25
......
...@@ -57,3 +57,4 @@ def go(id, params, players, mud, tokens, command): ...@@ -57,3 +57,4 @@ def go(id, params, players, mud, tokens, command):
57 if command is None and cmd is not None: 57 if command is None and cmd is not None:
58 command = cmd 58 command = cmd
59 next_command = go(id, params, players, mud, tokens, command) 59 next_command = go(id, params, players, mud, tokens, command)
60 del go
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -12,3 +12,4 @@ def help(id, tokens, mud): ...@@ -12,3 +12,4 @@ def help(id, tokens, mud):
12 mud.send_message(id, 'No help topics available for \"{}\". A list\r\n of all commands is available at: help index'.format(tokens[0])) 12 mud.send_message(id, 'No help topics available for \"{}\". A list\r\n of all commands is available at: help index'.format(tokens[0]))
13 13
14 help(id, tokens, mud) 14 help(id, tokens, mud)
15 del help
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -5,3 +5,4 @@ def inventory(id, players, mud): ...@@ -5,3 +5,4 @@ def inventory(id, players, mud):
5 mud.send_message(id, '\r\n-----------------------------------------') 5 mud.send_message(id, '\r\n-----------------------------------------')
6 6
7 inventory(id, players, mud) 7 inventory(id, players, mud)
8 del inventory
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -47,3 +47,4 @@ def look(id, mud, players, tokens): ...@@ -47,3 +47,4 @@ def look(id, mud, players, tokens):
47 mud.send_message(id, "Mobs here: {}".format( ", ".join(room_monsters.keys()))) 47 mud.send_message(id, "Mobs here: {}".format( ", ".join(room_monsters.keys())))
48 48
49 look(id, mud, players, tokens) 49 look(id, mud, players, tokens)
50 del look
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -6,3 +6,4 @@ def prompt(id, tokens, params, players, mud): ...@@ -6,3 +6,4 @@ def prompt(id, tokens, params, players, mud):
6 utils.save_object_to_file(players[id], "players/{}.json".format(players[id]["name"])) 6 utils.save_object_to_file(players[id], "players/{}.json".format(players[id]["name"]))
7 7
8 prompt(id, tokens, params, players, mud) 8 prompt(id, tokens, params, players, mud)
9 del prompt
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -5,3 +5,4 @@ def quit(id, players, mud): ...@@ -5,3 +5,4 @@ def quit(id, players, mud):
5 mud.disconnect_player(id) 5 mud.disconnect_player(id)
6 6
7 quit(id, players, mud) 7 quit(id, players, mud)
8 del quit
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -5,3 +5,4 @@ def save(id, players, mud): ...@@ -5,3 +5,4 @@ def save(id, players, mud):
5 mud.send_message(id, "Save complete") 5 mud.send_message(id, "Save complete")
6 6
7 save(id, players, mud) 7 save(id, players, mud)
8 del save
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -7,3 +7,4 @@ def say(id, params, players, mud): ...@@ -7,3 +7,4 @@ def say(id, params, players, mud):
7 mud.send_message(pid, "{} says: {}".format( 7 mud.send_message(pid, "{} says: {}".format(
8 players[id]["name"], params)) 8 players[id]["name"], params))
9 say(id, params, players, mud) 9 say(id, params, players, mud)
10 del say
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -8,3 +8,4 @@ def whisper(id, tokens, players, mud): ...@@ -8,3 +8,4 @@ def whisper(id, tokens, players, mud):
8 players[id]["name"], ' '.join(tokens[1:]))) 8 players[id]["name"], ' '.join(tokens[1:])))
9 9
10 whisper(id, tokens, players, mud) 10 whisper(id, tokens, players, mud)
11 del whisper
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -6,3 +6,4 @@ def who(id, players, mud): ...@@ -6,3 +6,4 @@ def who(id, players, mud):
6 mud.send_message(id, "---------------------------------------------".format(len(players))) 6 mud.send_message(id, "---------------------------------------------".format(len(players)))
7 mud.send_message(id, "") 7 mud.send_message(id, "")
8 who(id, players, mud) 8 who(id, players, mud)
9 del who
...\ No newline at end of file ...\ No newline at end of file
......
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 2
3 """A simple Multi-User Dungeon (MUD) game. Players can talk to each
4 other, examine their surroundings and move between rooms.
5
6 Some ideas for things to try adding:
7 * More rooms to explore
8 * An 'emote' command e.g. 'emote laughs out loud' -> 'Mark laughs
9 out loud'
10 * A 'whisper' command for talking to individual players
11 * A 'shout' command for yelling to players in all rooms
12 * Items to look at in rooms e.g. 'look fireplace' -> 'You see a
13 roaring, glowing fire'
14 * Items to pick up e.g. 'take rock' -> 'You pick up the rock'
15 * Monsters to fight
16 * Loot to collect
17 * Saving players accounts between sessions
18 * A password login
19 * A shop from which to buy items
20
21 author: Mark Frimston - mfrimston@gmail.com
22 """ 3 """
4 MudServer author: Mark Frimston - mfrimston@gmail.com
23 5
24 import time 6 Micropython port and expansion author: Barry Ruffner - barryruffner@gmail.com
25 import sys 7 """
26 if 'esp' in sys.platform: 8
27 import gc 9 from time import sleep
28 import machine 10 from sys import platform
11 if 'esp' in platform:
12 from gc import collect, mem_free
13 from machine import Pin
29 # import the MUD server class 14 # import the MUD server class
30 from mudserver import MudServer 15 from mudserver import MudServer
31 16
32 import utils 17 from utils import load_object_from_file, save_object_to_file
33 18
34 print('STARTING MUD\r\n\r\n\r\n') 19 print('STARTING MUD\r\n\r\n\r\n')
35 20
36 if 'esp' in sys.platform: 21 if 'esp' in platform:
37 flash_button = machine.Pin(0, machine.Pin.IN, machine.Pin.PULL_UP) 22 flash_button = Pin(0, Pin.IN, Pin.PULL_UP)
38 23
39 # stores the players in the game 24 # stores the players in the game
40 players = {} 25 players = {}
...@@ -59,14 +44,13 @@ tick = 0.0 ...@@ -59,14 +44,13 @@ tick = 0.0
59 spawn = 0.0 44 spawn = 0.0
60 # main game loop. We loop forever (i.e. until the program is terminated) 45 # main game loop. We loop forever (i.e. until the program is terminated)
61 while True: 46 while True:
62 if 'esp' in sys.platform: 47 if 'esp' in platform:
63 gc.collect() 48 collect()
64 if flash_button.value() == 0: 49 if flash_button.value() == 0:
65 break 50 break
66 # pause for 1/5 of a second on each loop, so that we don't constantly 51 # pause for 1/5 of a second on each loop, so that we don't constantly
67 # use 100% CPU time 52 sleep(0.001)
68 time.sleep(0.001) 53 if 'esp' in platform:
69 if 'esp' in sys.platform:
70 tick += 0.001 54 tick += 0.001
71 else: 55 else:
72 tick += 0.0005 56 tick += 0.0005
...@@ -80,6 +64,7 @@ while True: ...@@ -80,6 +64,7 @@ while True:
80 print('spawner error:') 64 print('spawner error:')
81 print(e) 65 print(e)
82 if tick >= 1: 66 if tick >= 1:
67 print(mem_free())
83 spawn += tick 68 spawn += tick
84 tick = 0 69 tick = 0
85 # try: 70 # try:
...@@ -101,7 +86,7 @@ while True: ...@@ -101,7 +86,7 @@ while True:
101 # The dictionary key is the player's id number. We set their room to 86 # The dictionary key is the player's id number. We set their room to
102 # None initially until they have entered a name 87 # None initially until they have entered a name
103 # Try adding more player stats - level, gold, inventory, etc 88 # Try adding more player stats - level, gold, inventory, etc
104 players[id] = utils.load_object_from_file("defaultplayer.json") 89 players[id] = load_object_from_file("defaultplayer.json")
105 with open('welcome.txt', 'r', encoding='utf-8') as f: 90 with open('welcome.txt', 'r', encoding='utf-8') as f:
106 for line in f: 91 for line in f:
107 mud.send_message(id, line, "\r") 92 mud.send_message(id, line, "\r")
...@@ -121,12 +106,11 @@ while True: ...@@ -121,12 +106,11 @@ while True:
121 # send each player a message to tell them about the diconnected 106 # send each player a message to tell them about the diconnected
122 # player 107 # player
123 if players[pid]["name"] != None: 108 if players[pid]["name"] != None:
124 mud.send_message(pid, "{} quit the game".format( 109 mud.send_message(pid, "{} quit the game".format(players[pid]["name"]))
125 players[pid]["name"]))
126 110
127 # remove the player's entry in the player dictionary 111 # remove the player's entry in the player dictionary
128 if players[id]["name"] != None: 112 if players[id]["name"] != None:
129 utils.save_object_to_file(players[id], "players/{}.json".format(players[id]["name"])) 113 save_object_to_file(players[id], "players/{}.json".format(players[id]["name"]))
130 del(players[id]) 114 del(players[id])
131 115
132 # go through any new commands sent from players 116 # go through any new commands sent from players
...@@ -151,7 +135,7 @@ while True: ...@@ -151,7 +135,7 @@ while True:
151 already_logged_in = True 135 already_logged_in = True
152 if already_logged_in: 136 if already_logged_in:
153 continue 137 continue
154 loaded_player = utils.load_object_from_file("players/{}.json".format(command)) 138 loaded_player = load_object_from_file("players/{}.json".format(command))
155 if loaded_player is None: 139 if loaded_player is None:
156 players[id]["name"] = command 140 players[id]["name"] = command
157 players[id]["room"] = "Tavern" 141 players[id]["room"] = "Tavern"
...@@ -171,7 +155,7 @@ while True: ...@@ -171,7 +155,7 @@ while True:
171 155
172 # send the new player the description of their current room 156 # send the new player the description of their current room
173 157
174 mud.send_message(id, utils.load_object_from_file('rooms/' + players[id]["room"] + '.json')['description']) 158 mud.send_message(id, load_object_from_file('rooms/' + players[id]["room"] + '.json')['description'])
175 159
176 else: 160 else:
177 from commandhandler import CommandHandler 161 from commandhandler import CommandHandler
...@@ -182,7 +166,7 @@ while True: ...@@ -182,7 +166,7 @@ while True:
182 show_prompt(id) 166 show_prompt(id)
183 167
184 # Start WIFI Setup 168 # Start WIFI Setup
185 if 'esp' in sys.platform: 169 if 'esp' in platform:
186 if flash_button.value() == 0: 170 if flash_button.value() == 0:
187 print('Starting WIFIWeb') 171 print('Starting WIFIWeb')
188 import wifiweb 172 import wifiweb
......
1 1
2 def run_mobs(players, mud): 2 def run_mobs(players, mud):
3 def get_att(d):
4 att = 0
5 if 'd' in d:
6 dice = d.split('d')
7 for d in range(int(dice[0])):
8 att += utils.randrange(int(dice[1])) + 1
9 else:
10 att = int(d)
11 return att
12 def calc_att(pid, attacks, bank):
13 v_att = []
14 att = 0
15 for attack in attacks:
16 if attack['cost'] < bank:
17 v_att.append(attack)
18 # Select a random attack
19 if len(v_att) > 0:
20 attack = v_att[utils.randrange(len(v_att))]
21 att = get_att(attack['dmg'])
22 mud.send_message(pid, "%s for %d" % (attack['desc'], att,))
23 bank -= attack['cost']
24 return att, bank
25 3
4 from utils import load_object_from_file, save_object_to_file, calc_att, get_att
26 for pid, player in players.items(): 5 for pid, player in players.items():
27 if not player['name']: 6 if not player['name']:
28 continue 7 continue
29 room_monsters = utils.load_object_from_file('rooms/{}_monsters.json'.format(player['room'])) 8 room_monsters = load_object_from_file('rooms/{}_monsters.json'.format(player['room']))
30 if not room_monsters: 9 if not room_monsters:
31 continue 10 continue
32 for mon_name, monster in room_monsters.items(): 11 for mon_name, monster in room_monsters.items():
33 monster_template = utils.load_object_from_file('mobs/{}.json'.format(mon_name)) 12 monster_template = load_object_from_file('mobs/{}.json'.format(mon_name))
34 if not monster_template: 13 if not monster_template:
35 continue 14 continue
36 for active_monster_idx, active_monster in enumerate(monster['active']): 15 for active_monster_idx, active_monster in enumerate(monster['active']):
...@@ -44,40 +23,43 @@ def run_mobs(players, mud): ...@@ -44,40 +23,43 @@ def run_mobs(players, mud):
44 sta += monster_template['star'] 23 sta += monster_template['star']
45 active_monster['sta'] = sta 24 active_monster['sta'] = sta
46 if active_monster['action'] == "attack" and active_monster['target'] == player['name']: 25 if active_monster['action'] == "attack" and active_monster['target'] == player['name']:
47 if player["weapon"]: 26 if player.get("weapon"):
48 weapon = utils.load_object_from_file('inventory/{}.json'.format(player['weapon'])) 27 weapon = load_object_from_file('inventory/{}.json'.format(player['weapon']))
49 if weapon:
50 att = get_att(weapon['damage']) 28 att = get_att(weapon['damage'])
51 mud.send_message(pid, "Your %s strikes the %s for %d" % (weapon['title'], mon_name, att,)) 29 mud.send_message(pid, "Your %s strikes the %s for %d" % (weapon['title'], mon_name, att,))
52 else: 30 else:
53 att = get_att(player['aa']) 31 att = get_att(player['aa'])
54 else:
55 att = get_att(player['aa'])
56 mud.send_message(pid, "You hit the %s for %d" % (mon_name, att,)) 32 mud.send_message(pid, "You hit the %s for %d" % (mon_name, att,))
57 hp -= att 33 hp -= att
58 if hp == 0: 34 if hp == 0:
59 DEAD = 1 35 DEAD = 1
36 if active_monster.get("weapon"):
37 weapon = load_object_from_file('inventory/{}.json'.format(active_monster['weapon']))
38 att = get_att(weapon['damage'])
39 mud.send_message(pid, "The %s strikes you with a %s for %d" % (mon_name, weapon['title'], att,))
40 else:
60 att = get_att(monster_template['aa']) 41 att = get_att(monster_template['aa'])
61 players[pid]['hp'] -= att
62 mud.send_message(pid, "You were hit by a %s for %d" % (mon_name, att,)) 42 mud.send_message(pid, "You were hit by a %s for %d" % (mon_name, att,))
43 players[pid]['hp'] -= att
63 # wait until at least 50% of stamina or mp are regenerated or hp is less than 25% 44 # wait until at least 50% of stamina or mp are regenerated or hp is less than 25%
64 45
65 if (hp/active_monster['maxhp'] < 0.25) or (mp > 0 and mp/active_monster['maxmp'] > 0.5) or (sta > 0 and sta/active_monster['maxsta'] > 0.5): 46 if (hp/active_monster['maxhp'] < 0.25) or (mp > 0 and mp/active_monster['maxmp'] > 0.5) or (sta > 0 and sta/active_monster['maxsta'] > 0.5):
66 magic_cast = False 47 magic_cast = False
67 if mp > 0: 48 if mp > 0:
68 att, mp = calc_att(pid, monster_template['sp'], mp) 49 att, mp = calc_att(mud, pid, monster_template['sp'], mp)
69 active_monster['mp'] = mp 50 active_monster['mp'] = mp
70 players[pid]['hp'] -= att 51 players[pid]['hp'] -= att
71 if att > 0: 52 if att > 0:
72 magic_cast = True 53 magic_cast = True
73 if not magic_cast: 54 if not magic_cast:
74 if sta > 0: 55 if sta > 0:
75 att, sta = calc_att(pid, monster_template['at'], sta) 56 att, sta = calc_att(mud, pid, monster_template['at'], sta)
76 active_monster['sta'] = sta 57 active_monster['sta'] = sta
77 players[pid]['hp'] -= att 58 players[pid]['hp'] -= att
78 59
79 room_monsters[mon_name]['active'][active_monster_idx] = active_monster 60 room_monsters[mon_name]['active'][active_monster_idx] = active_monster
80 61
81 utils.save_object_to_file(room_monsters, 'rooms/{}_monsters.json'.format(player['room'])) 62 save_object_to_file(room_monsters, 'rooms/{}_monsters.json'.format(player['room']))
82 63
83 run_mobs(players, mud) 64 run_mobs(players, mud)
65 del run_mobs
...\ No newline at end of file ...\ No newline at end of file
......
1 {"name": "test", "room": "Tavern", "inventory": {"candle": 1}, "prompt": "%hp> ", "aliases": {}, "hp": 596, "mp": 100, "sta": 10, "aa": "1d2", "mpr": 0.25, "star": 0.4, "maxhp": 953, "maxmp": 100, "maxsta": 10, "weapon": "sword"}
...\ No newline at end of file ...\ No newline at end of file
1 {"name": "test", "room": "Outside", "inventory": {"candle": 1}, "prompt": "%hp> ", "aliases": {}, "hp": 593, "mp": 100, "sta": 10, "aa": "1d2", "mpr": 0.25, "star": 0.4, "maxhp": 953, "maxmp": 100, "maxsta": 10, "weapon": "sword"}
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -36,6 +36,7 @@ def run_command(sio, command, expected='>>>'): ...@@ -36,6 +36,7 @@ def run_command(sio, command, expected='>>>'):
36 36
37 with serial.Serial(PORT, BAUDRATE, timeout=1) as ser: 37 with serial.Serial(PORT, BAUDRATE, timeout=1) as ser:
38 sio = io.TextIOWrapper(io.BufferedRWPair(ser, ser)) 38 sio = io.TextIOWrapper(io.BufferedRWPair(ser, ser))
39 run_command(sio, '\x03')
39 run_command(sio, 'import os') 40 run_command(sio, 'import os')
40 root = eval(run_command(sio, 'os.listdir()', expected=']')) 41 root = eval(run_command(sio, 'os.listdir()', expected=']'))
41 42
...@@ -52,13 +53,14 @@ with serial.Serial(PORT, BAUDRATE, timeout=1) as ser: ...@@ -52,13 +53,14 @@ with serial.Serial(PORT, BAUDRATE, timeout=1) as ser:
52 print('Folders already created.') 53 print('Folders already created.')
53 54
54 55
55 for folder in folders: 56 for folder in folders:
56 for f in os.listdir(folder): 57 for f in os.listdir(folder):
57 files.append('{}/{}'.format(folder, f)) 58 files.append('{}/{}'.format(folder, f))
58 59
59 with open('releasepw.conf', 'r', encoding='utf-8') as f: 60 with open('releasepw.conf', 'r', encoding='utf-8') as f:
60 password = f.read() 61 password = f.read()
61 62
62 for file in files: 63 for file in files:
63 os.system("python webrepl\webrepl_cli.py -p {} {} {}:/{}".format(password, file, IPADDRESS, file)) 64 os.system("python webrepl\webrepl_cli.py -p {} {} {}:/{}".format(password, file, IPADDRESS, file))
64 65
66 run_command(sio, 'import machine;machine.reset')
......
1 {"cricket": {"max": 1, "active": [{"hp": 100, "mp": 0.25, "sta": 2.7500000000000715, "maxhp": 100, "maxmp": 10, "maxsta": 10, "action": "attack", "target": "test"}]}}
...\ No newline at end of file ...\ No newline at end of file
1 {"cricket": {"max": 1, "active": [{"hp": 100, "mp": 2.0, "sta": 4.550000000000075, "maxhp": 100, "maxmp": 10, "maxsta": 10, "action": "attack", "target": "test"}]}}
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -38,3 +38,26 @@ def randrange(start, stop=None): ...@@ -38,3 +38,26 @@ def randrange(start, stop=None):
38 return r + start 38 return r + start
39 else: 39 else:
40 return random.randrange(start) 40 return random.randrange(start)
41
42 def get_att(d):
43 att = 0
44 if 'd' in d:
45 dice = d.split('d')
46 for d in range(int(dice[0])):
47 att += randrange(int(dice[1])) + 1
48 else:
49 att = int(d)
50 return att
51 def calc_att(mud, pid, attacks, bank):
52 v_att = []
53 att = 0
54 for attack in attacks:
55 if attack['cost'] < bank:
56 v_att.append(attack)
57 # Select a random attack
58 if len(v_att) > 0:
59 attack = v_att[randrange(len(v_att))]
60 att = get_att(attack['dmg'])
61 mud.send_message(pid, "%s for %d" % (attack['desc'], att,))
62 bank -= attack['cost']
63 return att, bank
...\ No newline at end of file ...\ No newline at end of file
......