vais/character.py
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# character.py
import os
import random
## TODO - once
fldr = os.getcwd() + os.sep + 'data'
#print('character.py: fldr = ', fldr)
class RefFile(object):
"""
Class to handle a CSV type reference file for
stats, races, etc - generally has a header and
any column can have multiple values if enclosed
by [] where values parsed by |
"""
def __init__(self, fldr, fname):
self.name = fname[0:-4]
self.fname = fldr + os.sep + fname
self.hdrs = []
self.dat = self.parse_to_dict() # read CSV file and parse into dictionary
def __str__(self):
res = ' === ' + self.name + ' Reference File ====\n'
res += str(len(self.dat)) + ' lines = '
for row in self.dat:
if 'name' in self.hdrs:
res += row['name'] + ','
#for colnum, col in enumerate(row):
# print(str(rownum), str(colnum), col)
return res
def parse_to_dict(self):
"""
parse raw CSV into dictionary
"""
lst = []
with open(self.fname, 'r') as f:
hdr = f.readline()
self.hdrs = hdr.split(',')
#print("self.hdrs = ", self.hdrs)
for line in f:
cols = line.split(',')
if len(cols) == len(self.hdrs):
#print(cols)
d = {}
for ndx, col_header in enumerate(self.hdrs):
#d[self.hdrs[ndx].strip('\n').strip()] = cols[ndx].strip('\n').strip()
d[col_header.strip('\n').strip()] = cols[ndx].strip('\n').strip()
lst.append(d)
else:
print("Error parsing " + self.fname + " line : " + line)
return lst
def get_random_choice(self):
"""
returns a random name from the class
"""
i = random.randint(0,len(self.dat)-1)
return self.dat[i]['name']
class CharacterCollection(object):
"""
Class to handle all the character traits
"""
def __init__(self, fldr):
"""
loads all the ref_*.csv files relating
to character traits
"""
self.ref_folder = fldr
#print('loading data files')
self.races = RefFile(fldr, 'ref_races.csv')
self.classes = RefFile(fldr, 'ref_classes.csv')
self.stats = RefFile(fldr, 'ref_stats.csv')
self.skills = RefFile(fldr, 'ref_skills.csv')
self.stories = RefFile(fldr, 'ref_stories.csv')
self.inventory = RefFile(fldr, 'ref_objects.csv')
def __str__(self):
res = '=== DUMP OF ALL CHARACTER TRAITS ===\n'
res += 'Classes:\n' + str(self.classes)
res += 'Races:\n' + str(self.races)
res += 'STATS:\n' + str(self.stats)
res += '\nStory:\n' + str(self.stories)
res += 'SKILLS:\n' + str(self.skills)
res += 'INVENTORY:\n' + str(self.inventory)
return res
def generate_random_character(self):
"""
uses the traits to create a random, but plausible
character. Sample below:
CHARACTER = Amador
Race = Halfling
Class = Priest
STATS = CON = 12, STA = 4, INT = 10, STR = 0, AGI = 5,
Story = A brave person looking to fight evil in the dark forests of Divitie
SKILLS = Remove Curse, Frost Ball, Frost Bolt
INVENTORY = 5 gold, stick, leaf, sword
"""
name = self.create_name()
ch_class = self.classes.get_random_choice()
race = self.races.get_random_choice()
stats = self.random_stats(self.stats.dat, race, ch_class)
skills = []
story = self.stories.get_random_choice()
inventory = [str(random.randint(21,29)) + ' gold']
# pick random stuff here
for _ in range(3):
inventory.append(self.inventory.get_random_choice())
for _ in range(3):
skills.append(self.skills.get_random_choice())
return Character(name, race, ch_class, stats, skills, story, inventory)
def random_stats(self, all_stats, race, ch_class):
"""
create random stats based on the characters class and race
This looks up the tables from CharacterCollection to get
base stats and applies a close random fit
"""
# create blank list of stats to be generated
stats = []
res = {}
for s in all_stats:
stats.append(s['stat'])
res[s['stat']] = 0
cur_stat = 0
for stat in stats:
for ndx, i in enumerate(self.classes.dat):
if i['name'] == ch_class:
cur_stat = int(i[stat]) # use stats for this class as baseline
for ndx, i in enumerate(self.races.dat):
if i['name'] == race:
cur_stat += int(i[stat]) # use stats for this race to modify base stats
#print(stat, cur_stat)
if cur_stat < 1:
cur_stat = 1
elif cur_stat > 10:
if stat not in ('Health', 'max_health'): # dont trim down health
cur_stat = 10
res[stat] = cur_stat
return res
def create_name(self):
a = random.choice(['Vol','Ama','Zan','Fea','Cra','Por','Tra','Are','Rek','Wol','Zat','Pli'])
b = random.choice(['mar','dor','mor','dar','dom','kaj','sij','lim','gri','put','eat','rey'])
return a + b
class Character(object):
"""
character class
"""
def __init__(self, name, race, ch_class, stats, skills, story, inventory):
"""
all params except name is a list
"""
self.name = name
self.race = race
self.ch_class = ch_class
self.stats = stats
self.skills = skills
self.story = story
self.inventory = inventory
def __str__(self):
res = 'CHARACTER = ' + self.name + '\n'
res += 'Race = ' + self.race + '\n'
res += 'Class = ' + self.ch_class + '\n'
res += 'STATS = '
for k,v in self.stats.items():
res += k + ':' + str(v) + ' '
res += '\nStory = ' + self.story
res += '\nSKILLS = ' + ', '.join([s for s in self.skills])
res += '\nINVENTORY = ' + ', '.join([s for s in self.inventory])
return res
def load_from_file(self, fname):
"""
OVERWRITES the current character object from stats in file
"""
with open(fname, 'r') as f:
for line in f:
k,v = line.split(' = ')
self._parse_char_line_to_self(k,v)
def _parse_char_line_to_self(self, k,v):
"""
takes a line from a saved file split into key and values
and updates the appropriate self parameters of character.
"""
k = k.strip(' ').strip('\n')
v = v.strip(' ').strip('\n')
# print('_parse_char_line_to_self(self, k,v): ' , k, v)
if k == 'CHARACTER':
self.name = v
elif k == 'Race':
self.race = v
elif k == 'Class':
self.ch_class = v
elif k == 'STATS':
self.stats = self._extract_stats_from_line(v)
elif k == 'Story':
self.story = v.strip(' ').strip('\n')
elif k == 'SKILLS':
self.skills = v.split(', ')
elif k == 'INVENTORY':
self.inventory = v.split(', ')
def _extract_stats_from_line(self, txt, stats_delim=' ', val_delim=':'):
"""
extracts the stats from a line of text to the class params
STR:7 AGI:9 STA:5 INT:5 Health:21 CON:8 max_health:21
"""
result = {}
stats_txt = txt.split(stats_delim)
for s in stats_txt:
#print('s = ', s)
if s.strip(' ').strip('\n') != '':
k,v = s.split(val_delim)
result[k.strip(' ')] = v.strip(' ').strip('\n')
return result
def save_to_file(self, fname):
"""
saves a characters data to file
"""
with open(fname, 'w') as f:
f.write(str(self))
def copy(self):
"""
make an identical copy of the character
"""
return Character(self.name, self.race,self.ch_class, self.stats, self.skills, self.story, self.inventory)
############################
# Utility functions
def read_file(fname):
"""
read a CSV file (ref_classes.csv) and return the
list of names
"""
print("NO - dont use this function read_file(fname):")
exit(1)
lst = []
with open(fname, 'r') as f:
#hdr = f.readline()
for line in f:
lst.append(line.strip('\n'))
return lst
def read_file_1st_col_only(fname):
"""
read a CSV file (ref_classes.csv) and return the
list of names
"""
lst = []
with open(fname, 'r') as f:
_ = f.readline() # read the header and ignore it
for line in f:
lst.append(line.split(',')[0])
return lst