b3a05ac4 by Barry

partial combat system and bug fixes for go.. again?

1 parent 955331a5
...@@ -2,3 +2,60 @@ ...@@ -2,3 +2,60 @@
2 2
3 This project is a simple mud that runs entirely within an ESP8266 and can be accessed via the wifi portal it connects to. 3 This project is a simple mud that runs entirely within an ESP8266 and can be accessed via the wifi portal it connects to.
4 4
5 ## Next Steps
6
7 1. every tick loop through the players
8 2. for each player load the roomname_monsters.txt
9 3. execute any current action [flee (maybe later), attack, continue combat, special attack (if enough mp or stamina)]
10 4. Write results of action to the roomname_monsters.txt if the monster is killed or mp / stamina has changed. - Sidenote.. don't store inventory, get a list of possible inventory and randomize on death and drop on the ground (no corpses)
11 5. Process any special commands from the player [spells, special attacks based on stamina]
12 6. Write results of action to the player file [damage, mp use, stamina use]
13 7. Write any new inventory to the room file. Expire any inventory that is old TBD....
14 8. Every minute respawn mobs for any room the players are in.
15
16 ## Mob Format
17
18 Mobs folder:
19
20 monstername.json
21
22 Example:
23 ```
24 {
25 "name": "cricket",
26 "desc": "A small green chirping insect with large legs suited for jumping.",
27 "aa": "1d2",
28 "spawn": {
29 "hp": "2d2",
30 "mp": "0",
31 "sta": "10",
32 },
33 "say": [
34 "A cricket quietly chirps",
35 "A cricket moves quietly"
36 ],
37 "sp": [],
38 "at": [
39 {"name": "kick", "cost":5, "dmg": "2d4", "desc": "The cricket kicks with powerful legs"},
40 {"name": "antenna tickle", "cost":2, "dmg": "1d3" "desc": "The cricket brushes you with antenna"},
41 ]
42
43 }
44 ```
45
46 All damage rolls are described in the number of times to roll and the random amount in dice format: 1d20 = 1 to 20, 2d6 = 2 to 12
47
48 * name - The name that will be displayed to the user when the monster is described
49 * desc - The description that will be displayed to the user when the monster is looked at
50 * aa - Auto-Attack amount that will be applied for every tick
51 * spawn - The values used when the spawner creates the monster to seed the values. A direct integer means the value will be set to that value always.
52 * hp - the starting hp range
53 * mp - the starting mp range
54 * sta - the stamina used to perform special attacks or actions
55 * say - Things when not in combat the monster will express to anyone in the room.
56 * sp - A list of spells that appear in the spells/ folder
57 * at - Special attacks
58 * name - The special attack name
59 * cost - The cost in stamina of the attack
60 * dmg - the amount of damage caused by this attack
61 * desc - the description to display when the attack is performed
......
...@@ -36,10 +36,14 @@ class CommandHandler(object): ...@@ -36,10 +36,14 @@ class CommandHandler(object):
36 if cmd in utils.load_object_from_file('rooms/' + players[id]["room"] + '.txt').get('exits'): 36 if cmd in utils.load_object_from_file('rooms/' + players[id]["room"] + '.txt').get('exits'):
37 params = cmd + " " + params.lower().strip() 37 params = cmd + " " + params.lower().strip()
38 cmd = "go" 38 cmd = "go"
39 if cmd == '':
40 return True
39 ldict = locals() 41 ldict = locals()
40 with open('commands/{}.txt'.format(cmd), 'r', encoding='utf-8') as f: 42 with open('commands/{}.txt'.format(cmd), 'r', encoding='utf-8') as f:
41 exec(f.read(), globals(), ldict) 43 exec(f.read(), globals(), ldict)
42 if ldict['next_command'] != None: 44 if ldict['next_command'] != None:
45 locals()['tokens'] = []
46 tokens = []
43 with open('commands/{}.txt'.format(ldict['next_command']), 'r', encoding='utf-8') as f: 47 with open('commands/{}.txt'.format(ldict['next_command']), 'r', encoding='utf-8') as f:
44 exec(f.read()) 48 exec(f.read())
45 return True 49 return True
......
1 def go(id, params, players, mud, tokens): 1 def go(id, params, players, mud, tokens, command):
2 # store the exit name 2 # store the exit name
3 params = params.lower().strip() 3 params = params.strip()
4 if params == '':
5 params = command
4 6
5 room_data = utils.load_object_from_file('rooms/' + players[id]["room"] + '.txt') 7 room_data = utils.load_object_from_file('rooms/' + players[id]["room"] + '.txt')
6 exits = room_data['exits'] 8 exits = room_data['exits']
7 # if the specified exit is found in the room's exits list 9 # if the specified exit is found in the room's exits list
10
8 if params in exits: 11 if params in exits:
9 # go through all the players in the game 12 # go through all the players in the game
10 for pid, pl in players.items(): 13 for pid, pl in players.items():
...@@ -47,4 +50,4 @@ def go(id, params, players, mud, tokens): ...@@ -47,4 +50,4 @@ def go(id, params, players, mud, tokens):
47 else: 50 else:
48 # send back an 'unknown exit' message 51 # send back an 'unknown exit' message
49 mud.send_message(id, "Unknown exit '{}'".format(params)) 52 mud.send_message(id, "Unknown exit '{}'".format(params))
50 next_command = go(id, params, players, mud, tokens)
...\ No newline at end of file ...\ No newline at end of file
53 next_command = go(id, params, players, mud, tokens, cmd)
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -49,21 +49,43 @@ def prompt(pid): ...@@ -49,21 +49,43 @@ def prompt(pid):
49 players[pid]["hp"] = 100 49 players[pid]["hp"] = 100
50 if 'mp' not in players[pid]: 50 if 'mp' not in players[pid]:
51 players[pid]["mp"] = 100 51 players[pid]["mp"] = 100
52 if 'sta' not in players[pid]:
53 players[pid]["sta"] = 10
52 54
53 prompt = players[pid]["prompt"].replace('%hp', str(players[pid]["hp"])).replace('%mp', str(players[pid]["mp"])) 55 prompt = players[pid]["prompt"].replace('%hp', str(players[pid]["hp"])).replace('%mp', str(players[pid]["mp"]))
54 mud.send_message(pid, "\r\n" + prompt, '') 56 mud.send_message(pid, "\r\n" + prompt, '')
55 57
58 tick = 0.0
59 spawn = 0.0
56 # main game loop. We loop forever (i.e. until the program is terminated) 60 # main game loop. We loop forever (i.e. until the program is terminated)
57 while True: 61 while True:
58 if 'esp' in sys.platform: 62 if 'esp' in sys.platform:
59 gc.collect() 63 gc.collect()
60 print(flash_button.value())
61 if flash_button.value() == 0: 64 if flash_button.value() == 0:
62 break 65 break
63 # pause for 1/5 of a second on each loop, so that we don't constantly 66 # pause for 1/5 of a second on each loop, so that we don't constantly
64 # use 100% CPU time 67 # use 100% CPU time
65 time.sleep(0.001) 68 time.sleep(0.001)
66 69 tick += 0.001
70 if spawn >= 60:
71 spawn = 0
72 try:
73 ldict = {}
74 with open('spawner.txt', 'r', encoding='utf-8') as f:
75 exec(f.read(), globals(), ldict)
76 except Exception as e:
77 print('spawner error:')
78 print(e)
79 if tick >= 3:
80 spawn += tick
81 tick = 0
82 try:
83 ldict = {}
84 with open('mobs.txt', 'r', encoding='utf-8') as f:
85 exec(f.read(), globals(), ldict)
86 except Exception as e:
87 print('mob error:')
88 print(e)
67 # 'update' must be called in the loop to keep the game running and give 89 # 'update' must be called in the loop to keep the game running and give
68 # us up-to-date information 90 # us up-to-date information
69 mud.update() 91 mud.update()
...@@ -84,6 +106,7 @@ while True: ...@@ -84,6 +106,7 @@ while True:
84 "aliases": {}, 106 "aliases": {},
85 "hp": 100, 107 "hp": 100,
86 "mp": 100, 108 "mp": 100,
109 "sta": 10,
87 } 110 }
88 with open('welcome.txt', 'r', encoding='utf-8') as f: 111 with open('welcome.txt', 'r', encoding='utf-8') as f:
89 for line in f: 112 for line in f:
...@@ -167,4 +190,5 @@ while True: ...@@ -167,4 +190,5 @@ while True:
167 # Start WIFI Setup 190 # Start WIFI Setup
168 if 'esp' in sys.platform: 191 if 'esp' in sys.platform:
169 if flash_button.value() == 0: 192 if flash_button.value() == 0:
193 print('Starting WIFIWeb')
170 import wifiweb 194 import wifiweb
......
1 # 1. every tick loop through the players
2 # 2. for each player load the roomname_monsters.txt
3 # 3. execute any current action [flee (maybe later), attack, continue combat, special attack (if enough mp or stamina)]
4 # 4. Write results of action to the roomname_monsters.txt if the monster is killed or mp / stamina has changed. - Sidenote.. don't store inventory, get a list of possible inventory and randomize on death and drop on the ground (no corpses)
5 # 5. Process any special commands from the player [spells, special attacks based on stamina]
6 # 6. Write results of action to the player file [damage, mp use, stamina use]
7 # 7. Write any new inventory to the room file. Expire any inventory that is old TBD....
8 # 8. Every minute respawn mobs for any room the players are in.
9
10
11
12
13 # def randint(start, stop):
14 # return randrange(start, stop + 1)
15
16 def run_mobs(players, mud):
17 def randrange(start, stop=None):
18 if 'esp' in sys.platform:
19 if stop is None:
20 stop = start
21 start = 0
22 upper = stop - start
23 bits = 0
24 pwr2 = 1
25 while upper > pwr2:
26 pwr2 <<= 1
27 bits += 1
28 while True:
29 from urandom import getrandbits
30 r = getrandbits(bits)
31 if r < upper:
32 break
33 return r + start
34 else:
35 import random
36 return random.randrange(start)
37
38 for pid, player in players.items():
39 if not player['name']:
40 continue
41 print(player)
42 print('checking actions in room: ' + player['room'])
43 room_monsters = utils.load_object_from_file('rooms/{}_monsters.json'.format(player['room']))
44 for mon_name, monster in room_monsters.items():
45 print(mon_name)
46 monster_template = utils.load_object_from_file('mobs/{}.json'.format(mon_name))
47 print(monster)
48 for active_monster in monster['active']:
49 if active_monster['action'] == "attack":
50 if active_monster['hp'] == 0:
51 DEAD = 1
52 if "d" in monster_template['aa']:
53 dice = monster_template['aa'].split('d')
54 att = 0
55 for d in range(int(dice[0])):
56 att += randrange(int(dice[1]) + 1)
57 players[pid]['hp'] -= att
58 mud.send_message(pid, "You were hit by a %s for %d" % (mon_name, att,))
59 else:
60 print(randrange(120))
61 # {
62 # "cricket": {
63 # "max": 1,
64 # "active": [
65 # {
66 # "hp": 100,
67 # "mp": 0,
68 # "sta": 10,
69 # "action": "attack",
70 # "target": "test",
71 # }
72 # ]
73 # }
74 # }
75 #prompt(pid)
76 # active_mobs = utils.load_object_from_file('activemobs.json')
77 # # check to see if everything has been spawned that needs to be.
78 # {
79 # "cricket": {
80 # "room001": {
81 # "max": 2,
82 # "active": [
83 # {
84 # "hp": 100,
85 # "mp": 0,
86 # "sta": 10,
87 # "inv": []
88 # },
89 # {
90 # "hp": 100,
91 # "mp": 0,
92 # "sta": 10,
93 # "inv": []
94 # }
95 # ]
96 # },
97 # "tavern": {
98 # "max": 1,
99 # "active": [
100 # {
101 # "hp": 100,
102 # "mp": 0,
103 # "sta": 10,
104 # "inv": []
105 # }
106 # ]
107 # }
108 # }
109 # }
110 # for mob in active_mobs:
111
112
113
114 run_mobs(players, mud)
...\ No newline at end of file ...\ No newline at end of file
1 {
2 "name": "cricket",
3 "desc": "A small green chirping insect with large legs suited for jumping.",
4 "aa": "1d2",
5 "spawn": {
6 "hp": "2d2",
7 "mp": "0",
8 "sta": "10"
9 },
10 "say": [
11 "A cricket quietly chirps",
12 "A cricket moves quietly"
13 ],
14 "sp": [],
15 "at": [
16 {"name": "kick", "cost":5, "dmg": "2d4", "desc": "The cricket kicks with powerful legs"},
17 {"name": "antenna tickle", "cost":2, "dmg": "1d3", "desc": "The cricket brushes you with antenna"}
18 ]
19 }
...\ No newline at end of file ...\ No newline at end of file
1 {"name": "test", "room": "Tavern", "inventory": {"candle": 1}, "prompt": "%hp> ", "aliases": {}, "hp": 100, "mp": 100}
...\ No newline at end of file ...\ No newline at end of file
1 {"name": "test", "room": "Outside", "inventory": {"candle": 1}, "prompt": "%hp> ", "aliases": {}, "hp": 96, "mp": 100, "sta": 10}
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -28,5 +28,5 @@ with open('releasepw.conf', 'r', encoding='utf-8') as f: ...@@ -28,5 +28,5 @@ with open('releasepw.conf', 'r', encoding='utf-8') as f:
28 password = f.read() 28 password = f.read()
29 29
30 for file in files: 30 for file in files:
31 os.system("python webrepl\webrepl_cli.py -p {} {} 192.168.1.126:/{}".format(password, file, file)) 31 os.system("python webrepl\webrepl_cli.py -p {} {} 192.168.1.189:/{}".format(password, file, file))
32 32
......
1 {
2 "title": "Outside the Tavern",
3 "description": "You are standing outside of a simple tavern made of pressed clay and shale roof. The door becons you to come in and have a drink.",
4 "exits": {"tavern": "Tavern"},
5 "look_items": {
6 "tavern": "A roughly constructed building."
7 },
8 "inventory": {}
9 }
...\ No newline at end of file ...\ No newline at end of file
1 {"title": "Outside the Tavern", "description": "You are standing outside of a simple tavern made of pressed clay and shale roof. The door becons you to come in and have a drink.", "exits": {"tavern": "Tavern"}, "look_items": {"tavern": "A roughly constructed building."}, "inventory": {"candle": 1}}
...\ No newline at end of file ...\ No newline at end of file
......
1 {
2 "cricket": {
3 "max": 1,
4 "active": [
5 {
6 "hp": 100,
7 "mp": 0,
8 "sta": 10,
9 "action": "attack",
10 "target": "test"
11 }
12 ]
13 }
14 }
...\ No newline at end of file ...\ No newline at end of file
1 def spawn_mobs(players):
2 for pid, player in players.items():
3 print('checking spawn in room: ' + player['room'])
4
5 spawn_mobs(players)
...\ No newline at end of file ...\ No newline at end of file