1+ # Character Generator
2+
3+ # imports
4+ import random as r
5+ import time
6+
7+ # definitions
8+ REDON = "\033 [31m" # Red text.
9+ GREENON = "\033 [32m" # Green text.
10+ COLOUROFF = "\033 [0m" #Reset special formatting (such as colour).
11+
12+ CLEAR = '\x1b [2K'
13+ RESET = '\033 [2J'
14+
15+ ## function to get an integer with error checking
16+ def get_int (input_prompt , min_val = int (1 ), max_val = int (100 )):
17+ return_value = int (0 )
18+ int_val = int (- 1 )
19+
20+ while not ((int_val >= min_val and int_val <= max_val )) and not int_val == 0 :
21+ try :
22+ get_val = input (input_prompt + f" (Min: { str (min_val )} Max: { str (max_val )} Exit: 0) : " )
23+ int_val = int (get_val )
24+
25+ ## exit if select 0
26+ if int_val == 0 :
27+ break
28+
29+ return_value = int_val
30+ except :
31+ print ( f"Invalid '{ input_prompt } ' value entered '" + get_val + "'" )
32+
33+ return return_value
34+
35+ def show_stats (s_class = "" ):
36+
37+ print (RESET )
38+
39+ print ( 'Your abilities and the requirements for each class: ' )
40+ print ( "-" * 80 )
41+ print ( f"| { 'Class' :12} " , end = "|" )
42+ for key in a_attributes :
43+ print ( f'{ a_attributes [key ]["Name" ]:^12} ' , end = "|" )
44+ print ("" )
45+ print ( "-" * 80 )
46+ # print initial scores
47+ if s_class != "" :
48+ print ( f"| { 'Initial' :12} " , end = "|" )
49+ for key in a_attributes :
50+ print ( f' { a_attributes [key ]["Initial" ]:>2} ' , end = "|" )
51+ print ("" )
52+
53+ # print Current scores
54+ print ( f"| { 'Your score' :12} " , end = "|" )
55+ for key in a_attributes :
56+ if s_class != "" :
57+ if required_skill_points (s_class , key ) == 0 :
58+ print ( GREENON , end = "" )
59+ print ( f' { float (a_attributes [key ]["Current" ]):^6.1f} ' + COLOUROFF , end = "|" )
60+ print ("" )
61+ print ( "-" * 80 )
62+ # if a class is chosen then output the required stats.
63+ if s_class != "" :
64+ print ( f"| { 'Required' :12} " , end = "|" )
65+ for key in a_attributes :
66+ rsp = int (required_skill_points (s_class ,key ))
67+ if rsp > 0 :
68+ print ( f' { rsp :>2} ' , end = "|" )
69+ else :
70+ print ( f' ' , end = "|" )
71+ print ("" )
72+
73+ print ( f"| { 'Free' :12} " , end = "|" )
74+ for key in a_attributes :
75+ fsp = int (free_skill_points (s_class ,key ))
76+ if fsp > 0 :
77+ print ( f' { fsp :>2} ' , end = "|" )
78+ else :
79+ print ( f' ' , end = "|" )
80+
81+ print ("" )
82+
83+ print ( "-" * 80 )
84+
85+ for key in a_characters :
86+ if s_class == "" or s_class == key :
87+ print (a_posit [key ], end = "" )
88+ if check_stats (key )== True :
89+ print ( GREENON , end = "" )
90+ print ( f' { key :12} ' + COLOUROFF , end = "|" )
91+ for this_key in a_characters [key ]:
92+ if a_characters [key ][this_key ]> a_attributes [this_key ]["Current" ]:
93+ print (REDON , end = "" )
94+ else :
95+ print (GREENON , end = "" )
96+ print ( f' { a_characters [key ][this_key ]:>2} ' + COLOUROFF , end = "|" )
97+ print ("" )
98+
99+ print ( "-" * 80 )
100+
101+ def randomise_attributes ():
102+ global a_attributes
103+ for key in a_attributes :
104+ a_attributes [key ]["Initial" ]= r .randrange (a_attributes [key ]["Min" ], a_attributes [key ]["Max" ]+ 1 )
105+ a_attributes [key ]["Current" ]= a_attributes [key ]["Initial" ]
106+
107+ def check_stats (s_class ):
108+ f_valid = True
109+ for s_stat in a_characters [s_class ]:
110+ if a_characters [s_class ][s_stat ]> a_attributes [s_stat ]["Current" ]:
111+ f_valid = False
112+ return f_valid
113+
114+ # list the categories with free points
115+ def list_excess_categories (s_class ):
116+ l_available = []
117+ for key in a_characters [s_class ]:
118+ if free_skill_points (s_class , key ) > 0 :
119+ l_available .append (key )
120+ return l_available
121+
122+ # list the categories requiring points
123+ def list_reqd_categories (s_class ):
124+ l_reqd = []
125+ for key in a_characters [s_class ]:
126+ if required_skill_points (s_class ,key ) > 0 :
127+ l_reqd .append (key )
128+ return l_reqd
129+
130+ # look how many points are available across all skills.
131+ def free_points (s_class ):
132+ i_points = 0
133+ for key in a_characters [s_class ]:
134+ i_points += free_skill_points (s_class ,key )
135+ return i_points
136+
137+ # Look how many points are available in a given skill
138+ def free_skill_points (s_class , s_skill ):
139+ i_points = 0
140+ i_min_allowed = a_attributes [s_skill ]["Min" ]
141+ i_min_test = a_characters [s_class ][s_skill ]
142+ # check it maintains the minimum required points.
143+ if i_min_test < i_min_allowed :
144+ i_min_test = i_min_allowed
145+ ## see what's free
146+ if (a_attributes [s_skill ]["Current" ])> i_min_test :
147+ i_points = (a_attributes [s_skill ]["Current" ])- i_min_test
148+ return i_points
149+
150+ def required_points (s_class ):
151+ i_points = 0
152+ for key in a_characters [s_class ]:
153+ i_points += required_skill_points (s_class , key )
154+ return i_points
155+
156+ def required_skill_points (s_class , s_skill ):
157+ i_points = 0
158+ if a_attributes [s_skill ]["Current" ]< a_characters [s_class ][s_skill ]:
159+ i_points = a_characters [s_class ][s_skill ]- a_attributes [s_skill ]["Current" ]
160+ return i_points
161+
162+ def move_points (s_class ):
163+ l_skills = list_excess_categories (s_class )
164+ s_source = "X"
165+ while not s_source in l_skills and s_source != "Q" :
166+ s_source = input (f'Please enter the source ability ({ "," .join (l_skills )} ) [Q to Exit]:' ).upper ()
167+
168+ if s_source != "Q" :
169+ i_free_p = free_skill_points (s_class , s_source )
170+
171+ if i_free_p == 0 :
172+ print ("You don't have any free points on that skill" )
173+ else :
174+ l_skills = list_reqd_categories (s_class )
175+ s_target = "X"
176+ while not s_target in l_skills :
177+ s_target = input (f'Please enter the target ability ({ "," .join (l_skills )} ) :' ).upper ()
178+
179+ i_req_p = required_skill_points (s_class , s_target )
180+
181+ print (f"You have { i_free_p } available ({ i_free_p / 2 } ) and require { i_req_p } . (2 free points = 1 required points)." )
182+ i_move = - 1
183+ while (i_move < 0 or i_move > i_free_p ) :
184+ i_move = get_int ("How many points do you want to move?" ,1 ,i_free_p )
185+
186+ a_attributes [s_source ]["Current" ] -= i_move
187+ a_attributes [s_target ]["Current" ] += (i_move / 2 )
188+ return "1"
189+ else :
190+ return "Q"
191+
192+
193+
194+
195+ a_attributes = {"S" : {"Name" : "Strength" , "Min" : 3 , "Max" : 18 , "Initial" : 0 , "Current" : 0 },
196+ "I" : {"Name" : "Intelligence" , "Min" : 3 , "Max" : 18 , "Initial" : 0 , "Current" : 0 },
197+ "W" : {"Name" : "Wisdom" ,"Min" : 3 , "Max" : 18 , "Initial" : 0 , "Current" : 0 },
198+ "D" : {"Name" : "Dexterity" ,"Min" : 3 , "Max" : 18 , "Initial" : 0 , "Current" : 0 },
199+ "C" : {"Name" : "Constitution" ,"Min" : 3 , "Max" : 18 , "Initial" : 0 , "Current" : 0 }}
200+
201+ a_characters = { "Warrior" : {"S" : 15 , "I" : 0 , "W" : 0 , "D" : 12 , "C" : 10 },
202+ "Wizard" : {"S" : 0 , "I" : 15 , "W" : 10 , "D" : 10 , "C" : 0 },
203+ "Thief" : {"S" : 10 , "I" : 9 , "W" : 0 , "D" : 15 , "C" : 0 },
204+ "Necromancer" : {"S" : 10 , "I" : 10 , "W" : 15 , "D" : 0 , "C" : 0 }}
205+
206+ a_posit = {
207+ "Warrior" : "1" ,
208+ "1" : "Warrior" ,
209+ "Wizard" : "2" ,
210+ "2" : "Wizard" ,
211+ "Thief" : "3" ,
212+ "3" : "Thief" ,
213+ "Necromancer" : "4" ,
214+ "4" : "Necromancer"
215+ }
216+
217+ i_target = 0
218+
219+ randomise_attributes ()
220+ show_stats ()
221+
222+
223+ i_target = get_int ("Please select your desired class :" ,1 ,4 )
224+
225+ if i_target > 0 :
226+ s_target = a_posit [str (i_target )]
227+ req_p = required_points (s_target )
228+ free_p = free_points (s_target )
229+
230+ show_stats (s_target )
231+ print ( f"You require { req_p } extra points to become a { s_target } ." )
232+
233+ if int (req_p * 2 )> int (free_p ):
234+ print ( f"You only have { free_p } free points, (and you need { req_p * 2 } ). \n Sadly that's not enough free points to become an { s_target } . \n Please try again." )
235+ else :
236+ print ( f"You have { free_p } points available and you only need { req_p * 2 } free points!" )
237+
238+ while check_stats (s_target )== False :
239+ ret_val = move_points (s_target )
240+ if ret_val == "Q" :
241+ break
242+ show_stats (s_target )
243+
244+ if check_stats (s_target )== True :
245+ print ( f"Congratulations you're now a { s_target } !" )
246+
247+ print ( f'Thanks for playing, please come back soon.' )
248+
0 commit comments