#!/usr/bin/python3 """ This module implements the (foundation) GameObject Class """ import sys from random import randint from base import Base from gameaction import GameAction class GameObject(Base): """ This is the base class for all artifacts, actors, and contexts. The abilities of this base class are: - own a list of objects (which can be added and retrieved) - return a list of GameActions that it enables - accept and process non-ATTACK GameActions @ivar objects: list of owned/contained GameObjects objects can be I{hidden} in which case they might not be returned """ def __init__(self, name="actor", descr=None): """ create a new GameObject @param name: display name of this object @param descr: for players description of this object """ def __str__(self): """ return the given name of this object """ def get_objects(self, hidden=False): """ return a list of GameObjects contained in/owned by this GameObject if an object is hidden (has a positive RESISTANCE.SEARCH) it may not be visible unless - it has been successfully found (SEARCH > 0) - caller specifies that hidden objects should be returned @param hidden: return only hidden objects @return: list of discoverd GameOjects """ # check object's RESISTANCE.SEARCH and SEARCH attributes # if hidden specified, find all hidden objects # else find only visible objects def get_object(self, name): """ return a named object from my inventory @param name: (string) of the desired object @return: first matching object (or None) """ def add_object(self, item): """ add another object to my C{objects} list (if not already there) """ def accept_action(self, action, actor, context): """ called by C{GameAction.act()} to receive GameAction, determine effects NOTE: this base class cannot process ATTACK actions. Those are processed by the C{GameActor} sub-class. This base class can only process actions which (if successful), increment the property who's name matches the action verb. @param action: GameAction being performed @param actor: GameActor initiating the action @param context: GameContext in which action is occuring NOTE: this base class makes no use of the C{actor} or C{context} parameters, but they might be useful to a subc-class that could process actions before passing them down to us. @return: <(boolean) success, (string) description of the effect> """ # get the base verb and sub-type # look up our base resistance # see if we have a RESISTANCE.base-verb # see if we have a RESISTANCE.base-verb.subtype # if sum of RESISTANCE >= TO_HIT, action has been resisted # for each STACK instance, roll to see if roll+RESISTANCE > TO_HIT # accumulate the number that get through # add number of successful STACKS to affected attribute # (or if C{GameAction.TOTAL} is negative, subtract) # special case: LIFE cannot be raised beyond HP # return def possible_actions(self, actor, context): """ return list of C{GameAction}s this object enables verbs come from our (comma-separated-verbs) ACTIONS attribute for each C{GameAction}, ACCURACY, DAMAGE, POWER, STACKS are the sum of - our base ACCURACY, DAMAGE, POWER, STACKS - our ACCURACY.verb, DAMAGE.verb, POWER.verb, STACKS.verb, @param actor: GameActor initiating the action @param context: GameContext in which the action is taken NOTE: this base class makes no use of the C{actor} and C{context} parameters, but a sub-class might want to determine whether or not B{this actor} could perform this action in B{this context}. @return: list of possible GameActions """ # get a list of possible actions with this object (e.g. weapon) # get our base ACCURACY/DAMAGE/POWER/STACKS attributes # instantiate a GameAction for each verb in our ACTIONS list # accumulate base and sub-type attributes # if a verb is compound (+), accumulate each sub-verb separately # see if we have ATTACK sub-type ACCURACY/DAMAGE # combine the base and sub-type values # FIX GameAction.DAMAGE could be a (non-addable) D-formula # see if we have verb sub-type POWER/STACKS # FIX GameAction.STACKS could be a (non-addable) D-formula # add accumulated ACCURACY/DAMAGE/POWER/STACKS to C{GameAction} # append the new C{GameAction} to the list to be returned def load(self, filename): """ read object definitions from a file - blank lines and lines beginning w/# are ignored - NAME string ... is the name of an object - DESCRIPTION string ... is the description of that object - ACTIONS string ... is the list of supported verbs - OBJECT ... introduces definition of an object in our inventory - anything else is an atribute and value (strings should be quoted) NOTE: The object being defined can contain other objects. (e.g. guard has a sword, box contains a scroll) But contained objects cannot, themselves, contain other objects. @param filename: name of file to be read """ # for each non-comment line, read name and value # check for special names: NAME, DESCRIPTION, OBJECT # anything else is just an attribute of latest object def _lex(line): """ helper function to lex a name and (potentially quoted) value from a line - treat (single or double) quoted strings as a single token - if second token is an integer, return it as such, else a string @param line: string to be lexed @return: (name, value) ... or (None, None) for blank/comment lines """ # find the start of the first token # if this is a comment or blank line, return (None, None) # lex off first (blank separated) token as a name # lex off next token as a value # either single or double quotes can surround a value # scan until the closing quote (or EOL) # an un-quoted number should be returned as an int