def get_InventorySlot( d): # check if an item is in the inventory (and get slot) # Accepts: d MUST be an obj_id # CHECK (and return) object's inventory-slot if 'inventory-slot' in gD.gameDB['objectsDB'][d]: inv_slot = gD.gameDB['objectsDB'][d]['inventory-slot'] # check if object is IN inv if d in gD.PLAYERINV[inv_slot]: return inv_slot else: return False else: # check if item can take GET, PUT or USE commands if any(k in gD.gameDB['objectsDB'][d] for k in ('getCmds-OK', 'putCmds-OK', 'useCmds-OK')): de.bug(5, "ERROR, missing inventory slot on ", gD.gameDB['objectsDB'][d], "in gameData file") else: de.bug(5, "this object ", gD.gameDB['objectsDB'][d]['name'], "cannot exist in the inventory") return False
def uiActions(cmd, obj, jun, via, inps, uiData): # generic UI cmd handler # Resetting values my_cmd = None # check for singleton object with no command (show help if it is) if cmd != None: # consolidate cmd reference word my_cmd = gD.INPUT_VARS['THIS_CMD']['user-input'] # render the appropriate user feedback message for the cmd if my_cmd in gD.gameDB['uiCmds']['playerCmds']: if my_cmd == "inv" or my_cmd == "inventory": renderers.render_charInventory() elif my_cmd in gD.gameDB['uiCmds']['generalCmds']: # Just print out the message for the UI command ctrls.printText(uiData[my_cmd], my_cmd) else: de.bug("Error (doCommand): command '", my_cmd, "' not found in uiCmds")
def render_objectActions(d, cmd, t, ob=None): de.bug(3, "data for interaction is", d) if t in ("get-take", "put-leave", "ok", "unlocked"): print(ss.inputFeedbackPre, "You", cmd, "the", d['name'].lower()) elif t == "has-req-obj": print(ss.inputFeedbackPre, "You", cmd, "the", d['name'].lower(), "with the", gD.gameDB['objectsDB'][ob]['name'].lower()) elif t == "use": # singleton "use" command: use on what? print(ss.inputFeedbackPre, "Use the", d['name'].lower(), "to do what?") elif t == "locked_by": # tell player what req obj is print( ss.inputFeedbackPre, "The", d['name'].lower(), "is locked by the", gD.gameDB['objectsDB'][d['permissions'] ['locked_by']]['name'].lower()) elif t == "unlocked_by": # tell player what req obj is print( ss.inputFeedbackPre, "The", d['name'].lower(), "can be locked using the", gD.gameDB['objectsDB'][ d['permissions']['unlocked_by']]['name'].lower()) elif t == "illegal": # user tried to do an illegal action on an object print(ss.inputFeedbackPre, "You can\'t", cmd, "the", d['name'].lower())
def get_ObjectContents(obj_id): # get contents of an objects. Returns [ids, descs, type-of-containment] obj = gD.gameDB['objectsDB'][obj_id] # check this obj actually HAS children if 'contains' in obj['state']: # required access check if get_ObjectPermissions(obj) != 'locked': # reset type t = False # make array of contained obj refs cont_objs_ids = [] cont_objs = [] # Determine if contained objects are "in" or "via" their container # makes a "mixed bag" of descriptions if there are multiple types # type inherits from the last item in the list # could be changed to make it smarter if we need that functionality for o in obj['state']['contains']: cont_objs_ids.append(o) if o[0:2] == "ob": cont_objs.append(gD.gameDB['objectsDB'][o]['name']) t = "in" elif o[0] == "m": for i, j in gD.gameDB['moveCommandsDB'][o].items(): cont_objs.append(j['moveDesc']) t = "via" # return a list [ids, obs, t] == ids, descriptions, type return [cont_objs_ids, cont_objs, t] else: de.bug(6, "Cannot access object:", obj_id) return obj_id, False, False else: de.bug(6, "Object:", obj_id, "has no contents") return obj_id, False, False
def update_WorldState(ids, t, c): # change the World State e.g. objects in the world: add, remove etc. de.bug(1, "update World State with", ids, " ", t, "and", c) # == REMOVE OBJECTS ============================== if c == 'remove': if t == False: # sent obj has no contents if ids in gD.locDB[gD.CURRENT_LOC]['locObjects']: gD.locDB[gD.CURRENT_LOC]['locObjects'].remove(ids) else: for ob in ids: if t == "in": if ob in gD.locDB[gD.CURRENT_LOC]['locObjects']: gD.locDB[gD.CURRENT_LOC]['locObjects'].remove(ob) elif t == "via": if ob in gD.LOCDATA['moveCmds']: gD.LOCDATA['moveCmds'].remove(ob) # == ADDING OBJECTS ============================== elif c == 'add': if t == False: # sent obj has no contents if ids not in gD.locDB[gD.CURRENT_LOC]['locObjects']: gD.locDB[gD.CURRENT_LOC]['locObjects'].append(ids) else: for ob in ids: if t == "in": # add contained objects to locdata objects list if ob not in gD.LOCDATA['locObjects']: gD.LOCDATA['locObjects'].append(ob) elif t == "via": if ob not in gD.LOCDATA['moveCmds']: gD.LOCDATA['moveCmds'].append(ob)
def throwError(s, dd): de.bug("we are in throwError() with this data: ", dd) # error types and data truths theTruth = {'uiSpawn': gD.gameDB['uiCmds']} # throw an error of source s if s in theTruth: # expect data d for i, j in theTruth.items(): d = j # but got data dd if d != dd: # show error message plus data mismatch print(ss.errorPre + "Data mismatch") print(ss.errorPre + "Expect data: '", d, "' but received data: '", dd, "'") else: print(ss.errorPre + "No error found...") # error source not recognised else: print(ss.errorPre + "Error source '", s, "' not recognised")
def get_ObjectPermissions(d): # access control to certain objects # Accepts: d = whole object # Returns: # "ok" if no access restrictions on object # "has-req-obj" if player has req_obj to access locked object # "locked_by" or "unlocked_by" if access is denied perm_ok = False # check the state of the object (locked etc) if 'access' in d['state']: if d['state']['access'] == 'locked': perm_type = "locked_by" elif d['state']['access'] == 'unlocked': perm_type = "unlocked_by" if perm_type in d['permissions']: req_obj = d['permissions'][perm_type] # check if player has required object in their inventory de.bug(5, "checking player inventory for", req_obj) if get_InventorySlot(req_obj): perm_ok = True if perm_ok == True: # player has the req obj return "has-req-obj" else: # player does NOT have req obj, just return state return perm_type else: # no restrictions so return "ok" (not True, or it overrides every other condition check!) return "ok"
def cmdDidYouMeanThis(tks, parsed_list): # check with player what input actually was # flatten out parsed_cmds because we don't need it segmented by token pdl = {} for a, b in parsed_list.items(): for c, d in b.items(): pdl[c] = d de.bug(1, "Original parsed_list", parsed_list, "vs flatten pdl list", pdl) # get first 'cmd' in parsed_list of cmds c_lst = [a for a, b in pdl.items()] # handle empty c_lst - which could mean that the input was NONE # i.e. player probably just pressed RETURN if len(c_lst) > 0: # get an integer for every n+-cmd keys in parsed list c_pos = c_lst[0][0] c_pos = int(c_pos) - 1 # grab all junk words to let user know they are unrecognised unknown_junk = '' for i in tks[:c_pos]: unknown_junk += str(i) if tks.index(i) < len(tks[:c_pos]) - 1: unknown_junk += ' ' # remove all (junk word) tokens from inputTokenized list that appear # before the first valid parsed_cmd new_tokens = tks[c_pos:] user_conf = ' '.join(new_tokens) # return sanitised input and setup confirmation request prompt de.bug(1, "3. confirm me this", user_conf) gD.PROMPT = 'reqconf' gD.USERCONF = user_conf gD.UNKNOWN_INPUT = unknown_junk else: # just spawn default PROMPT again de.bug(1, "no input, just respawn default PROMPT") gD.PROMPT = False gD.USERCONF = None gD.UNKNOWN_INPUT = None
import debugger as de import gameData as gD import settings as ss import controllers import input_parsing as parseInp import command_handling as doCmd import errorHandler # == INITIALISE GAME DATA == #################################### # initialise GLOBALS gD.init() de.bug(1, "allInputRefs", gD.allInputRefs) # == RENDER FIRST/DEFAULT LOCATION == ############################# # render first/default location loc = gD.DEFAULTLOC controllers.changeLoc(loc) ################################################################### # GAME STATE PLAYING LOOP ################################################################### WIN = False
def cmdLengthChecker(cmd_mtch, parsed_cmds, tkns): # verify that the input contains the right number of # cmd words to complete a valid command phrase if type(cmd_mtch) == list: # If the object to be checked is a list (not a set{}) # then it is a singleton and we only need to find the commands # in the list that only have ONE word and then check if the # tokenised single word player input and any of those commands # match exactly de.bug(1, "singleton command, checking for length=1 valid commands in", cmd_mtch) for rf in cmd_mtch: rf_elems = rf.split("-") # find the appropriate cmd_list in allInputRefs for a, b in gD.allInputRefs.items(): if rf_elems[0] == a: cmd_wrds = b[int(rf_elems[1])] # count the number of words in the command cmd_wrds_len = len(tokenizeInput(cmd_wrds)) # we are only interested in one word commands if cmd_wrds_len == 1: # does the player input match any single command word? for t in tkns: if t == cmd_wrds: de.bug(1, "valid command phrase matched:", t, "as", cmd_wrds, "returning ref", rf) return rf return False else: # if cmd_match is not a list then check each item in the set # to see if they share a multi-word command de.bug(1, "Checking command length") for cmd_item in cmd_mtch: # get the actual command-tokened words cmd_elems = cmd_item.split("-") # handle each of the types of command if (cmd_elems[0] == 'o') or (cmd_elems[0] == 'm'): cmd_lst = gD.allInputRefs[cmd_elems[0]] else: cmd_lst = gD.gameDB['actionCmds'][cmd_elems[0]] if cmd_elems[0] == 'o': suf = "-obj" elif cmd_elems[0] == 'm': suf = "-mov" elif cmd_elems[0] == 'conJuncts': suf = "-jun" else: suf = "-cmd" # count the number of words cmd_wrds = cmd_lst[int(cmd_elems[1])] cmd_len = len(tokenizeInput(cmd_wrds)) de.bug(1, "cmd wrds '", cmd_wrds, "' cmd len", cmd_len) # require this many sequential parsed_cmds.keys() matches q = 1 cmd_valid = True while q <= cmd_len: # increment through each "n-suffix" myKey = str(q) + suf de.bug(1, "check this key", myKey) #check we haven't just run out of cmds if myKey in parsed_cmds.keys(): if cmd_item not in parsed_cmds[myKey]: de.bug(1, "missing in", myKey) cmd_valid = False else: # failed to match full length, invalid command cmd_valid = False q = q + 1 # if yes, this is a valid command if cmd_valid == True: de.bug(1, "valid command phrase matched:", cmd_wrds, "as", cmd_item) return cmd_item # no need to check further cmd_items break
def parseInput(skip=False): # extract objects from tokenized input # Reset duplicates prompt builder before next input parsing run if gD.PROMPT == 'duplicates': gD.PROMPT = False tkns = gD.TOKENS # 'skip' = Setup for "reSTART" of parseInput see: re_runWrdChecker(d) # to avoid over-writing existing parsed_cmds etc. on 2nd run if skip == False: parsed_cmds = {} matched_cmds = None type_track = [] i = 0 # cmd-type index dictKey # for each word in the input for w in tkns: # use each WORD token to create GROUPS of parsed cmd matches parsed_cmds[w] = {} i = i + 1 # check against every type of input and parse # out useful references for handling back in gameExec for j, k in gD.allInputRefs.items(): # used to be legalinputs.items() # for each cmd in each cmd group for l in k: # is the word in the cmd group if re.search(w, l): # complex bit: if the type of command changes # between m, o, and c for the SAME word in tkns # artificially bump i to avoid duplicate index numbers type_track.append(j) if len(type_track) > 1: # match back for 'm' if type_track[len(type_track)-1] == 'm': if type_track[len(type_track)-2] != 'm': i = i + 1 # match back for 'o' if type_track[len(type_track)-1] == 'o': if type_track[len(type_track)-2] != 'o': i = i + 1 # match back for 'c' if type_track[len(type_track)-1] == 'c': if type_track[len(type_track)-2] != 'c': i = i + 1 # match back for neither 'm' or 'o' or 'c' if type_track[len(type_track)-1] != 'o': if type_track[len(type_track)-1] != 'm': if type_track[len(type_track)-1] != 'c': if type_track[len(type_track)-2] == 'o' or type_track[len(type_track)-2] == 'm' or type_track[len(type_track)-2] == 'c': i = i + 1 # handle each of the command types # because move and object don't have # explicit labels for j, unlike cmds if j == "m": c = "mov" elif j == "o": c = "obj" elif j == "conJuncts": c = "jun" else: c = "cmd" # combine cmdgrp name - match index as label c = str(i) + '-' + c # combine j and the index of k as valid # matching cmds ind = j + "-" + str(k.index(l)) # build list of potential cmd matches # called PARSED_CMDS if c in parsed_cmds[w].keys(): parsed_cmds[w][c].append(ind) else: parsed_cmds[w][c] = [ind] else: parsed_cmds = skip de.bug(1, "Parsed input: tokens", tkns, "and cmds", parsed_cmds) ## Check output from above: "parsed_cmds" using wrdChecker and RETURN if len(parsed_cmds) > 0: matched_cmds = wrdChecker(tkns, parsed_cmds) if matched_cmds == False: de.bug(1, "USERCONF", gD.USERCONF) de.bug(1, "PROMPT", gD.PROMPT) de.bug(1, "UNKNOWN JUNK", gD.UNKNOWN_INPUT) matched_cmds = [None, None, None, None] elif matched_cmds != None: de.bug(1, "successfully matched these commands", matched_cmds) else: matched_cmds = [None, None, None, None] de.bug(1, "there were no valid commands matched in the input") # RETURN all of the things!! return matched_cmds
def wrdChecker(tkns, parsed_cmds): # If the first dict group in parsed_cmds has nothing in it # the first token did not match and so is probably junk # check with the player what they really wanted to do first # and automatically resend commands if correct to do so junk_wrds = False if len(parsed_cmds[tkns[0]]) < 1: de.bug(1, "First token", "'"+tkns[0]+"'", "not a valid input. Check for junk input.") junk_wrds = True # handle finding junk words (above) or second pass as a "reqconf" if junk_wrds == True or gD.PROMPT == 'reqconf': if gD.PROMPT == False: cmdDidYouMeanThis(tkns, parsed_cmds) # return matched_cmds as False to parseInput() return False elif gD.PROMPT == 'reqconf': # require Y/N confirmation if tkns[0].lower() == "y": # if y or Y entered gD.PROMPT = 'autoresend' else: # if anything else treat it as a NO (bcoz 'n' = 'north') gD.USERCONF = None gD.PROMPT = False gD.UNKNOWN_INPUT = None # return matched_cmds as False to parseInput() return False else: # check parsed_cmds as normal # use tkns as a reference, because parsed_cmds dict is unordered # check if each parsed_cmds[tkns] shares any commands with another tkn_cmd_matches = {} # complete list of input tokens & matched cmds known_cmds = [] parsed_final = [] # to send back to gameExec # skip this if we are dealing with single word input if len(tkns) > 1: # make a working copy, so we can amend it later working_tokens = tkns i = 0 # step through tkns as a guide list for current_token in working_tokens: # Deal with tokens that have MULTIPLE matches in gameData first if len(parsed_cmds[current_token]) > 1: de.bug(1, "Multiple possible gameData matches found for", parsed_cmds[current_token]) # if existing tkn_cmd_matches contain get, put, int or useCmds del_keys = [] for v in tkn_cmd_matches.values(): if ('getCmds' in v) or ('putCmds' in v) or ('intCmds' in v) or ('useCmds' in v): de.bug(1, "OBJECT command already found, forcing object discovery") for a, b in parsed_cmds[current_token].items(): de.bug(1, "Find 'o-' in", b) for c in b: if 'o-' not in c: del_keys.append(a) de.bug(1, "del_keys", del_keys) for d in del_keys: del parsed_cmds[current_token][d] de.bug(1, "Cleaned PARSED_CMDS", parsed_cmds[current_token]) parsed_final = re_runWrdChecker(parsed_cmds) de.bug(1, "PARSED_FINAL (after reSTART)", parsed_final) return parsed_final # otherwise return a "duplicate objects found" response else: # THIS IS INCOMPLETE, but it is hard to create a situation # where this specific disambiguation would be needed de.bug(1, "Which of these did you mean for", current_token, "?") # Otherwise check for MULTI word commands in the input else: de.bug(1, "Current token is", working_tokens[i]) # if we are not at the last item in parsed_cmds if len(working_tokens) > working_tokens.index(current_token)+1: # reset some vars shared_cmds = [] next_token = working_tokens[i+1] # compare the commands for this parsed_cmds(key) # with the "next token" according to working_tokens for a, b in parsed_cmds[current_token].items(): for cm in b: shared_cmds.append(cm) for a, b in parsed_cmds[next_token].items(): for cm in b: shared_cmds.append(cm) de.bug(1, "ALL FOUND cmds", shared_cmds) # check shared_cmds for duplicates dupe_found = False dupe_cmds = [] for c in shared_cmds: if shared_cmds.count(c) > 1: dupe_cmds.append(c) dupe_found = True # if so combine current + next tokens in our working_tokens list if dupe_found == True: de.bug(1, "Duplicates found", dupe_cmds) # update working_token list so the index is still accurate working_tokens[i] = current_token +" "+ next_token del working_tokens[i+1] de.bug(1, "AMENDED working_tokens", working_tokens) # check if the combined tokens match a command # and if so append to our final dict of matches if len(dupe_cmds) > 2: de.bug(1, "TOO MANY duplicate commands found for", dupe_cmds) cmd_elms = dupe_cmds[0].split("-") if working_tokens[i] == gD.allInputRefs[cmd_elms[0]][int(cmd_elms[1])]: de.bug(1, "this command is", dupe_cmds[0]) tkn_cmd_matches[working_tokens[i]] = dupe_cmds[0] else: de.bug(1, "We have a weird problem with this input", working_tokens[i], "it doesn't resolve to one single command in gameData") # If no dupes, this is a SINGLE word command else: # check it's not a malformed multi-word de.bug(1, "single word command detected") for x, y in parsed_cmds[current_token].items(): valid = cmdLengthChecker(y, parsed_cmds[current_token].items(), tkns) if valid != False: de.bug(1, "This came back as VALID:", valid) tkn_cmd_matches[working_tokens[i]] = valid else: de.bug("that wasn't a fully formed command, ignoring it") de.bug(1, "MATCHED COMMANDS so far (single word)", tkn_cmd_matches) # bump the i cursor and keep going (because we combined two items # we just need to check the next item, as normal) i = i + 1 else: de.bug(1, "Got to final word in working_tokens") # if we know we are matching a single word then # it can match exactly and it will be correct for a, b in parsed_cmds[current_token].items(): for cc in b: cmd_elms = cc.split("-") if working_tokens[i] == gD.allInputRefs[cmd_elms[0]][int(cmd_elms[1])]: de.bug(1, "this command is", cc) tkn_cmd_matches[working_tokens[i]] = cc de.bug(1, "MATCHED COMMANDS so far (final word)", tkn_cmd_matches) break else: de.bug(1, "We have a weird problem with this input", working_tokens[i], "it doesn't resolve to one single command in gameData") # This is a SINGLE word input else: # check it's not a malformed multi-word de.bug(1, "single word input detected") # NOTE: If an input has multiple possible entries # in the gameData it will send off the cmdLengthChecker for # each one in the for loop here below. valid_singles = [] for x, y in parsed_cmds[tkns[0]].items(): valid = cmdLengthChecker(y, parsed_cmds[tkns[0]].items(), tkns) if valid != False: de.bug(1, "This came back as VALID:", valid) # So... We need to collect all possible matches valid_singles.append(valid) else: de.bug("that wasn't a fully formed command, ignoring it") # Then ignore the objects / conjuncts because this is # a single command, so more likely to be a movement/command if len(valid_singles) > 1: de.bug(1, "Most likely is a single COMMAND, deleting matched objects etc.") del_keys = [] for c in valid_singles: if 'o-' in c: del_keys.append(c) de.bug(1, "del_keys", del_keys) for d in del_keys: valid_singles.remove(d) de.bug(1, "Cleaned VALID SINGLES", valid_singles) # If only ONE VALID match, all is fine, keep going if len(valid_singles) == 1: tkn_cmd_matches[tkns[0]] = valid_singles[0] else: # final check just in case #### NEED TO FIX THIS WITH A PROPER ERROR RESPONSE!! #### de.bug("ERROR!!!!! can't resolve this command. Too many gameData matches!!!") de.bug(1, "MATCHED COMMANDS so far (all done)", tkn_cmd_matches) de.bug(1, "CHECK parsed_final = ", parsed_final) ## Finally, classify the known commands for a, b in tkn_cmd_matches.items(): known_cmds.append(b) de.bug(1, "ALL KNOWN COMMANDS, in order", known_cmds) # then classify each matched cmd as a type # o = obj, m = mov, conJunct = con # else = cmd a_cmd = None a_obj = None a_conJunct = None a_via = None obj_ls = [] type_list = [None, None, None, None] # see grammar bit below for i in known_cmds: els = i.split("-") if els[0] == "conJuncts": a_conJunct = i type_list[known_cmds.index(i)] = 'jun' elif els[0] == "o": # obj and via present obj_ls.append(i) type_list[known_cmds.index(i)] = 'obj' else: a_cmd = i type_list[known_cmds.index(i)] = 'cmd' de.bug(1, "type_list", type_list) # assign obj and via, if present if len(obj_ls) > 1: a_obj, a_via = obj_ls elif len(obj_ls) == 1: a_obj = obj_ls[0] # build and return the correctly ordered variables to gameExec parsed_types = ['cmd', 'obj', 'jun', 'via'] parsed_final.extend([a_cmd, a_obj, a_conJunct, a_via]) # Create TEMP_VARS dictionary of all user-input, dicovered matches # in gameData, and locations of objects for subsequent NLP rules TEMP_VARS = {} for a, b in tkn_cmd_matches.items(): v_name = ('this_' + parsed_types[parsed_final.index(b)]).upper() TEMP_VARS[v_name] = {} TEMP_VARS[v_name]['user-input'] = a TEMP_VARS[v_name]['ref-id'] = [] if (parsed_types[parsed_final.index(b)] == 'obj') or (parsed_types[parsed_final.index(b)] == 'via'): TEMP_VARS[v_name]['obj-loc'] = [] objIds = ctrls.get_ObjectId(a) de.bug(1, "possible ids for the obj are:", objIds) i = 0 for o in objIds: l = ctrls.get_ObjectLocation(o) de.bug(1, "OBJ LOC is", l) TEMP_VARS[v_name]['obj-loc'].append(l) if l == False: # FALSE if obj not found at loc or INV TEMP_VARS[v_name]['ref-id'].append(False) else: TEMP_VARS[v_name]['ref-id'].append(o) i += 1 else: TEMP_VARS[v_name]['ref-id'].append(b) de.bug(1, "TEMP_VARS", TEMP_VARS) # HANDLING MULITPLE MATCHES from vague user-input # Help the player by removing some options that are # impossible given the structure of the user input ##################### GRAMMAR BIT ############################# ################### IMPORTANT NOTE ############################ # This is only to remove impossible options from a list # that already contains too many options. This is NOT # pre-censoring user-input. All SINGLE matches, including illegal # ones are handled later by specific clauses in command_handling # Remove INVALID Commands options if 'THIS_CMD' in TEMP_VARS: if len(TEMP_VARS['THIS_CMD']['ref-id']) > 1: # if OBJ present cannot be an EXPLORE command del_list = [] if len(TEMP_VARS['THIS_OBJ']['ref-id']) > 0: for i in TEMP_VARS['THIS_CMD']['ref-id']: if "explore" in i: c = TEMP_VARS['THIS_CMD']['ref-id'].index(i) de.bug(1, "Need to REMOVE this ref-id", c) del_list.append(c) # de-dupe del_list del_list = list(set(del_list)) # delete invalid items for d in del_list: TEMP_VARS['THIS_CMD']['ref-id'].remove(d) # If no OBJ, or OBJ not in INV, can't be a PUT command # Not complete (because I think it is impossible # to have multiple matched commands, so this section is # not needed! :) # Remove INVALID Objects options if 'THIS_OBJ' in TEMP_VARS: if len(TEMP_VARS['THIS_OBJ']['ref-id']) > 1: ## RULE: if THIS_CMD is GET then.... del_list = [] for i in TEMP_VARS['THIS_CMD']['ref-id']: if "get" in i: # ...object must be in LOCDATA or it is not visible to the player for k in TEMP_VARS['THIS_OBJ']['ref-id']: if k in gD.LOCDATA['locObjects']: # check locObjects, not ['obj-loc'] because a key in an OPEN box will be in locObjects, but have an obj-loc of the box continue else: de.bug(1, "Need to REMOVE this ref-id", k, "and this obj-loc", TEMP_VARS['THIS_OBJ']['obj-loc'][TEMP_VARS['THIS_OBJ']['ref-id'].index(k)]) del_list.append(k) # ...the object cannot be in INV for j in TEMP_VARS['THIS_OBJ']['obj-loc']: if j == '$INV': c = TEMP_VARS['THIS_OBJ']['obj-loc'].index(j) de.bug(1, "Need to REMOVE this ref-id", TEMP_VARS['THIS_OBJ']['ref-id'][c], "and this obj-loc", TEMP_VARS['THIS_OBJ']['obj-loc'][c]) del_list.append(TEMP_VARS['THIS_OBJ']['ref-id'][c]) # de-dupe del_list del_list = list(set(del_list)) # delete invalid items for d in del_list: TEMP_VARS['THIS_OBJ']['obj-loc'].remove(TEMP_VARS['THIS_OBJ']['obj-loc'][TEMP_VARS['THIS_OBJ']['ref-id'].index(d)]) TEMP_VARS['THIS_OBJ']['ref-id'].remove(d) ## RULE: if THIS_CMD is PUT then... del_list = [] for i in TEMP_VARS['THIS_CMD']['ref-id']: if "put" in i: # ...the object must be in INV for j in TEMP_VARS['THIS_OBJ']['obj-loc']: if j != '$INV': c = TEMP_VARS['THIS_OBJ']['obj-loc'].index(j) de.bug(1, "Need to REMOVE this ref-id", TEMP_VARS['THIS_OBJ']['ref-id'][c], "and this obj-loc", TEMP_VARS['THIS_OBJ']['obj-loc'][c]) del_list.append(TEMP_VARS['THIS_OBJ']['ref-id'][c]) # delete invalid items for d in del_list: TEMP_VARS['THIS_OBJ']['obj-loc'].remove(TEMP_VARS['THIS_OBJ']['obj-loc'][TEMP_VARS['THIS_OBJ']['ref-id'].index(d)]) TEMP_VARS['THIS_OBJ']['ref-id'].remove(d) ## RULE: check OBJ commands, if THIS_CMD not there remove OBJ del_list = [] for o in TEMP_VARS['THIS_OBJ']['ref-id']: this_obj = gD.gameDB['objectsDB'][o] ch_list = [] for k, v in this_obj.items(): #match any of "getCmds-OK, putCmds-OK" etc if 'OK' in k: els = k.split("-") ch_list.append(els[0]) cm = TEMP_VARS['THIS_CMD']['ref-id'][0].split("-") if ch_list.count(cm[0]) == 0: de.bug(1, "Need to REMOVE this ref-id", o, "and this obj-loc", TEMP_VARS['THIS_OBJ']['obj-loc'][TEMP_VARS['THIS_OBJ']['ref-id'].index(o)]) del_list.append(o) # de-dupe del_list del_list = list(set(del_list)) # delete invalid items for d in del_list: TEMP_VARS['THIS_OBJ']['obj-loc'].remove(TEMP_VARS['THIS_OBJ']['obj-loc'][TEMP_VARS['THIS_OBJ']['ref-id'].index(d)]) TEMP_VARS['THIS_OBJ']['ref-id'].remove(d) # Remove INVALID Conjuncts options # if 'THIS_JUN' in TEMP_VARS: # Not got any yet :) # Remove INVALID Vias options if 'THIS_VIA' in TEMP_VARS: if len(TEMP_VARS['THIS_VIA']['ref-id']) > 1: # RULE: if conjunct is "with", VIA must be in INV, or not valid del_list = [] if TEMP_VARS['THIS_JUN']['user-input'] == 'with': for l in TEMP_VARS['THIS_VIA']['obj-loc']: if l is not '$INV': de.bug(1, "Need to REMOVE this ref-id", TEMP_VARS['THIS_VIA']['ref-id'][TEMP_VARS['THIS_VIA']['obj-loc'].index(l)], "and this obj-loc", l) del_list.append(TEMP_VARS['THIS_VIA']['ref-id'][TEMP_VARS['THIS_VIA']['obj-loc'].index(l)]) # delete invalid items for d in del_list: TEMP_VARS['THIS_VIA']['obj-loc'].remove(TEMP_VARS['THIS_VIA']['obj-loc'][TEMP_VARS['THIS_VIA']['ref-id'].index(d)]) TEMP_VARS['THIS_VIA']['ref-id'].remove(d) ######################### END OF GRAMMAR BIT ####################### de.bug(1, "CLEANED TEMP_VARS", TEMP_VARS) # set GLOBAL VARS gD.INPUT_VARS = TEMP_VARS de.bug(1, "INPUT_VARS are now:", gD.INPUT_VARS) # If more than one remaining option set input prompt to "duplicates" for i, j in gD.INPUT_VARS.items(): if len(j['ref-id']) > 1: de.bug(1, "Duplicates still present. Need more details.") gD.PROMPT = 'duplicates' return False de.bug(1, "PARSED_FINAL (sending to gameExec)", parsed_final) return parsed_final
def re_runWrdChecker(d): de.bug(1, "!-!-!-! RESTARTING PARSEINPUT!!!") return parseInput(d)
def render_Text(d, t="default"): #generic text renderer if t == 'move': # movement description text if d != False: print(ss.inputChangeLocPre, d) else: print(ss.inputFeedbackPre, "You can't go that way") elif t == 'win': # winning message print(ss.inputFeedbackPre, d) elif t == 'exit': #exit command print(ss.inputFeedbackPre, ss.exitMessage) # elif t == 'unlocked': # now open # print(ss.inputFeedbackPre, "The", d.lower(), "is now", t) elif t == 'already locked': # now open print(ss.inputFeedbackPre, "The", d.lower(), "is", t) elif t == 'cheat': #cheat command temp = 'this is t {}'.format(t) de.bug(temp) # show all available movement commands for this location print(ss.inputFeedbackPre, "Available moves are", end=": ") # unpack commands from nested dicts{} tmp = [j for i in d for j in i] # list the commands print(tfs.listify(tmp)) #show custom cheater feedback message messages = ss.cheaterMessage print(ss.inputFeedbackPre, messages[random.randint(0, len(messages) - 1)]) elif t == 'help': #help command # split d - data payload in params genCmds = d[0] objCmds = d[1] # show all GENERAL commands for the game print(ss.inputFeedbackPre, "General commands", end=": ") # end= prevents new line # unpack commands from nested dicts{} tmp = [j for i, k in genCmds.items() for j in k] # list the GENERAL commands print(tfs.listify(tmp)) # show all OBJECT commands for the game print(ss.inputFeedbackPre, "Interaction commands", end=": ") # end= prevents new line # retrieve commands in array data tmp = [i for i in objCmds] # list the OBJECT commands print(tfs.listify(tmp)) elif t in ('look', 'search'): #search command # show all objects in the location print(ss.inputFeedbackPre, "You find the following", end=": ") oRefs = [ gD.gameDB['objectsDB'][i]['name'] for i in gD.LOCDATA['locObjects'] ] # for i in d: # oRefs.append(gD.gameDB['objectsDB'][i]['name']) # list the object refs print(tfs.listify(oRefs, True)) # show all monsters in the location! #TODO: Make search trigger all monsters revealed #### INCOMPLETE elif t in ('look for', 'where'): # requires an obj [desc,location] array print(ss.inputFeedbackPre, "You see", d[0].lower(), d[1].lower()) elif t == 'missing object': # part of controllers.useObject() print(ss.inputFeedbackPre, "You can't see the", d.lower(), "here") elif t == 'look at': # d is a list but [1] can be False is d has no access restrictions i.e. "locked" if (len(d) > 1) and (d[1] != False): print(ss.inputFeedbackPre, "You see", d[0].lower(), ". It is", d[1].lower()) else: print(ss.inputFeedbackPre, "You see", d[0].lower()) elif t == 'not in inv': # player trying to drop an obj not in their inv print(ss.inputFeedbackPre, "You do not have the", d.lower(), "in your inventory") elif t == 'already in inv': # trying to add an obj already in the inv print(ss.inputFeedbackPre, "You already have the", d.lower(), "in your inventory") elif t == 'contained by': print(ss.inputFeedbackPre, "You see", tfs.listify(d[0], True), "in the", d[1].lower()) elif t == 'container empty': print(ss.inputFeedbackPre, "The", d.lower(), "is empty!") elif t == 'seen through': print(ss.inputFeedbackPre, "You see", tfs.listify(d[0], True), "through the", d[1].lower()) elif t == 'examine': # part of controllers.useObject() # grab object name & remove from list oword = d.pop() print(ss.inputFeedbackPre, "You can", end=" ") # end= prevents new line # list out the available commands print(tfs.listify(d, False, "or"), "the", oword.lower()) elif t == 'default': # just render payload print(d)
def doCommand(cmd, obj, jun, via, uiData): legalInputs = gD.LEGALINPUTS if cmd != None: # we only need to identify the TYPE of cmd # so we can action the correct function next cmd_spl = cmd.split("-") cmd_ky = cmd_spl[0] my_cmd = gD.INPUT_VARS['THIS_CMD']['user-input'] de.bug(1, "my_cmd is", my_cmd) de.bug(1, "move cmds for this loc are", gD.LOCDATA['moveCmds']) if cmd_ky == "m": # MOVEMENT command moveDesc = False moveDest = False for m in gD.LOCDATA['moveCmds']: for h, i in gD.gameDB['moveCommandsDB'][m].items(): for j in i['cmds']: if my_cmd == j: moveDesc = i['goDesc'] if 'destId' in i: moveDest = i['destId'] else: de.bug( "NOTICE: This cmd doesn't change our location" ) # show moveDesc feedback for moveCmd ctrls.printText(moveDesc, "move") # if associated locID for moveCmd - ctrls.changeLoc ctrls.changeLoc(moveDest) elif cmd_ky in gD.gameDB['uiCmds'].keys(): # UI command # send to uiActions to handle the UI command uiActions(cmd, obj, jun, via, legalInputs, uiData) elif cmd_ky in gD.gameDB['actionCmds'].keys(): # ACTION command de.bug(2, "locDATA", gD.LOCDATA) # send the cmd and the obj to useObject for more detailed handling useObject(cmd, obj, jun, via) else: # Command not known de.bug("Error (doCommand): The command", cmd, "is not handled yet") elif obj != None: # empty cmd but we have a singleton obj # send to useObject anyway to give Player object help feedback useObject(cmd, obj, jun, via) else: # Too many params are None to do anything useful return False
def useObject(cmd, obj, jun, via): # generic Object handler # E.G. cmd: generalCmds-0 | obj: o-7 | jun: conJuncts-2 | via: o-11 ######### GOT TO HERE ############### # then finally # need to go through anything that REworks out any of # these now global references and make then use the # GLOBALS instead. For example: do_command() # THEN FINALLY need to make the "what am I" function # that "is this object at the location" can call # and tidy up that whole useObject function A LOT """ INPUT_VARS are now: { 'THIS_CMD': {'user-input': 'open', 'ref-id': ['intCmds-0']}, 'THIS_OBJ': {'user-input': 'box', 'ref-id': ['ob0002'], 'obj-loc': ['z0001']}, 'THIS_JUN': {'user-input': 'with', 'ref-id': ['conJuncts-0']}, 'THIS_VIA': {'user-input': 'key', 'ref-id': [], 'obj-loc': []} } """ # Resetting values # obs_list = gD.LOCDATA['locObjects'] obj_cmds = [] cmd_ref = None obj_ref = None via_ref = None jun_ref = None obj_id = None this_obj = None this_via = None # SETUP SCRIPT VARS from globals if cmd: cmd_ref = gD.INPUT_VARS['THIS_CMD']['user-input'] if jun: jun_ref = gD.INPUT_VARS['THIS_JUN']['user-input'] if via: via_ref = gD.INPUT_VARS['THIS_VIA']['user-input'] # Detect invalid VIA if gD.INPUT_VARS['THIS_VIA']['ref-id']: via_id = gD.INPUT_VARS['THIS_VIA']['ref-id'][0] this_via = gD.gameDB['objectsDB'][via_id] else: de.bug(1, "INVALID VIA", via_ref) if obj: obj_ref = gD.INPUT_VARS['THIS_OBJ']['user-input'] # Detect invalid obj if gD.INPUT_VARS['THIS_OBJ']['ref-id']: obj_id = gD.INPUT_VARS['THIS_OBJ']['ref-id'][0] obj_desc = gD.gameDB['objectsDB'][obj_id]['desc'] obj_locdesc = gD.gameDB['objectsDB'][obj_id]['location'] this_obj = gD.gameDB['objectsDB'][obj_id] # Get all Object Commands obj_cmds = ctrls.get_ObjectCommands(this_obj) # User referenced a VALID object WITHOUT putting # an action command - So give them help if cmd_ref == None: renderers.render_objectHelp(obj_cmds, this_obj['name']) return False # exit this function else: de.bug(1, "INVALID OBJ", obj_ref) ############## COMMANDS THAT REQUIRE NO OBJECT ################ if cmd_ref in gD.gameDB['actionCmds']['exploreCmds'] and obj == None: ### == generic explore COMMANDS: look / search etc ==== # give user feedback on their command ctrls.printText(None, cmd_ref) return True # exit this function, we're done here if via_ref: ### == navigation COMMANDS w/ VIA e.g. 'go in', 'get in' ========= if cmd_ref in ('get', 'go', 'walk'): de.bug(3, "We have a VIA movement type of command!", cmd_ref, jun, via) #TODO: Handle changing location with a cmd, jun, via input ######### NOT COMPLETE NEED RENDER TEXT TO HANDLE THIS ## # Needs to handle changing location using the via ######################################################## ############## COMMANDS THAT NEED AN OBJECT ################ if obj_ref: # if obj_ref != None, but gD.INPUT_VARS['THIS_OBJ']['ref-id'] == None: ## This means that the command is invalid for the object # so throw that error "You can't X the Y" if obj_id == None: de.bug(1, "INVALID obj", obj_ref, ". You can't", cmd_ref, "this object") ### We are no longer checking if object at location before this # So GET for example, needs to check if INPUT_VARS['THIS_OBJ']['obj-loc'] == gD.CURRENTLOC # And put needs to check obj in INV # And any other cmd that requires obj to be local needs to CHECK ### == specific explore COMMANDS: look in / under etc ==== if cmd_ref in gD.gameDB['actionCmds']['exploreCmds']: # check object access state ob_access = ctrls.get_ObjectState(this_obj, 'access') de.bug(4, "ob_access is:", ob_access) # GET the contained objects ids, descs, t = ctrls.get_ObjectContents(obj_id) ## check if object permissions prevent action if ob_access == "unlocked": # ADD the object to the world local objects ctrls.update_WorldState(obj_id, False, 'add') de.bug(1, "contained objects", descs) # full or empty container? if len(descs) > 0: # feedback to player what they have discovered ctrls.printText([descs, this_obj['name']], "contained by") else: ctrls.printText(this_obj['name'], 'container empty') elif ob_access == "locked": # feedback to player about the req object renderers.render_objectActions(this_obj, cmd_ref, "locked_by") # does player have the req object? this_via_obj = gD.gameDB['objectsDB'][this_obj['permissions'] ['locked_by']] if ctrls.get_InventorySlot(this_via_obj) == False: ctrls.printText(this_via_obj['name'], 'not in inv') ### == examine COMMANDS: look at, examine etc. ============= elif cmd_ref in gD.gameDB['actionCmds']['examineCmds']: d = [this_obj['desc'], ctrls.get_ObjectState(this_obj, s='access')] ### FIX THIS ################# # Combine these two printText renders into one # show object description ctrls.printText(d, 'look at') # bit of a hack this... add obj name to end of obj_cmds # for renderer to .pop() off afterwards obj_cmds.append(this_obj['name']) ctrls.printText(obj_cmds, 'examine') ### == search COMMANDS: look for, where etc =========== elif cmd_ref in gD.gameDB['actionCmds']['searchCmds']: # show both obj desc and loc together ctrls.printText([obj_desc, obj_locdesc], cmd_ref) ### == get, put, use, int COMMANDS ===================== # check legal action for the object elif cmd_ref in obj_cmds: ### == get command add object to inventory ============ # check all get aliases for i in gD.gameDB['actionCmds']['getCmds']: if cmd_ref == i: # GET the contained objects ids, descs, t = ctrls.get_ObjectContents(obj_id) de.bug(4, "these contained objs", ids, "this containment type", t, "this_obj", this_obj) # add obj to inv & ctrls.update_WorldState if ctrls.update_Inventory(obj_id, "add") != False: # render feedback to player renderers.render_objectActions(this_obj, cmd_ref, "get-take") # render the player inventory renderers.render_charInventory() # update child object state & get parent container p = ctrls.update_ObjectState(obj_id, this_obj, cmd_ref) # update parent container state using returned "p" if p != None: ctrls.update_ObjectState(obj_id, this_obj, 'un_contain', p) # finally REMOVE the contained items from the world # because they are now in player inventory ctrls.update_WorldState(ids, t, 'remove') else: # trying to add obj ALREADY in inv ctrls.printText(this_obj['name'], 'already in inv') ### == put command remove object from inventory ========= #TODO: Need a more complex "put ... in... " version where this_obj # gets added to a new parent_container, not to local Objects # see 'get' above for handling parents vs local world objects # check all put aliases for i in gD.gameDB['actionCmds']['putCmds']: if cmd_ref == i: # remove obj from inv if ctrls.update_Inventory(obj_id, "remove") != False: # is there a VIA object for the action? if via != None: # put something IN somewhere (VIA) # update parent container (via) state ctrls.update_ObjectState(obj_id, this_obj, 'add', via_id) else: # simple put/drop command # render feedback to player renderers.render_objectActions( this_obj, cmd_ref, "put-leave") # ADD the object to the world local objects ctrls.update_WorldState(obj_id, False, 'add') # render the player inventory renderers.render_charInventory() else: # trying to remove obj not in inv ctrls.printText(this_obj['name'], 'not in inv') ### == open/unlock command do object custom action ============= if cmd_ref in ("open", "unlock"): # check object access state ob_access = ctrls.get_ObjectState(this_obj, s='access') de.bug(4, "ob_access is:", ob_access) if ob_access == 'locked': # check if object permissions prevent action can_open = ctrls.get_ObjectPermissions(this_obj) de.bug(4, "lock perms are", can_open) if can_open in ("ok", "unlocked", "has-req-obj"): # obj not locked # render feedback to player renderers.render_objectActions( this_obj, cmd_ref, can_open, this_obj['permissions']['locked_by']) # update object state ctrls.update_ObjectState(obj_id, this_obj, cmd_ref) else: # feedback access state of object to player renderers.render_objectActions(this_obj, cmd_ref, can_open) # player does not have the req object this_via = gD.gameDB['objectsDB'][obj_id][ 'permissions']['locked_by'] if ctrls.get_InventorySlot(this_via) == False: ctrls.printText( gD.gameDB['objectsDB'][this_via]['name'], 'not in inv') else: # not locked => can open: update object state ctrls.update_ObjectState(obj_id, this_obj, cmd_ref) ### == close/lock command do object custom action ============= elif cmd_ref in ("lock", "close"): # check object access state ob_access = ctrls.get_ObjectState(this_obj, s='access') de.bug(4, "ob_access is:", ob_access) if ob_access == 'unlocked': # check if object permissions prevent action can_close = ctrls.get_ObjectPermissions(this_obj) de.bug(4, "lock perms are", can_close) if can_close == "has-req-obj": # render feedback to player renderers.render_objectActions( this_obj, cmd_ref, can_close, this_obj['permissions']['unlocked_by']) # update object state ctrls.update_ObjectState(obj_id, this_obj, cmd_ref) else: # render object state feedback to player renderers.render_objectActions(this_obj, cmd_ref, can_close) # player does not have the req object this_via = gD.gameDB['objectsDB'][ this_obj['permissions']['unlocked_by']] if ctrls.get_InventorySlot(this_via) == False: ctrls.printText(this_via['name'], 'not in inv') else: # feedback to player object already locked ctrls.printText(this_obj['name'], 'already locked') ### == use command do object custom action ============= elif cmd_ref == "use": # check used obj is in player inv if ctrls.get_InventorySlot(this_obj) != False: # no target, singleton "use" if via != None: #TODO: The USE command and results of it ## INCOMPLETE . JUST ALL OF THIS!! # check object STATE ctrls.update_ObjectState(obj_id, this_obj, cmd_ref) de.bug("use key on -", via) #use key on box # renderers.render_objectActions(o, cmd, cmd) # check correct req obj for obj # do something now the obj is used # for example a box display stuff inside else: # use key - "use key on what?" # render feedback to player renderers.render_objectActions(this_obj, cmd_ref, cmd_ref) else: # trying to use obj not in inv ctrls.printText(this_obj['name'], 'not in inv') else: # must be an illegal command for this object # feedback 'you can't do that to this object' t = "illegal" renderers.render_objectActions(this_obj, cmd_ref, t) # IF ALL ELSE FAILS cmd is a singleton, show correct actionHelp feedback if cmd != None and obj == None and via == None: renderers.render_actionHelp(cmd_ref)
def update_ObjectState(obj_id, o, cmd_ref, p=None): # p is the parent container, optional param # reset values o_s = o['state'] # == Simple state changes ================================== if cmd_ref == 'un_contain': de.bug(5, "Want to un-parent this:", obj_id, "from this:", gD.gameDB['objectsDB'][p]['state']['contains']) gD.gameDB['objectsDB'][p]['state']['contains'].remove(obj_id) elif cmd_ref == 'add': de.bug(5, "Adding", obj_id, "to", p) gD.gameDB['objectsDB'][p]['state']['contains'].append(obj_id) # == GET/PUT COMMANDS ============================================= ## If object is contained, change its state to not-contained and # return the parent object for future processing elif cmd_ref in gD.gameDB['actionCmds']['getCmds']: if len(o_s): for s, t in o_s.items(): if s == 'contained_by': # get parent container p = gD.gameDB['objectsDB'][obj_id]['state']['contained_by'] # remove contained by state as the object is now # out of its container and into the world del gD.gameDB['objectsDB'][obj_id]['state']['contained_by'] # return requirement to update parent container return p # == OPEN/UNLOCK COMMANDS ========================================== elif cmd_ref in ('open', 'unlock'): # open, unlock etc. if len(o_s): # change STATE and PERMISSIONS of object if 'access' in o_s: # RENAME the 'locked' state to 'unlocked' gD.gameDB['objectsDB'][obj_id]['state']['access'] = 'unlocked' # RENAME the permissions field # so a record of the locking item is kept (for re-locking) if 'locked_by' in o['permissions']: gD.gameDB['objectsDB'][obj_id]['permissions'][ 'unlocked_by'] = gD.gameDB['objectsDB'][obj_id][ 'permissions']['locked_by'] del gD.gameDB['objectsDB'][obj_id]['permissions'][ 'locked_by'] de.bug(5, "changed state of", obj_id, "to", gD.gameDB['objectsDB'][obj_id]['state']['access'], "and", gD.gameDB['objectsDB'][obj_id]['permissions']) if 'contains' in o_s: # GET the contained objects ids, descs, t = get_ObjectContents(obj_id) # ADD the contained items to the game world update_WorldState(ids, t, 'add') # feedback to player the objects they have discovered if t == "in": printText([descs, o['name']], "contained by") elif t == "via": printText([descs, o['name']], "seen through") # == CLOSE/LOCK COMMANDS ========================================== elif cmd_ref in ('close', 'lock'): # close, lock etc. if len(o_s): # have to do contents removal first, because otherwise # the box is locked and contents are inaccessible! :D if 'contains' in o_s: # GET the contained objects ids, descs, t = get_ObjectContents(obj_id) # ADD the contained items to the game world update_WorldState(ids, t, 'remove') if 'access' in o_s: # RENAME the 'unlocked' state to 'locked' gD.gameDB['objectsDB'][obj_id]['state']['access'] = 'locked' # RENAME the permissions field # so a record of the locking item is kept (for un-locking) if 'unlocked_by' in o['permissions']: gD.gameDB['objectsDB'][obj_id]['permissions'][ 'locked_by'] = gD.gameDB['objectsDB'][obj_id][ 'permissions']['unlocked_by'] del gD.gameDB['objectsDB'][obj_id]['permissions'][ 'unlocked_by'] de.bug(5, "changed state of", obj_id, "to", gD.gameDB['objectsDB'][obj_id]['state']['access'], "and", gD.gameDB['objectsDB'][obj_id]['permissions'])