Source code for game.common.map.occupiable

from game.common.enums import ObjectType
from game.common.game_object import GameObject
from game.common.items.item import Item
from typing import Self, Type
from game.common.avatar import Avatar


[docs]class Occupiable(GameObject): """ `Occupiable Class Notes:` Occupiable objects exist to encapsulate all objects that could be placed on the gameboard. These objects can only be occupied by GameObjects, so inheritance is important. The ``None`` value is acceptable for this too, showing that nothing is occupying the object. Note: The class Item inherits from GameObject, but it is not allowed to be on an Occupiable object. """ def __init__(self, occupied_by: GameObject = None, **kwargs): super().__init__() self.object_type: ObjectType = ObjectType.OCCUPIABLE self.occupied_by: GameObject | None = occupied_by @property def occupied_by(self) -> GameObject | None: return self.__occupied_by @occupied_by.setter def occupied_by(self, occupied_by: GameObject | None) -> None: # first if statement used to prevent Item objects from being set as occupied_by # this can be discussed further, but it has been removed to allow for more flexibility if occupied_by is not None and not isinstance(occupied_by, GameObject): raise ValueError( f'{self.__class__.__name__}.occupied_by must be None or an instance of GameObject. It is a(n) {occupied_by.__class__.__name__} with the value of {occupied_by}.') self.__occupied_by = occupied_by
[docs] def place_on_top_of_stack(self, game_object: GameObject) -> bool: """ This method will take in a GameObject and place it on top of the occupied_by stack of the Occupiable object. The placed object will then also be underneath the Avatar object. Example before placing: Tile -> Avatar After placing: Tile -> NewObject -> Avatar """ temp_game_object: GameObject = self # Execute loop only if the object occupying self is an object (i.e., not none) and can also be occupied while temp_game_object.occupied_by is not None and isinstance(temp_game_object.occupied_by, Occupiable): # moves to the next thing in the stack of occupiable objects temp_game_object = temp_game_object.occupied_by if temp_game_object.occupied_by is not None: if not isinstance(temp_game_object.occupied_by, Avatar) or not isinstance(game_object, Occupiable): return False game_object.occupied_by = temp_game_object.occupied_by temp_game_object.occupied_by = game_object # assign the last thing on top of the stack that is occupiable return True
[docs] def get_occupied_by(self, target: ObjectType | GameObject) -> GameObject | None: """ Get the object in the occupied_by stack given either the ObjectType or GameObject. Returns the GameObject in the stack, but None if it isn't there. **This does NOT remove the GameObject.** """ # start on the first object in the stack that isn't this object temp_game_object: GameObject = self.occupied_by while temp_game_object is not None: if (isinstance(target, ObjectType) and temp_game_object.object_type == target) or \ isinstance(target, GameObject) and isinstance(temp_game_object, target.__class__): return temp_game_object if isinstance(temp_game_object, Occupiable): temp_game_object = temp_game_object.occupied_by else: return None return temp_game_object
[docs] def is_occupied_by_object_type(self, object_type: ObjectType) -> bool: """ This method searches for the given ObjectType in the stack of occupied_by. If found, returns true. """ # start on the first object in the stack that isn't this object temp_game_object: GameObject = self.occupied_by # only check if the object is None because we want to look through the entire stack of objects. while temp_game_object is not None: # if the object is what we want, return true if temp_game_object.object_type == object_type: return True if isinstance(temp_game_object, Occupiable): # moves to the next thing in the stack of occupiable objects temp_game_object = temp_game_object.occupied_by else: return False # if the object doesn't have the attribute, wanted object isn't in stack # if the wanted object isn't found, return False return False
[docs] def is_occupied_by_game_object(self, game_object_type: Type) -> bool: """ This method searches for the given GameObject in the stack of occupied_by. If found, returns true. """ # start on the first object in the stack that isn't this object temp_game_object: GameObject = self.occupied_by # only check if the object is None because we want to look through the entire stack of objects. while temp_game_object is not None: # if the object is what we want, return true if isinstance(temp_game_object, game_object_type): return True if isinstance(temp_game_object, Occupiable): # moves to the next thing in the stack of occupiable objects temp_game_object = temp_game_object.occupied_by else: return False # if the object doesn't have the attribute, wanted object isn't in stack # if the wanted object isn't found, return False return False
[docs] def get_top_of_stack(self) -> GameObject | None: """ Method to get the top object of a stack """ temp_game_object: GameObject = self #ignore potential warnings while temp_game_object.occupied_by is not None and isinstance(temp_game_object.occupied_by, Occupiable): temp_game_object = temp_game_object.occupied_by return temp_game_object
[docs] def remove_object_type_from_occupied_by(self, object_type: ObjectType | None = None) -> GameObject | None: """ This method will remove the first instance of the given ObjectType found in the occupied by stack. """ # if the object type isn't in the stack, return None if not self.is_occupied_by_object_type(object_type): return None current_game_object: GameObject = self # variable to store what the next thing in the stack is. Either None or a GameObject next_game_object: GameObject = current_game_object.occupied_by while (current_game_object and next_game_object is not None) and \ current_game_object.occupied_by.object_type != object_type: current_game_object = current_game_object.occupied_by next_game_object = next_game_object.occupied_by # at top of stack without finding wanted object if next_game_object is None: return None if not isinstance(next_game_object, Occupiable): current_game_object.occupied_by = None return next_game_object if next_game_object.object_type == object_type and isinstance(next_game_object, Occupiable): # reassign the current game_object's occupied_by and return what the next game object is IF it's occupiable current_game_object.occupied_by = next_game_object.occupied_by return next_game_object else: current_game_object.occupied_by = None return None
[docs] def remove_game_object_from_occupied_by(self, game_object: GameObject | None = None) -> GameObject | None: """ This method will remove the first instance of the given ObjectType found in the occupied by stack. """ # if the object type isn't in the stack, return None if not self.is_occupied_by_object_type(game_object.object_type): return None current_game_object: GameObject = self # variable to store what the next thing in the stack is. Either None or a GameObject next_game_object: GameObject = current_game_object.occupied_by while (current_game_object and next_game_object is not None) and \ current_game_object.occupied_by is not game_object: current_game_object = current_game_object.occupied_by next_game_object = next_game_object.occupied_by # at top of stack without finding wanted object if next_game_object is None: return None if next_game_object is game_object and isinstance(next_game_object, Occupiable): # reassign the current game_object's occupied_by and return what the next game object is IF it's occupiable current_game_object.occupied_by = next_game_object.occupied_by return next_game_object else: current_game_object.occupied_by = None return next_game_object
[docs] def get_stack_list(self): temp_game_object: GameObject = self stack_list: list = [] while temp_game_object.occupied_by is not None and isinstance(temp_game_object.occupied_by, Occupiable): temp_game_object = temp_game_object.occupied_by stack_list.append(temp_game_object) return stack_list
[docs] def to_json(self) -> dict: data: dict = super().to_json() data['occupied_by'] = self.occupied_by.to_json() if self.occupied_by is not None else None return data
[docs] def from_json(self, data: dict) -> Self: super().from_json(data) return self