class Warehouse(Building): max_capacity = kp.NumericProperty() time_to_full = kp.DictProperty({"wood": "", "clay": "", "iron": ""}) time_when_its_full = kp.DictProperty({"wood": "", "clay": "", "iron": ""}) def __init__(self): self.settings = BUILDINGS.get("WAREHOUSE") super().__init__() self.capacity0 = self.settings.get("CAPACITY_INIT") self.capacity_ratio = self.settings.get("CAPACITY_RATIO") self.max_capacity = self.calc_capacity(self.level) self.bind(level=self.on_level) Clock.schedule_interval(self.calc_when_is_full, .1) def calc_capacity(self, level): return self.capacity0 * self.capacity_ratio**(level - 1) def on_level(self, *args): self.max_capacity = self.calc_capacity(self.level) def calc_when_is_full(self, *args): self.app = App.get_running_app() for resource in self.app.resources: resource_until_full = self.max_capacity - resource.current resource_until_full = max(resource_until_full, 0) seconds_to_full = resource_until_full / resource.per_s self.time_to_full[resource._type] = str( datetime.timedelta(seconds=int(seconds_to_full))) self.time_when_its_full[resource._type] =\ datetime.datetime.fromtimestamp(time.time() + seconds_to_full).strftime('%H:%M:%S')
class CustomTVLabel(HoverBehavior, TreeViewNode, MDLabel): """Custom node object for storing database row""" item_data = prop.DictProperty() ## Dict with one row from database def __init__(self,**kwargs): super().__init__(**kwargs)
class PCDTree(MDBoxLayout): """Treeview widget + buttons and dialogs manipulations refered to data""" btn_icon = prop.ListProperty(['unfold-more-horizontal','unfold-less-horizontal']) btn_text = prop.ListProperty(['Expandir Árvore', 'Retrair Árvore']) app = prop.ObjectProperty() ## Main APP reference toggled = prop.BooleanProperty(False) ## State of nodes nodes_dict = prop.DictProperty() ## All nodes instances callable via id dialog = prop.ObjectProperty() ## Search dialog search_widget = prop.ObjectProperty() ## Search dialog content instance def __init__(self, **kwargs): super().__init__(**kwargs) self.app = MDApp.get_running_app() self.populate_all_nodes() ## add nodes to the treeview self.search_widget = SearchFrame(self) ## creates search widget self.create_search_dialog() ## creates search dialog with `self.search_widget` """ Treeview methods """ def regen_tree(self): """Regenerates treeview nodes""" self.ids.treeview.root.nodes = [] ## clear nodes list self.ids.treeview.clear_widgets() ## clear nodes widgets self.toggled = False ## reset toggled state self.populate_all_nodes() ## populate treeview def _fetch_data_into_dict(self): """Fetches data from database and converts into dict returns a list with a dict for each row of the database :return: list""" query = 'SELECT * FROM PCD ORDER BY cls_codigo' data = self.app.cursor.execute(query).fetchall() description = [ col[0] for col in self.app.cursor.description ] return [ dict(zip(description,item)) for item in data ] def _create_all_nodes(self): """Generates all nodes and sorts them between parents and children, returns a tupple of (parents,children) lists :return: tupple""" self.nodes_dict = {} ## nodes instances for future reference parents = [] ## parents list children = [] ## children list data = self._fetch_data_into_dict() ## database items in dict for item in data: ## Creates treeview node object for each item in database \/ label = CustomTVLabel(text=f"{item['cls_codigo']} - {item['cls_nome']}") label.item_data = item ## add data dict to object label.bind(on_touch_down= lambda node, _: self._node_callback(node)) ## bind function ## Adding reference to dict self.nodes_dict[item['legacyId']] = label ## sorting parents and children if str(item['parentId']) == 'zero': parents.append(label) else: children.append(label) return parents,children def populate_all_nodes(self): """Populate treeview with new nodes""" parents,children = self._create_all_nodes() for parent in parents: ## add parents to tree self.ids.treeview.add_node(parent) ## adds children nodes into parents for parent in self.ids.treeview.iterate_all_nodes(): for child in children: if parent != self.ids.treeview.root: ## skip root node if child.item_data['parentId'] == parent.item_data['legacyId']: self.ids.treeview.add_node(child,parent=parent) children.remove(child) def _node_callback(self, node): """Callback for treeview nodes, checks if Form isn't already the selected node :param node: obj""" df_c = self.app.root.ids.data_frame.children if df_c and isinstance(df_c[0], DataManagement): ## Form exists if df_c[0].item_data['legacyId'] == node.item_data['legacyId']: ## Node is IN the current Form return ## Form doesn't exist or node != current node self.generate_data_frame(node) def generate_data_frame(self, node): """Creates data management obj from current node data. node = instance of selected node :param node: obj""" self.app.set_data_management_widget( view_only = True, item_data = node.item_data ) def delete_node_from_tree(self): """Delete selected node from tree""" selected_node = self.ids.treeview.get_selected_node() self.ids.treeview.remove_node(selected_node) self.nodes_dict.pop(selected_node.item_data['legacyId']) """ Buttons methods """ def toggle_all_nodes(self): """Toggles all nodes to toggled state""" for node in self.ids.treeview.iterate_all_nodes(): if node != self.ids.treeview.root: if self.toggled and node.is_open: ## close open node self.ids.treeview.toggle_node(node) if not self.toggled and not node.is_open: ## open closed nodes self.ids.treeview.toggle_node(node) ## switches toggled state \/ self.toggled = not self.toggled def switch_button(self,reset=False): """Switches tooltip and icon when pressed""" if reset: self.btn_icon = ['unfold-more-horizontal','unfold-less-horizontal'] self.btn_text = ['Expandir Árvore', 'Retrair Árvore'] else: self.btn_icon[0], self.btn_icon[1] = self.btn_icon[1], self.btn_icon[0] self.btn_text[0], self.btn_text[1] = self.btn_text[1], self.btn_text[0] """ Search dialog methods """ def create_search_dialog(self): """Creates search dialog""" if not self.dialog: self.dialog = MDDialog( title = 'Clique na Classe para encontrá-la na árvore', size_hint = (.5,.9), pos_hint = {'right': .9}, overlay_color = [0, 0, 0, .3], auto_dismiss = False, type = "custom", radius = [20,], content_cls = self.search_widget) self.dialog.bind(on_open = self.set_focus) def set_focus(self, *_): """Sets focus to text field""" self.search_widget.ids.to_search.focus = True
class DataManagement(MDBoxLayout): """Object of text fields and buttons for managing data""" ## Place holders \/ app = None ## Main APP reference item_data = prop.DictProperty() ## Dict of one row from database new_cls = prop.BooleanProperty() ## Bool for new item without parents view_only = prop.BooleanProperty() ## Enables/Disables text fields delete_dialog = prop.ObjectProperty() ## Delete Dialog popup object editing = prop.BooleanProperty(False) ## Enable/Disable editing mode def __init__(self,view_only=True,item_data=None,new_cls=False,**kwargs): super().__init__(**kwargs) self.app = MDApp.get_running_app() ## App object reference self.view_only = view_only self.item_data = item_data self.new_cls = new_cls self.set_fields() ## Set text field contents self.add_buttons() ## Add buttons to screen def set_fields(self): """Set rules for text fields content""" if self.view_only: ## populate fields with current database row self.populate_fields() else: ## if not view_only tests for new item if self.new_cls: ## if new item, changes label icon and adds 'None' to parent node self.ids.label_icon.icon = 'folder-plus-outline' self.ids.cls_sub.text = '[ Fundo ]' self.app.pcd_tree.disabled = True ## Locks treeview else: ## if not new item, adds current item code as item parent self.ids.cls_sub.text = self.item_data['cls_codigo'] def add_buttons(self): """Add buttons depending on view_only mode""" if self.view_only: buttons = ViewButtons(edit_code=str(self.item_data['cls_codigo'])) else: buttons = EditButtons() self.ids.btn_frame.clear_widgets() self.ids.btn_frame.add_widget(buttons) def enable_edit(self): """Enables editing of text fields""" toast(f'Editando {self.item_data["cls_nome"][:40]}{" [...]" if len(self.item_data["cls_nome"]) > 40 else ""}',1) self.ids.add_label.text = f'[b]Editando[/b] {self.item_data["cls_nome"]}' self.editing = True ## Enables editing self.view_only = False ## Disables view_only mode self.app.pcd_tree.disabled = True ## Locks treeview self.add_buttons() ## Add new buttons def populate_fields(self): """Populates text fields with current item_data data""" self.ids.add_label.text = f'Visualizando [b]{self.item_data["cls_nome"]}[/b]' self.ids.cls_nome.text = str(self.item_data['cls_nome']) self.ids.cls_codigo.text = str(self.item_data['cls_codigo']) self.ids.cls_sub.text = str(self.item_data['cls_sub']) if self.item_data['cls_sub'] != '' else '[ Fundo ]' self.ids.reg_abertura.text = str(self.item_data['reg_abertura']) self.ids.reg_desativacao.text = str(self.item_data['reg_desativacao']) self.ids.reg_reativacao.text = str(self.item_data['reg_reativacao']) self.ids.reg_mudanca_nome.text = str(self.item_data['reg_mudanca_nome']) self.ids.reg_deslocamento.text = str(self.item_data['reg_deslocamento']) self.ids.reg_extincao.text = str(self.item_data['reg_extincao']) self.ids.ativa.state = 'down' if self.item_data['cls_indicador'] == 'Ativa' else 'normal' self.ids.inativa.state = 'normal' if self.item_data['cls_indicador'] == 'Ativa' else 'down' self.ids.fase_corrente.text = str(self.item_data['fase_corrente']) self.ids.evento_fase_corrente.text = str(self.item_data['evento_fase_corrente']) self.ids.fase_intermediaria.text = str(self.item_data['fase_intermediaria']) self.ids.evento_fase_inter.text = str(self.item_data['evento_fase_inter']) self.ids.preservacao.state = 'down' if self.item_data['dest_final'] == 'Preservação' else 'normal' self.ids.eliminacao.state = 'normal' if self.item_data['dest_final'] == 'Preservação' else 'down' self.ids.reg_alteracao.text = str(self.item_data['reg_alteracao']) self.ids.observacoes.text = str(self.item_data['observacoes']) def show_delete_dialog(self): """Create and open delete dialog popup""" btn_cancel = MDFlatButton( text = 'Cancelar', theme_text_color = 'Custom', text_color = self.app.theme_cls.primary_color, on_release = lambda x: self.delete_dialog.dismiss()) btn_confirm = MDRaisedButton( text = 'Apagar', elevation = 11, on_release = lambda *x: (self.delete_item_from_db(), self.delete_dialog.dismiss())) self.delete_dialog = MDDialog( title = 'Deseja realmente apagar?', text = f'{self.item_data["cls_nome"]}', buttons = [btn_cancel,btn_confirm], auto_dismiss = False) self.delete_dialog.open() def delete_item_from_db(self): """Try deleting item from database, if successful, deletes item from treeview""" try: delete_row(self.item_data) except lib.utils.ItemHasChildren: toast('Classe possui dependentes! Impossível apagar.') else: toast(f'{self.item_data["cls_nome"][:40]}{" [...]" if len(self.item_data["cls_nome"]) > 40 else ""} apagado com sucesso!',1) self.app.root.ids.data_frame.clear_widgets() ## clear data management frame self.app.pcd_tree.delete_node_from_tree() ## delete item from treeview def text_fields_into_dict(self): """Gets data from text fields into dict :return: dict""" data = { 'parentId': self.item_data['legacyId'] if not self.new_cls else 'zero', 'cls_nome': self.ids.cls_nome.text.strip(), 'cls_codigo': self.ids.cls_codigo.text.strip(), 'cls_sub': self.ids.cls_sub.text.strip() if not self.new_cls else '', 'reg_abertura': self.ids.reg_abertura.text.strip(), 'reg_desativacao': self.ids.reg_desativacao.text.strip(), 'reg_reativacao': self.ids.reg_reativacao.text.strip(), 'reg_mudanca_nome': self.ids.reg_mudanca_nome.text.strip(), 'reg_deslocamento': self.ids.reg_deslocamento.text.strip(), 'reg_extincao': self.ids.reg_extincao.text.strip(), 'cls_indicador': 'Ativa' if self.ids.ativa.state == 'down' else 'Inativa', 'fase_corrente': self.ids.fase_corrente.text.strip(), 'evento_fase_corrente': self.ids.evento_fase_corrente.text.strip(), 'fase_intermediaria': self.ids.fase_intermediaria.text.strip(), 'evento_fase_inter': self.ids.evento_fase_inter.text.strip(), 'dest_final': 'Preservação' if self.ids.preservacao.state == 'down' else 'Eliminação', 'reg_alteracao': self.ids.reg_alteracao.text.strip(), 'observacoes': self.ids.observacoes.text.strip()} return data def insert_data_into_db(self): """Try to insert data into database, if successful regen treeview with new data""" data = self.text_fields_into_dict() ## Current item data dict parent = self.item_data if not self.new_cls else 'zero' ## set parent data if not new cls if self.ids.cls_nome.text.strip() and self.ids.cls_codigo.text.strip() != '': ## if required fields are not empty try: ## Instantiate data manager object \/ to_insert = ManageData(item_data=data,parent_data=parent) if not self.editing: to_insert.insert_into_db() ## inserts into database else: to_insert.update_db() ## updates database except: toast('Algo deu errado! Impossível salvar a Classe.') else: toast('Classe salva com sucesso!',1) self.app.root.ids.data_frame.clear_widgets() ## clear data management frame self.app.pcd_tree.regen_tree() ## Regenerates pcd treeview self.app.pcd_tree.switch_button(reset=True) ## switch toggle nodes button self.app.pcd_tree.disabled = False ## Unlocks treeview else: ## if required fields are empty toast('Campos obrigatórios estão em branco!') self.ids.cls_codigo.focus = True if self.ids.cls_codigo.text.strip() == '' else False self.ids.cls_nome.focus = True if self.ids.cls_nome.text.strip() == '' else False
class AppFrame(FloatLayout): """ The core layout of the application, acts as the root widget and provides methods universal to all child widgets. """ btn_layout = kp.ObjectProperty(None) keybindings = kp.DictProperty({}) config = kp.DictProperty({}) def new_keybind_dialogue(self) -> None: """ Opens a NewBindDialogue pop up to get user input. :return: None """ nbd = NewBinding() self.add_widget(nbd) def name_bindset_dialogue(self, mode: str = 'Save') -> None: """ Opens a NameBindSet pop up to get user input. :param mode: A string, either 'Save' or 'Load'. :return: None """ sbs = NameBindSet(mode=mode) self.add_widget(sbs) def update_keybind(self, **options) -> None: """ Creates a new Keybind object or updates an existing one. :param options: kwargs. Main kwarg that update_keybind requires is name, a string specifying the user-supplied name of the keybind. :return: None """ bind_name = options.get('name') if self.keybindings.get(bind_name): self.keybindings[bind_name].setup(**options) else: new_btn = Keybind() new_btn.setup(**options) self.keybindings[bind_name] = new_btn self.btn_layout.add_widget(new_btn) @staticmethod def to_json(file_path: str, data: dict) -> None: """ Simple method to save a one line dictionary to a json file. :param file_path: A string, a valid file path. :param data: A dictionary. :return: None """ with open(file_path, 'w') as w: w.write(json.dumps(data)) @staticmethod def from_json(file_path: str) -> dict: """ Simple method to load a one line json into a python dictionary. :param file_path: A string, a file path. :return: A dictionary containing the json in file_path, or an empty dictionary if the file_path was invalid. """ if os.path.exists(file_path): with open(file_path, 'r') as r: for line in r: result = json.loads(line) return result else: return dict() def save(self, file_name: str) -> None: """ Saves all the Keybinds in keybindings as well as the values stored in config. :param file_name: A string, the name of the file to save to. :return: None """ result = dict() for k, v in self.keybindings.items(): result[k] = {**v.output()} self.to_json(f'bindsets/{file_name}.json', result) self.config['last_bindset'] = file_name self.save_config() def save_config(self) -> None: """ Saves the config dictionary to a json file called ref. :return: None """ self.to_json('ref.json', self.config) def load(self, file_name: str) -> bool: """ Loads a specified bindset from the bindsets directory and replaces the existing bindset with Keybinds corresponding to the new bindset. :param file_name: A valid file path. :return: A boolean indicating whether data was successfully retrieved from the passed file. """ p = f'bindsets/{file_name}.json' result = self.from_json(p) if len(result) > 0: self.btn_layout.clear_widgets() for k, v in result.items(): b = Keybind() b.setup(k, **v) self.keybindings[k] = b self.btn_layout.add_widget(b) return True else: return False
class RallyPoint(Building): attacker = kp.DictProperty(defaultdict(int)) defender = kp.DictProperty(defaultdict(int)) units_kills_atk = kp.DictProperty(defaultdict(int)) units_kills_def = kp.DictProperty(defaultdict(int)) def __init__(self): self.settings = BUILDINGS.get("RALLY_POINT") super().__init__() self.scavenging = self.settings.get("SCAVENGING") def calc_simulator(self, *args): print("simulator", args) attacker_inputs = args[0] attacker_inputs = list(reversed(attacker_inputs.children[:-1])) defender_inputs = args[1] defender_inputs = list(reversed(defender_inputs.children[:-1])) app = args[2] # attacker = defaultdict(int) attacker_power_per_type = defaultdict(int) total_defender_power_per_type = defaultdict( lambda: app.wall.basic_defense) defender_power_per_type = defaultdict(int) total_population_per_type = defaultdict(int) total_population_per_type_def = defaultdict(int) perc_population_per_type = defaultdict(int) _types = ["general", "cavalry", "archer"] # get input units: for i, unit in enumerate(app.units): try: self.attacker[unit] = int(attacker_inputs[i].text) except ValueError: self.attacker[unit] = 0 try: self.defender[unit] = int(defender_inputs[i].text) except ValueError: self.defender[unit] = 0 print("attacker", self.attacker) print("defender", self.defender) # calc total power done for all units per type: for i, unit in enumerate(app.units): attacker_power_per_type[ unit._type] += self.attacker[unit] * unit.atk for _type in _types: total_defender_power_per_type[_type] += self.defender[ unit] * unit.defence.get(_type.upper()) print("attacker_power_per_type", attacker_power_per_type) print("total_defender_power_per_type", total_defender_power_per_type) # calc total_population_per_type: for i, unit in enumerate(app.units): total_population_per_type[ unit._type] += self.attacker[unit] * unit.population total_population_per_type_def[ unit._type] += self.defender[unit] * unit.population print("total_population_per_type", total_population_per_type) print("total_population_per_type_def", total_population_per_type_def) # calc perc_population_per_type: total_all_types_population = sum(total_population_per_type.values()) try: for _type in _types: perc_population_per_type[_type] += total_population_per_type[ _type] / total_all_types_population except ZeroDivisionError: return print("perc_population_per_type", perc_population_per_type) # calc defender power after aply perc_population_per_type: for _type in _types: defender_power_per_type[_type] = total_defender_power_per_type[ _type] * perc_population_per_type[_type] print("defender_power_per_type", defender_power_per_type) # calc total_killed_units_per_type by type: total_killed_units_per_type = defaultdict(int) total_killed_units_per_type_def = defaultdict(int) for _type in _types: print(_type) if attacker_power_per_type[_type] == 0: continue if total_population_per_type[_type] == 0: continue x = attacker_power_per_type[_type] / defender_power_per_type[_type] x_defender = defender_power_per_type[ _type] / attacker_power_per_type[_type] print("x", x) print("x_defender", x_defender) ratio = 1 / x**0.5 ratio_defender = 1 / x_defender**0.5 print("ratio", ratio) print("ratio_defender", ratio_defender) damage_done_by_def = ratio * defender_power_per_type[_type] damage_done_by_atk = ratio_defender * attacker_power_per_type[_type] print("damage_done_by_def", damage_done_by_def) print("damage_done_by_atk", damage_done_by_atk) total_killed_units_per_type[_type] =\ damage_done_by_def / attacker_power_per_type[_type] * total_population_per_type[_type] total_killed_units_per_type_def[_type] =\ damage_done_by_atk / defender_power_per_type[_type] * total_population_per_type[_type] print("total_killed_units_per_type", total_killed_units_per_type) print("total_killed_units_per_type_def", total_killed_units_per_type_def) # calc units_kills: split the type % for all units for i, unit in enumerate(app.units): # attacker: try: ratio_units = (self.attacker[unit] * unit.population ) / total_population_per_type[unit._type] print("ratio_units", ratio_units) self.units_kills_atk[unit] = total_killed_units_per_type[ unit._type] * ratio_units / unit.population self.units_kills_atk[unit] = min( round(self.units_kills_atk[unit]), self.attacker[unit]) except ZeroDivisionError: continue # defender: try: ratio_units_def = ( self.defender[unit] * unit.population ) / total_population_per_type_def[unit._type] print("ratio_units_def", ratio_units_def) self.units_kills_def[unit] = total_killed_units_per_type_def[ unit._type] * ratio_units_def / unit.population self.units_kills_def[unit] = min( round(self.units_kills_def[unit]), self.defender[unit]) except ZeroDivisionError: continue print("self.units_kills_atk", self.units_kills_atk) print("self.units_kills_def", self.units_kills_def)
class GameApp(App): width = kp.NumericProperty(Window.width) height = kp.NumericProperty(Window.height) # offset = kp.NumericProperty() # resources: wood = kp.ObjectProperty(Resource("WOOD")) clay = kp.ObjectProperty(Resource("CLAY")) iron = kp.ObjectProperty(Resource("IRON")) population_icon = kp.StringProperty( RESOURCES.get("ICON").get("POPULATION")) resources_ratio = kp.NumericProperty(RESOURCES.get("RATIO")) population = kp.DictProperty({ "max": BUILDINGS.get("FARM").get("POPULATION_INIT"), "buildings": 0, "units": 0, "total": 0, }) # buildings: headquarters = kp.ObjectProperty(Headquarters()) rally_point = kp.ObjectProperty(RallyPoint()) statue = kp.ObjectProperty(Statue()) timber_camp = kp.ObjectProperty(TimberCamp()) clay_pit = kp.ObjectProperty(ClayPit()) iron_mine = kp.ObjectProperty(IronMine()) farm = kp.ObjectProperty(Farm()) warehouse = kp.ObjectProperty(Warehouse()) hiding_place = kp.ObjectProperty(HidingPlace()) barracks = kp.ObjectProperty(Barracks()) stable = kp.ObjectProperty(Stable()) workshop = kp.ObjectProperty(Workshop()) academy = kp.ObjectProperty(Academy()) smithy = kp.ObjectProperty(Smithy()) market = kp.ObjectProperty(Market()) wall = kp.ObjectProperty(Wall()) # to upgrade buildings: current_upgrading = kp.ObjectProperty("") time_left = kp.NumericProperty() time_eta = kp.ObjectProperty("") cancel = kp.BooleanProperty(False) is_upgrading = kp.BooleanProperty(False) # Units: spear_fighter = kp.ObjectProperty(Unit(name="SPEAR_FIGHTER")) swordsman = kp.ObjectProperty(Unit(name="SWORDSMAN")) axeman = kp.ObjectProperty(Unit(name="AXEMAN")) archer = kp.ObjectProperty(Unit(name="ARCHER")) scout = kp.ObjectProperty(Unit(name="SCOUT")) light_cavalry = kp.ObjectProperty(Unit(name="LIGHT_CAVALRY")) mounted_archer = kp.ObjectProperty(Unit(name="MOUNTED_ARCHER")) heavy_cavalry = kp.ObjectProperty(Unit(name="HEAVY_CAVALRY")) ram = kp.ObjectProperty(Unit(name="RAM")) catapult = kp.ObjectProperty(Unit(name="CATAPULT")) paladin = kp.ObjectProperty(Paladin()) noble = kp.ObjectProperty(Unit(name="NOBLE")) militia = kp.ObjectProperty(Unit(name="MILITIA")) def build_config(self, *args): self.units = [ self.spear_fighter, self.swordsman, self.axeman, self.archer, self.scout, self.light_cavalry, self.mounted_archer, self.heavy_cavalry, self.ram, self.catapult, self.paladin, self.noble, self.militia ] self.buildings = [ self.headquarters, self.rally_point, self.statue, self.timber_camp, self.clay_pit, self.iron_mine, self.farm, self.warehouse, self.hiding_place, self.barracks, self.stable, self.workshop, self.academy, self.smithy, self.market, self.wall ] def build(self): self.game = Game(transition=NoTransition()) self.resources = [self.wood, self.clay, self.iron] self.calc_current_population() Clock.schedule_interval(self.update_resources, .1) return self.game def calc_current_population(self): for building in self.buildings: self.population["buildings"] += building.population for unit in self.units: self.population["units"] += unit.n * unit.population self.population[ "total"] = self.population["buildings"] + self.population["units"] def upgrade_building(self, building): if self.is_upgrading: return # check if can upgrade: check_resources =\ self.wood.current > building.wood and \ self.clay.current > building.clay and self.iron.current > building.iron check_max_level = building.level < building.max_level if not (check_resources and check_max_level): return self.current_upgrading = building self.time_left = building.time self.time_eta = datetime.datetime.fromtimestamp( time.time() + self.time_left).strftime('%H:%M:%S') # update resources: self.wood.current -= self.current_upgrading.wood self.clay.current -= self.current_upgrading.clay self.iron.current -= self.current_upgrading.iron self.is_upgrading = True Clock.schedule_interval(self.update_building, .1) def update_building(self, dt): if self.cancel: # undo update resources: self.wood.current += self.current_upgrading.wood self.clay.current += self.current_upgrading.clay self.iron.current += self.current_upgrading.iron self.current_upgrading = "" self.time_left = 0 self.cancel = False self.is_upgrading = False return False self.time_left -= dt if self.time_left <= 0: self.update_building_finish() return False def update_building_finish(self): # update requirements: self.current_upgrading.level += 1 self.current_upgrading.update_cost_for_current_level() self.current_upgrading.update_population_for_current_level() self.calc_current_population() self.current_upgrading.time *= self.current_upgrading.ratio # update buildings: if self.current_upgrading.name == "headquarters": for build in self.buildings: build.time *= self.current_upgrading.time_reduce if self.current_upgrading.name == "timber_camp": self.wood.per_s *= self.resources_ratio if self.current_upgrading.name == "clay_pit": self.clay.per_s *= self.resources_ratio if self.current_upgrading.name == "iron_mine": self.iron.per_s *= self.resources_ratio if self.current_upgrading.name == "farm": self.population["max"] *= self.farm.population_ratio self.current_upgrading = "" self.is_upgrading = False def cancel_upgrading(self, *args): if self.is_upgrading: self.cancel = True def update_resources(self, dt): for resource in self.resources: resource.current += resource.per_s * dt resource.current = min(resource.current, self.warehouse.max_capacity)
class GameWidget(Screen): app = prop.ObjectProperty() game = prop.ObjectProperty() player_name = prop.StringProperty() current_turn_author = prop.StringProperty() player_widgets = prop.DictProperty() deck_widget = prop.ObjectProperty() pending_actions = [] player_tab_title = '* You *' def __init__(self, game, **kwargs): super(GameWidget, self).__init__(**kwargs) self.game = game self.player_name = self.app.player_name self.player_widgets = {player.name: player.make_widget(game_widget=self) \ for player in self.game.get_category(game_component_types.PLAYER).itervalues()} self.add_player_widget(self.player_widgets[self.player_name]) for widget in self.player_widgets.itervalues(): if widget.player.name != self.player_name: self.add_player_widget(widget) deck_zone = self.ids.deck_zone self.deck_widget = self.game.get_category( game_component_types.DECK).values()[0].make_widget( game_widget=self) deck_zone.add_widget(self.deck_widget) self.update_current_turn_author() def update_current_turn_author(self): self.current_turn_author = self.game.current_flow._author def is_our_turn(self): #print("Current player: {0}".format(self.game.current_flow._author)) return self.player_name == self.current_turn_author def is_our_tab_active(self): #print("Active tab: {0}".format(self.ids.player_zone.current_tab.text)) return self.ids.player_zone.current_tab.text == self.player_tab_title def add_player_widget(self, widget): caption = self.player_tab_title if widget.player.name == self.player_name else widget.player.name tab = tabbedpanel.TabbedPanelItem(text=caption) tab.add_widget(widget=widget) self.ids.player_zone.add_widget(tab) def queue_action(self, action): self.pending_actions.append(action) print(self.pending_actions) def send_actions(self, *actions): for action in actions: msg = action.make_message() self.app.send_action(msg) def push_game_forward(self, action): self.game.receive_message(action) self.update_current_turn_author() def notify(self, text): self.app.notify(text)
class mainwidget(FloatLayout): #flags=-1 represents game not started and only black can press since white starts pause_flag=1 white_time=kv.DictProperty({'hour':'0','minute':'5','second':'0'}) # dictionary to hold time of white and black black_time=kv.DictProperty({'hour':'0','minute':'5','second':'0'}) white_string=kv.StringProperty('0:5:0') black_string=kv.StringProperty("0:5:0") #strings which contain display of white and black time def __init__(self): super(mainwidget, self).__init__() self.flags=-1 def refresher(self): Clock.unschedule(self.decrease_time_default_white) Clock.unschedule(self.decrease_time_default_black) self.flags=-1 self.white_time={'hour':'0','minute':'5','second':'0'} self.black_time={'hour':'0','minute':'5','second':'0'} self.white_string='0:5:0' #used to set times to initial state self.black_string="0:5:0" def pauser(self): # used to pause the clock if(self.pause_flag==1): # if flag 1 then clock is ticking if(self.flags==1): Clock.unschedule(self.decrease_time_default_white) # unschedule white flags=1 represents white time is going elif(self.flags==0): # unschedule black flags=1 represents black time is going Clock.unschedule(self.decrease_time_default_black) labels=self.ids['pause_button'] labels.text="resume" #interchange between resume and pause self.pause_flag=0 elif(self.pause_flag==0): # if flag=0 clock is paused either side it remains constant if(self.flags==1): Clock.schedule_interval(self.decrease_time_default_white,1) # resume time if move belongs to white elif(self.flags==0): Clock.schedule_interval(self.decrease_time_default_black,1) labels=self.ids['pause_button'] labels.text="pause" #interchange the name self.pause_flag=1 def decrease_time_default_black(self,dt): self.black_time['second']=str(int(self.black_time['second'])-1) if(int(self.black_time['second'])<0): self.black_time['minute']=str(int(self.black_time['minute'])-1) self.black_time['second']=str(int(self.black_time['second'])+60) #decrease the time in black by 1 sec if(int(self.black_time['minute'])<0): self.black_time['hour']=str(int(self.black_time['hour'])-1) self.black_time['minute']=str(int(self.black_time['minute'])+60) self.black_string=self.black_time['hour']+':'+self.black_time['minute']+':'+self.black_time['second'] # update in the string def decrease_time_default_white(self,dt): self.white_time['second']=str(int(self.white_time['second'])-1) if(int(self.white_time['second'])<0): self.white_time['minute']=str(int(self.white_time['minute'])-1) self.white_time['second']=str(int(self.white_time['second'])+60) #decrease the time in black by 1 sec if(int(self.white_time['minute'])<0): self.white_time['hour']=str(int(self.white_time['hour'])-1) self.white_time['hour']=str(int(self.white_time['hour'])+60) self.white_string=self.white_time['hour']+':'+self.white_time['minute']+':'+self.white_time['second'] def click_setter_black(self): white=self.ids['white'] #if clicked on black black=self.ids['black'] if(self.flags ==-1): # beginning of the game white.background_color=[1,1,1,1] #running color black.background_color=[0,1,0,1] #dormant color self.flags=1 Clock.schedule_interval(self.decrease_time_default_white,1) print(self.white_string) elif(self.flags==0): # if black presses and its his turn white.background_color=[1,1,1,1] black.background_color=[0,1,0,1] self.flags=1 Clock.unschedule(self.decrease_time_default_black) Clock.schedule_interval(self.decrease_time_default_white,1) def click_setter_white(self): # similar to black white=self.ids['white'] black=self.ids['black'] if(self.flags==1): white.background_color=[0,1,0,1] black.background_color=[1,1,1,1] self.flags=0 Clock.unschedule(self.decrease_time_default_white) Clock.schedule_interval(self.decrease_time_default_black,1)
class SecondScreen(Screen): #flags=-1 represents game not started and only black can press since white starts pause_flag=1 white_time_init=kv.DictProperty({'hour':'0','minute':'5','second':'00'}) # dictionary to hold time of white and black black_time_init=kv.DictProperty({'hour':'0','minute':'5','second':'00'}) increment_white_time=kv.DictProperty({'hour':'0','minute':'0','second':'02'}) increment_black_time=kv.DictProperty({'hour':'0','minute':'0','second':'02'}) white_time=kv.DictProperty({'hour':'0','minute':'5','second':'00'}) # dictionary to hold time of white and black black_time=kv.DictProperty({'hour':'0','minute':'5','second':'00'}) white_string=kv.StringProperty('5:00') black_string=kv.StringProperty("5:00") #strings which contain display of white and black time flags=-1 def __init__(self, **kw): super().__init__(**kw) df=pd.read_csv("helo.csv") #elf.pause_flag=int(df.loc[0]['pause_flag']) # fields=['flags','pause_flag','white_string','black_string','increment_white','increment_black'] self.white_time=string_to_dict(df.loc[0]['white_string']) self.black_time=string_to_dict(df.loc[0]['black_string']) self.white_string=df.loc[0]['white_string'] self.black_string=df.loc[0]['black_string'] self.white_time_init=string_to_dict(df.loc[0]['init_white']) self.black_time_init=string_to_dict(df.loc[0]['init_black']) self.increment_white_time=string_to_dict(df.loc[0]['increment_white']) self.increment_black_time_=string_to_dict(df.loc[0]['increment_black']) self.flags=df.loc[0]['flags'] def value_time(self,dict): return int(dict['second'])+int(dict['minute'])*60+int(dict['hour'])*3600 def increment_setter(self,dict1,dict2): self.increment_white_time=dict1 self.increment_black_time=dict2 def new_value_setter(self,dict1,dict2): self.flags=-1 self.pause_flag=0 self.white_time_init=dict1 self.black_time_init=dict2 self.white_time=dict1 self.black_time=dict2 self.white_string=format_time(self.white_time) self.black_string=format_time(self.black_time) white=self.ids['white'] black=self.ids['black'] white.background_color=[0,1,1,1] black.background_color=[0,1,1,1] def refresher(self): self.exit_pauser() pop_layout=BoxLayout() popup=Popup(title="Are u sure u want to refresh",content=pop_layout) pop_label=Label(text="Refresh will make \n current time lost",font_size=50,color=[1,0.7,0.435,1],halign='right',valign='middle') q=BoxLayout(orientation="horizontal") yes_button=Button(text="yes",size_hint=(0.6,0.2)) no_button=Button(text="no",size_hint=(0.6,0.2)) def out(instance): Clock.unschedule(self.decrease_time_default_white) Clock.unschedule(self.decrease_time_default_black) self.flags=-1 self.pause_flag=1 labels=self.ids['pause_button'] labels.text="pause" self.white_time=self.white_time_init self.black_time=self.black_time_init self.white_string=format_time(self.white_time) self.black_string=format_time(self.black_time) white=self.ids['white'] black=self.ids['black'] white.background_color=[0,1,1,1] black.background_color=[0,1,1,1] popup.dismiss() yes_button.bind(on_press=out) no_button.bind(on_press=lambda x:popup.dismiss()) pop_layout.add_widget(pop_label) q.add_widget(yes_button) q.add_widget(no_button) pop_layout.add_widget(q) popup.open() def exit_pauser(self): if(self.pause_flag==1): # if flag 1 then clock is ticking if(self.flags==1): Clock.unschedule(self.decrease_time_default_white) # unschedule white flags=1 represents white time is going elif(self.flags==0): # unschedule black flags=1 represents black time is going Clock.unschedule(self.decrease_time_default_black) labels=self.ids['pause_button'] labels.text="resume" #interchange between resume and pause self.pause_flag=0 def pauser(self): # used to pause the clock if(self.pause_flag==1): # if flag 1 then clock is ticking if(self.flags==1): Clock.unschedule(self.decrease_time_default_white) # unschedule white flags=1 represents white time is going elif(self.flags==0): # unschedule black flags=1 represents black time is going Clock.unschedule(self.decrease_time_default_black) labels=self.ids['pause_button'] labels.text="resume" #interchange between resume and pause self.pause_flag=0 elif(self.pause_flag==0): # if flag=0 clock is paused either side it remains constant if(self.flags==1): Clock.schedule_interval(self.decrease_time_default_white,1) # resume time if move belongs to white elif(self.flags==0): Clock.schedule_interval(self.decrease_time_default_black,1) labels=self.ids['pause_button'] labels.text="pause" #interchange the name self.pause_flag=1 def decrease_time_default_black(self,dt): if(self.value_time(self.black_time)==0): white=self.ids['black'] white.background_color=[1,0,0,1] self.flags=-2 return self.black_time['second']=str(int(self.black_time['second'])-1) if(int(self.black_time['second'])<0): self.black_time['minute']=str(int(self.black_time['minute'])-1) self.black_time['second']=str(int(self.black_time['second'])+60) #decrease the time in black by 1 sec if(int(self.black_time['minute'])<0): self.black_time['hour']=str(int(self.black_time['hour'])-1) self.black_time['minute']=str(int(self.black_time['minute'])+60) self.black_string=format_time(self.black_time) # update in the string def incrementer_black(self): self.black_time['second']=str(int(self.black_time['second'])+int(self.increment_black_time['second'])) self.black_time['minute']=str(int(self.black_time['minute'])+int(self.increment_black_time['minute'])) self.black_time['hour']=str(int(self.black_time['hour'])+int(self.increment_black_time['hour'])) seconder=int(self.black_time['second'])%60 minuter=int(int(self.black_time['second'])/60)+int(self.black_time['minute']) hourer=int(self.black_time['hour'])+int(minuter/60) minuter=minuter%60 hourer=hourer%24 self.black_time['hour']=str(hourer) self.black_time['minute']=str(minuter) self.black_time['second']=str(seconder) self.black_string=format_time(self.black_time) def incrementer_white(self): self.white_time['second']=str(int(self.white_time['second'])+int(self.increment_white_time['second'])) self.white_time['minute']=str(int(self.white_time['minute'])+int(self.increment_white_time['minute'])) self.white_time['hour']=str(int(self.white_time['hour'])+int(self.increment_white_time['hour'])) seconder=int(self.white_time['second'])%60 minuter=int(int(self.white_time['second'])/60)+int(self.white_time['minute']) hourer=int(self.white_time['hour'])+int(minuter/60) minuter=minuter%60 hourer=hourer%24 self.white_time['hour']=str(hourer) self.white_time['minute']=str(minuter) self.white_time['second']=str(seconder) self.white_string=format_time(self.white_time) def decrease_time_default_white(self,dt): if(self.value_time(self.white_time)==0): white=self.ids['white'] white.background_color=[1,0,0,1] self.flags=2 return self.white_time['second']=str(int(self.white_time['second'])-1) if(int(self.white_time['second'])<0): self.white_time['minute']=str(int(self.white_time['minute'])-1) self.white_time['second']=str(int(self.white_time['second'])+60) #decrease the time in black by 1 sec if(int(self.white_time['minute'])<0): self.white_time['hour']=str(int(self.white_time['hour'])-1) self.white_time['minute']=str(int(self.white_time['minute'])+60) self.white_string=format_time(self.white_time) def click_setter_black(self ): white=self.ids['white'] #if clicked on black black=self.ids['black'] if(self.flags ==-1 and self.value_time(self.black_time)>0 and self.pause_flag==1): # beginning of the game white.background_color=[1,1,1,1] #running color black.background_color=[0,1,0,1] #dormant color self.flags=1 Clock.schedule_interval(self.decrease_time_default_white,1) print(self.white_string) elif(self.flags ==-1 and self.value_time(self.black_time)==0 and self.pause_flag==1): black.background_color=[1,0,0,1] white.background_color=[1,0,0,1] self.flags=-2 Clock.unschedule(self.decrease_time_default_black) Clock.unschedule(self.decrease_time_default_white) elif(self.flags==0 and self.value_time(self.black_time)>0 and self.pause_flag==1): # if black presses and its his turn white.background_color=[1,1,1,1] black.background_color=[0,1,0,1] self.flags=1 self.incrementer_black() Clock.unschedule(self.decrease_time_default_black) Clock.schedule_interval(self.decrease_time_default_white,1) elif(self.flags==0 and self.value_time(self.black_time)==0 and self.pause_flag==1): white.background_color=[0,1,1,1] black.background_color=[1,0,0,1] self.flags=-2 Clock.unschedule(self.decrease_time_default_black) Clock.unschedule(self.decrease_time_default_white) def click_setter_white(self): # similar to black white=self.ids['white'] black=self.ids['black'] if(self.flags==1 and self.value_time(self.white_time)>0 and self.pause_flag==1): white.background_color=[0,1,0,1] black.background_color=[1,1,1,1] self.flags=0 self.incrementer_white() Clock.unschedule(self.decrease_time_default_white) Clock.schedule_interval(self.decrease_time_default_black,1) elif(self.flags==1 and self.value_time(self.white_time)==0 and self.pause_flag==1): white.background_color=[1,0,0,1] black.background_color=[0,1,1,1] self.flags=2 Clock.unschedule(self.decrease_time_default_black) Clock.unschedule(self.decrease_time_default_white)
class GameApp(App): points = kp.NumericProperty(settings.POINTS["game"]["init"]) languages = kp.ListProperty(["", ""]) words = kp.ListProperty() number_of_words = kp.NumericProperty() current_word = kp.DictProperty() last_word = kp.DictProperty() def build(self): Window.size = (400, 600) self.meta_game = MetaGame() self.bind(words=self.calc_number_of_words) return self.meta_game def add_languages(self, lang1, lang2): self.languages = [lang1, lang2] def add_word(self, word1, word2): # print("add_word(%s, %s)" % (word1, word2)) new_word = {self.languages[0]: word1, self.languages[1]: word2} new_word["points"] = settings.POINTS["word"]["init"] self.words.append(new_word) def delete_word(self, word_to_delete="", language=""): # print("delete_word()", word_to_delete, language) # word_to_delete could be a string or a dict/obj if not language: language = self.languages[0] if not isinstance(word_to_delete, str): word_to_delete = word_to_delete[language] for word in self.words: if word[language] == word_to_delete: self.words.remove(word) return def calc_number_of_words(self, *args): # print("number_of_words()", args) self.number_of_words = len(self.words) return self.number_of_words def pick_random_word(self, lang1="", lang2=""): print("\npick_random_word(%s, %s)" % (lang1, lang2)) if not lang1: lang1 = self.languages[0] if not lang2: lang2 = self.languages[1] if lang1 not in self.languages or lang2 not in self.languages or lang1 == lang2: raise Exception("please insert a valid languages not: %s and %s" % (lang1, lang2)) if len(self.words) == 1: return self.words[0] # calc n_of_words_to_choose_from # it depends of the points, more points -> more degree -> more difficult # if the degree is 0 all the words have the same prob to appear # if the degree is high, will always appear the same words (with less points) n_of_words_to_choose_from = self.number_of_words print("n_of_words_to_choose_from: %s" % n_of_words_to_choose_from) degree = int(self.points / 100) print("degree: %s" % degree) for _ in range(degree): n_of_words_to_choose_from = max( random.randrange(n_of_words_to_choose_from) + 1, 2) print("n_of_words_to_choose_from: %s" % n_of_words_to_choose_from) self.order_by("points") print("self.words:", self.words) possible_words_to_choose = self.words[0:n_of_words_to_choose_from] print("possible_words_to_choose", possible_words_to_choose) word_choosed = random.choice(possible_words_to_choose) print(word_choosed, self.last_word) print(word_choosed[self.languages[0]], self.last_word.get(self.languages[0], "")) if word_choosed[self.languages[0]] == self.last_word.get( self.languages[0], ""): print("word_choosed == self.last_word") possible_words_to_choose.remove(word_choosed) word_choosed = random.choice(possible_words_to_choose) return word_choosed def check_solution(self, word1, word2): print("self.languages", self.languages) for word in self.words: print("word", word) if word[self.languages[0]] == word1: correct_word = word[self.languages[1]] correct_word = correct_word.split(", ") # print("correct_word: %s" % correct_word) correct_word = [word.lower() for word in correct_word] if word2 and word2.lower() in correct_word: # print("gain", correct_word == word2, word2 in correct_word) return True, word else: # print("lose", correct_word) return False, word def update_word_points(self, word1, word2): # print("update_word_points(%s, %s)" % (word1, word2)) increase_rate = settings.POINTS["word"]["increase_rate"] decreased_rate = settings.POINTS["word"]["decreased_rate"] is_correct, word = self.check_solution(word1, word2) if is_correct: word["points"] *= increase_rate else: word["points"] /= decreased_rate return word def update_points(self, word1, word2): print("update_points()", self.points) down4right_words = settings.POINTS["game"]["down4right_words"] up4wrong_words_a = settings.POINTS["game"]["up4wrong_words_a"] up4wrong_words_b = settings.POINTS["game"]["up4wrong_words_b"] is_correct, _ = self.check_solution(word1, word2) if is_correct: increment = up4wrong_words_a / (self.points + up4wrong_words_b) self.points += increment else: self.points -= self.points / down4right_words def order_by(self, what, reverse=False): print("order_by(%s, %s)" % (what, reverse)) # print(self.words) if what in ["points"]: self.words =\ sorted(self.words, key=lambda x: float(x[what]), reverse=reverse) else: self.words =\ sorted(self.words, key=lambda x: strip_accents(x[what]), reverse=reverse) # print(self.words) return self.words # GUI: def update_word_after_check(self, word1, word2): print("update_word_after_check(%s, %s)" % (word1, word2)) # print("self.current_word: %s" % self.current_word) self.current_word = self.update_word_points(word1, word2) self.update_points(word1, word2) # print("self.current_word: %s" % self.current_word) game_menu = self.meta_game.manager.game_menu game_menu.points_label.text = "Word Points: %s" % round( self.current_word["points"], 2) game_menu.word_input.text = str(self.current_word[self.languages[1]]) self.save_game() def update_word(self): print("update_word()", self.current_word) self.last_word = self.current_word.copy() print("self.last_word:", self.last_word) self.current_word = self.pick_random_word() print("self.current_word:", self.current_word) game_menu = self.meta_game.manager.game_menu game_menu.points_label.text = "Word Points: %s" % round( self.current_word["points"], 2) game_menu.word_label.text = self.current_word[self.languages[0]] game_menu.word_input.text = "" def quit(self): print("quit()") print(self.meta_game.manager.current) print(self.meta_game.manager.current_screen.previous_screen) previous_screen = self.meta_game.manager.current_screen.previous_screen if previous_screen: self.meta_game.manager.current = previous_screen else: exit() # load / save game: def load_game(self): try: with open(settings.SAVES_FILE) as f: data = json.load(f) self.points = data["points"] self.languages = data["languages"] self.words = data["words"] self.calc_number_of_words() except FileNotFoundError: pass def save_game(self): with open(settings.SAVES_FILE, "w") as f: data = { "points": self.points, "languages": self.languages, "words": self.words } json.dump(data, f, indent=4)