partial combat system and bug fixes for go.. again?
Showing
11 changed files
with
249 additions
and
17 deletions
... | @@ -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: |
170 | import wifiweb | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
193 | print('Starting WIFIWeb') | ||
194 | import wifiweb | ... | ... |
mobs.txt
0 → 100644
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 |
mobs/cricket.json
0 → 100644
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 | ... | ... |
rooms/tavern_monsters.json
0 → 100644
-
Please register or sign in to post a comment