You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
338 lines
13 KiB
338 lines
13 KiB
#!/usr/bin/env python
|
|
|
|
import os
|
|
import re
|
|
import sys
|
|
import math
|
|
import json
|
|
|
|
|
|
class MapDoorText:
|
|
number_map = {
|
|
"a ": 1,
|
|
"an ": 1,
|
|
"the ": 1,
|
|
"one ": 1,
|
|
"two ": 2,
|
|
"three ": 3,
|
|
"four ": 4,
|
|
"five ": 5,
|
|
"six ": 6,
|
|
"seven ": 7,
|
|
"eight ": 8,
|
|
"nine ": 9,
|
|
"ten ": 10,
|
|
"eleven ": 11,
|
|
"twelve ": 12,
|
|
"thirteen ": 13,
|
|
"fourteen ": 14,
|
|
"fifteen ": 15,
|
|
"sixteen ": 16,
|
|
"seventeen ": 17,
|
|
"eighteen ": 18,
|
|
"nineteen ": 19,
|
|
"twenty ": 20,
|
|
"twenty-one ": 21,
|
|
"twenty-two ": 22,
|
|
"twenty-three ": 23,
|
|
"twenty-four ": 24,
|
|
"twenty-five ": 25,
|
|
"twenty-six ": 26,
|
|
"twenty-seven ": 27,
|
|
"twenty-eight ": 28,
|
|
"twenty-nine ": 29,
|
|
"thirty ": 30,
|
|
}
|
|
|
|
direction_map = {
|
|
"north": "n",
|
|
"northeast": "ne",
|
|
"east": "e",
|
|
"southeast": "se",
|
|
"south": "s",
|
|
"southwest": "sw",
|
|
"west": "w",
|
|
"northwest": "nw",
|
|
"n": "n",
|
|
"ne": "ne",
|
|
"e": "e",
|
|
"se": "se",
|
|
"s": "s",
|
|
"sw": "sw",
|
|
"w": "w",
|
|
"nw": "nw",
|
|
}
|
|
colour_map = {
|
|
# http://terminal-color-builder.mudasobwa.ru/
|
|
"orange": "\033[01;38;05;214m",
|
|
"red": "\033[01;38;05;196m",
|
|
"cyan": "\033[01;38;05;37m",
|
|
"reset": "\033[00;39;49m"
|
|
}
|
|
|
|
def __init__(self):
|
|
self.return_value = []
|
|
self.custom_matches = []
|
|
|
|
# Load the JSON configuration file
|
|
with open('mdtconfig.json', 'r') as config_file:
|
|
config = json.load(config_file)
|
|
|
|
# Strip comments from custom matches
|
|
for match in config['custom_matches']:
|
|
if len(match) > 1:
|
|
self.custom_matches.append(match)
|
|
|
|
self.default_npc_value = config['default_npc_value']
|
|
self.bonus_player_value = config['bonus_player_value']
|
|
self.minimum_room_value = config['minimum_room_value']
|
|
self.show_hidden_room_count = config['show_hidden_room_count']
|
|
|
|
@staticmethod
|
|
def explode(div, mdt):
|
|
if div == '':
|
|
return False
|
|
pos, fragments = 0, []
|
|
for m in re.finditer(div, mdt):
|
|
fragments.append(mdt[pos:m.start()])
|
|
pos = m.end()
|
|
fragments.append(mdt[pos:])
|
|
return fragments
|
|
|
|
def parse_mdt(self, mdt_line):
|
|
# Make lower case, do initial replacements
|
|
mdt_line = mdt_line.lower()
|
|
mdt_line = mdt_line.replace(" are ", " is ")
|
|
mdt_line = mdt_line.replace(" black and white ", " black white ")
|
|
mdt_line = mdt_line.replace(" brown and white ", " brown white ")
|
|
mdt_line = mdt_line.replace("the limit of your vision is ", "the limit of your vision:")
|
|
mdt_line = mdt_line.replace(" and ", ", ")
|
|
mdt_line = mdt_line.replace(" is ", ", ")
|
|
mdt_table = self.explode(', ', mdt_line)
|
|
|
|
data = {
|
|
'last_direction': '',
|
|
'last_enemy_line': '',
|
|
'last_count': 0,
|
|
'last_was_dir': 0,
|
|
'enemies_by_square': [],
|
|
'ignoring_exits': False,
|
|
'entity_table': [],
|
|
'room_id': 1,
|
|
'room_value': 0,
|
|
'longest_direction': 0,
|
|
'nothing': True,
|
|
'next_color': ''
|
|
}
|
|
exit_strings = ['doors ', 'a door ', 'exits ', 'an exit ', 'a hard to see through exit ']
|
|
|
|
for entry in mdt_table:
|
|
if entry != "" and ' of a ' not in entry:
|
|
if entry.startswith(tuple(exit_strings)):
|
|
# print('Special exit, ignore this line? next line is processed...')
|
|
data['ignoring_exits'] = True
|
|
elif entry.startswith('the limit of your vision:'):
|
|
if data['last_count'] > 0:
|
|
this_square = [data['last_count'], data['last_direction'], data['room_id'], int(math.floor(data['room_value']))]
|
|
data['enemies_by_square'].append(this_square)
|
|
data['nothing'] = False
|
|
data['next_color'] = ''
|
|
data['room_id'] = data['room_id'] + 1
|
|
data['room_value'] = 0
|
|
data['last_direction'] = ''
|
|
data['last_enemy_line'] = ''
|
|
data['last_count'] = 0
|
|
data['last_was_dir'] = 0
|
|
else:
|
|
# find the quantity first
|
|
quantity = 1
|
|
for nm_key in self.number_map:
|
|
if entry.startswith(nm_key):
|
|
quantity = self.number_map[nm_key]
|
|
entry = entry[len(nm_key):]
|
|
break
|
|
|
|
is_direction = 0
|
|
this_direction = ''
|
|
|
|
if entry.startswith("northeast"):
|
|
is_direction = 1
|
|
this_direction = "northeast"
|
|
elif entry.startswith("northwest"):
|
|
is_direction = 1
|
|
this_direction = "northwest"
|
|
elif entry.startswith("southeast"):
|
|
is_direction = 1
|
|
this_direction = "southeast"
|
|
elif entry.startswith("southwest"):
|
|
is_direction = 1
|
|
this_direction = "southwest"
|
|
elif entry.startswith("north"):
|
|
is_direction = 1
|
|
this_direction = "north"
|
|
elif entry.startswith("east"):
|
|
is_direction = 1
|
|
this_direction = "east"
|
|
elif entry.startswith("south"):
|
|
is_direction = 1
|
|
this_direction = "south"
|
|
elif entry.startswith("west"):
|
|
is_direction = 1
|
|
this_direction = "west"
|
|
|
|
if is_direction == 1:
|
|
if not data['ignoring_exits']:
|
|
# print('[handling direction, not exits]')
|
|
data['last_was_dir'] = 1
|
|
|
|
if data['last_direction'] != '':
|
|
data['last_direction'] = '{}, '.format(data['last_direction'])
|
|
|
|
data['last_direction'] = '{}{} {}'.format(
|
|
data['last_direction'], quantity, self.direction_map[this_direction]
|
|
)
|
|
else:
|
|
# print('[ignoring exits direction line]')
|
|
pass
|
|
else:
|
|
data['ignoring_exits'] = False
|
|
if data['last_was_dir'] == 1:
|
|
# reset count
|
|
if data['last_count'] > 0:
|
|
this_square = [data['last_count'], data['last_direction'], data['room_id'], int(math.floor(data['room_value']))]
|
|
data['enemies_by_square'].append(this_square)
|
|
data['nothing'] = False
|
|
data['next_color'] = ''
|
|
data['room_id'] = data['room_id'] + 1
|
|
data['room_value'] = 0
|
|
data['last_direction'] = ''
|
|
data['last_enemy_line'] = ''
|
|
data['last_count'] = 0
|
|
data['last_was_dir'] = 0
|
|
|
|
data['next_color'] = ''
|
|
add_player_value = False
|
|
|
|
# Special GMCP MDT colour codes
|
|
if entry[0:6] == 'u001b[':
|
|
# u001b[38;5;37mRuhsbaaru001b[39;49mu001b[0m
|
|
here = entry.index('m')
|
|
data['next_color'] = entry[7:here]
|
|
# entry = entry[here + 1:-20]
|
|
# entry = entry.replace('u001b', '')
|
|
entry = entry.replace('u001b', '\033')
|
|
|
|
# Might be a second colour code for PK
|
|
if entry[0:6] == 'u001b[':
|
|
here = entry.index('m')
|
|
data['next_color'] = entry[7:here]
|
|
entry = entry[here + 1:-20]
|
|
add_player_value = True
|
|
|
|
this_value = self.default_npc_value
|
|
|
|
for custom_match in self.custom_matches:
|
|
if custom_match[3]:
|
|
# This is a regex match
|
|
rexp = re.compile(custom_match[0])
|
|
if rexp.match(entry):
|
|
if custom_match[1] and custom_match[1] in self.colour_map:
|
|
entry = '{}{}{}'.format(
|
|
self.colour_map[custom_match[1]],
|
|
entry,
|
|
self.colour_map['reset']
|
|
)
|
|
this_value = custom_match[2]
|
|
else:
|
|
# This is a regular string match
|
|
if custom_match[0] in entry:
|
|
if custom_match[1] and custom_match[1] in self.colour_map:
|
|
entry = '{}{}{}'.format(
|
|
self.colour_map[custom_match[1]],
|
|
entry,
|
|
self.colour_map['reset']
|
|
)
|
|
|
|
this_value = custom_match[2]
|
|
|
|
if add_player_value == True:
|
|
this_value = this_value + self.bonus_player_value
|
|
|
|
data['room_value'] = data['room_value'] + (this_value * quantity)
|
|
|
|
if quantity > 1:
|
|
entry = '{} {}'.format(quantity, entry)
|
|
data['entity_table'].append([data['room_id'], entry, data['next_color']])
|
|
|
|
data['last_count'] = data['last_count'] + quantity
|
|
if data['last_enemy_line'] != '':
|
|
data['last_enemy_line'] = '{}, '.format(data['last_enemy_line'])
|
|
data['last_enemy_line'] = '{}{}'.format(data['last_enemy_line'], entry)
|
|
|
|
if data['nothing']:
|
|
self.return_value.append('Nothing seen, try elsewhere!')
|
|
else:
|
|
done_here = False
|
|
rooms_ignored = 0
|
|
|
|
data['enemies_by_square'].sort(key=lambda square: square[3])
|
|
|
|
# Grab shortest
|
|
for square in data['enemies_by_square']:
|
|
# Only show if this room meets the minimum value
|
|
if square[3] >= self.minimum_room_value and len(square[1]) > data['longest_direction']:
|
|
data['longest_direction'] = len(square[1])
|
|
|
|
for square in data['enemies_by_square']:
|
|
# Only show if this room meets the minimum value
|
|
if square[3] >= self.minimum_room_value:
|
|
done_here = False
|
|
|
|
# add colour to points output
|
|
square[3] = '{}{}{}'.format(self.colour_map['cyan'], square[3], self.colour_map['reset'])
|
|
fstring = '{{:<{}}} [{{}}] '.format(data['longest_direction'])
|
|
output = fstring.format(square[1], square[3])
|
|
for entity in data['entity_table']:
|
|
if entity[0] == square[2]:
|
|
if done_here:
|
|
output = '{}, '.format(output)
|
|
output = '{}{}'.format(output, entity[1])
|
|
done_here = True
|
|
if square[0] < 2:
|
|
output = '{} [{} thing]'.format(output, square[0])
|
|
else:
|
|
output = '{} [{} things]'.format(output, square[0])
|
|
self.return_value.append(output)
|
|
else:
|
|
rooms_ignored = rooms_ignored + 1
|
|
|
|
square = None
|
|
|
|
for entity in data['entity_table']:
|
|
entity = None
|
|
|
|
if rooms_ignored > 0 and self.show_hidden_room_count:
|
|
output = '({} rooms below your value limit of {})'.format(rooms_ignored, self.minimum_room_value)
|
|
self.return_value.append(output)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
if len(sys.argv) < 2:
|
|
print('[error] No input provided.')
|
|
sys.exit()
|
|
|
|
argument, mdt_line = sys.argv.pop(1), None
|
|
|
|
# Is this a file passed to us?
|
|
if os.path.exists(argument):
|
|
with open(argument, 'r') as f:
|
|
mdt_line = f.readline()
|
|
|
|
else:
|
|
mdt_line = argument
|
|
|
|
mdt = MapDoorText()
|
|
mdt.parse_mdt(mdt_line)
|
|
|
|
for line in mdt.return_value:
|
|
print(line)
|