diff --git a/game/combat/__init__.py b/game/combat/__init__.py index c35ef333..04720536 100644 --- a/game/combat/__init__.py +++ b/game/combat/__init__.py @@ -573,6 +573,10 @@ def __init__(self, camp: gears.GearHeadCampaign): pbge.my_state.view.anim_list.append(pbge.scenes.animobs.MoveModel(pc, pc.pos, dest, speed=0.5)) pbge.my_state.view.handle_anim_sequence() + for m in camp.scene.contents: + if hasattr(m, "hidden") and m.hidden: + m.hidden = False + class Combat(object): def __init__(self, camp: gears.GearHeadCampaign): diff --git a/game/content/ghplots/lancedev.py b/game/content/ghplots/lancedev.py index af23294a..b1e53fb9 100644 --- a/game/content/ghplots/lancedev.py +++ b/game/content/ghplots/lancedev.py @@ -220,7 +220,8 @@ def METROSCENE_ENTER(self,camp): mymenu.add_item("Wait a minute- Who do you think the boss of this lance is?", self._question_mission) act = mymenu.query() - act(camp) + if act: + act(camp) def _start_mission(self, camp): pbge.alert("You rush to intercept the bandits before they can reach the convoy.") @@ -236,7 +237,8 @@ def _question_mission(self, camp): mymenu.add_item("We reject the mission. There are other things we need to do right now.", self._deny_mission) act = mymenu.query() - act(camp) + if act: + act(camp) def _grudgingly_start_mission(self, camp): pbge.alert("You go to intercept the bandits before they can reach the convoy. Hopefully you are not too late.") diff --git a/game/content/ghplots/multimission.py b/game/content/ghplots/multimission.py index 33dd9f11..b73f55b5 100644 --- a/game/content/ghplots/multimission.py +++ b/game/content/ghplots/multimission.py @@ -220,6 +220,9 @@ def call_stage(self, camp, mmission): dest(camp) elif mmission.elements.get("ONE_SHOT", True): mmission._lose_mission(camp) + else: + dest = mymenu.get_current_item() + dest(camp) class MultiMission(Plot): diff --git a/game/exploration.py b/game/exploration.py index 5d4b4c4b..da232b0c 100644 --- a/game/exploration.py +++ b/game/exploration.py @@ -738,8 +738,9 @@ def go(self): pc = self.scene.get_main_actor(self.view.mouse_tile) ExploMenu(self, pc) - if not self.no_quit: - self.camp.save() + if pbge.my_state.got_quit or not self.no_quit: + if self.camp.egg: + self.camp.save() else: self.camp.check_trigger("EXIT") diff --git a/game/fieldhq/backpack.py b/game/fieldhq/backpack.py index d04d6e14..6ddb35e9 100644 --- a/game/fieldhq/backpack.py +++ b/game/fieldhq/backpack.py @@ -9,22 +9,6 @@ PC_SWITCH_AREA = pbge.frects.Frect(-300, 100, 220, 100) -class CreditsBlock(object): - def __init__(self, camp: gears.GearHeadCampaign, font=None, width=220, **kwargs): - self.camp = camp - self.width = width - self.font = font or pbge.SMALLFONT - self.update() - self.height = self.image.get_height() - - def update(self): - self.image = pbge.render_text( - self.font, '${}'.format(self.camp.credits), self.width, justify=0, color=pbge.INFO_GREEN - ) - - def render(self, x, y): - self.update() - pbge.my_state.screen.blit(self.image, pygame.Rect(x, y, self.width, self.height)) class SwitchNameBlock(object): @@ -78,7 +62,7 @@ def render(self, x, y): class BackpackSwitchIP(gears.info.InfoPanel): - DEFAULT_BLOCKS = (SwitchNameBlock, CreditsBlock, SwitchEncumberanceBlock) + DEFAULT_BLOCKS = (SwitchNameBlock, gears.info.CreditsBlock, SwitchEncumberanceBlock) class InvItemWidget(widgets.Widget): @@ -94,12 +78,14 @@ def __init__(self, item, bp, show_parent=False, **kwargs): self.text = '{} [{}]'.format(str(item), str(item.parent)) else: self.text = item.get_full_name() - super(InvItemWidget, self).__init__(0, 0, INVENTORY_COLUMN.w, pbge.MEDIUMFONT.get_linesize(), **kwargs) + super().__init__(0, 0, INVENTORY_COLUMN.w, pbge.MEDIUMFONT.get_linesize(), **kwargs) def render(self, flash=False): mydest = self.get_rect() if flash or (self is self.bp.active_item): color = pbge.INFO_HILIGHT + elif self.item.is_destroyed(): + color = pbge.ENEMY_RED else: color = pbge.INFO_GREEN pbge.draw_text(pbge.MEDIUMFONT, self.text, mydest, color=color) @@ -358,8 +344,9 @@ def this_item_was_selected(self, wid, ev): def render(self, flash=False): if self.active_item: if self.active_item.item not in self.info_cache: - self.info_cache[self.active_item.item] = gears.info.get_longform_display(self.active_item.item, - width=INFO_COLUMN.w) + self.info_cache[self.active_item.item] = gears.info.get_longform_display( + self.active_item.item, width=INFO_COLUMN.w + ) mydest = INFO_COLUMN.get_rect() self.info_cache[self.active_item.item].render(mydest.x, mydest.y) diff --git a/game/shopui/__init__.py b/game/shopui/__init__.py index b2265092..f7062502 100644 --- a/game/shopui/__init__.py +++ b/game/shopui/__init__.py @@ -166,6 +166,13 @@ def render(self, x, y): ############################################################################### +class CustomerPanelIP(gears.info.InfoPanel): + DEFAULT_BLOCKS = (gears.info.NameBlock, gears.info.CreditsBlock, gears.info.EncumberanceBlock) + +class NoCustomerPanelIP(gears.info.InfoPanel): + DEFAULT_BLOCKS = (gears.info.CreditsBlock, ) + + class CustomerPanel(object): ''' Displays the customer and the money money money. @@ -174,6 +181,8 @@ def __init__(self, camp, customer_manager): self.camp = camp self.customer_manager = customer_manager self._portraits = dict() + self._infopanels = dict() + self._no_customer_ip = NoCustomerPanelIP(draw_border=False, width=CUSTOMER_PANEL_FRECT.w-100, camp=self.camp) def render(self): myrect = CUSTOMER_PANEL_FRECT.get_rect() @@ -182,16 +191,22 @@ def render(self): if customer: if customer not in self._portraits: self._portraits[customer] = customer.get_portrait() + if customer not in self._infopanels: + self._infopanels[customer] = CustomerPanelIP(draw_border=False, width=myrect.w-100, model=customer, camp=self.camp) self._portraits[customer].render(myrect, 1) myrect.x += 100 myrect.w -= 100 + ip = self._infopanels[customer] customertext = customer.name + '\n' else: customertext = '' - pbge.draw_text( pbge.MEDIUMFONT - , '{} ${:,}'.format(customertext, self.camp.credits) - , myrect - ) + ip = self._no_customer_ip + + ip.render(myrect.x, myrect.y) + #pbge.draw_text( pbge.MEDIUMFONT + # , '{} ${:,}'.format(customertext, self.camp.credits) + # , myrect + # ) ############################################################################### diff --git a/gears/__init__.py b/gears/__init__.py index e7cdb026..2ac19ee5 100644 --- a/gears/__init__.py +++ b/gears/__init__.py @@ -303,6 +303,11 @@ def get_tile_info(self, view: pbge.scenes.viewer.SceneView): elif pbge.my_state.view.waypointmap.get(pos): wp = pbge.my_state.view.waypointmap.get(pos) return info.ListDisplay(items=wp, view=view, view_pos=pos) + elif pbge.my_state.view.modelmap.get(pos): + items = [i for i in pbge.my_state.view.modelmap.get(pos) if not isinstance(i, base.Combatant)] + if items: + return info.ListDisplay(items=items, view=view, view_pos=pos) + def place_actor(self, actor, x0, y0, team=None): entry_points = pbge.scenes.pfov.MModeReach(self.environment.LEGAL_MOVEMODES[0], self, x0, y0, 5, True).tiles diff --git a/gears/eggs.py b/gears/eggs.py index 5e1e3a7a..d04c304a 100644 --- a/gears/eggs.py +++ b/gears/eggs.py @@ -58,6 +58,11 @@ def _remove_campdata_for(self, thing, cdat_rec): for sc in thing.inv_com: self._remove_campdata_for(sc, cdat_rec) + def _remove_hidden_for(self, thing, hidden_rec): + if hasattr(thing, "hidden") and thing.hidden: + hidden_rec.add(thing) + thing.hidden = False + def _reset_container_for(self, thing, con_rec): if thing in con_rec: con_rec[thing].append(thing) @@ -71,17 +76,25 @@ def _reset_campdata_for(self, thing, cdat_rec): for sc in thing.inv_com: self._reset_campdata_for(sc, cdat_rec) + def _reset_hidden_for(self, thing, hidden_rec): + if thing in hidden_rec: + thing.hidden = True + def write(self, f): # Save a record of all the containers. con_rec = dict() cdat_rec = dict() + hidden_rec = set() self._remove_container_for(self.pc, con_rec) self._remove_container_for(self.mecha, con_rec) + self._remove_hidden_for(self.pc, hidden_rec) + self._remove_hidden_for(self.mecha, hidden_rec) self._remove_campdata_for(self.pc, cdat_rec) self._remove_campdata_for(self.mecha, cdat_rec) for npc in list(self.dramatis_personae): self._remove_container_for(npc, con_rec) self._remove_campdata_for(npc, cdat_rec) + self._remove_hidden_for(npc, hidden_rec) if npc.is_destroyed(): self.dramatis_personae.remove(npc) pickle.dump(self, f, 4) @@ -89,9 +102,12 @@ def write(self, f): self._reset_container_for(self.mecha, con_rec) self._reset_campdata_for(self.pc, cdat_rec) self._reset_campdata_for(self.mecha, cdat_rec) + self._reset_hidden_for(self.pc, hidden_rec) + self._reset_hidden_for(self.mecha, hidden_rec) for npc in self.dramatis_personae: self._reset_container_for(npc, con_rec) self._reset_campdata_for(npc, cdat_rec) + self._reset_hidden_for(npc, hidden_rec) def save(self, sfpat='egg_{}.sav'): self._validate_dramatis_personae() diff --git a/gears/info.py b/gears/info.py index 8c517e6b..677bdd4d 100644 --- a/gears/info.py +++ b/gears/info.py @@ -11,7 +11,7 @@ class InfoPanel(object): # can't be pickled! Instead create the info panel anew as needed. DEFAULT_BLOCKS = list() - def __init__(self, padding=3, draw_border=True, view=None, view_pos=(0,0), border_style=pbge.default_border, + def __init__(self, padding=3, draw_border=True, view=None, view_pos=(0, 0), border_style=pbge.default_border, **kwargs): self.padding = padding self.info_blocks = list() @@ -71,7 +71,7 @@ def view_display(self, camp): else: x, y = self.view.foot_coords(*self.view_pos) y -= 64 - myrect.midbottom = (x,y) + myrect.midbottom = (x, y) myrect.clamp_ip(pbge.my_state.screen.get_rect()) self.render(myrect.left, myrect.top) @@ -263,7 +263,8 @@ def render(self, x, y): mydest = pygame.Rect(x + 83, y, field_width, self.height) if show_numbers: - pbge.draw_text(pbge.SMALLFONT, 'H:{}'.format(self.model.current_health), mydest.inflate(8,0), justify=-1, color=pbge.INFO_GREEN) + pbge.draw_text(pbge.SMALLFONT, 'H:{}'.format(self.model.current_health), mydest.inflate(8, 0), + justify=-1, color=pbge.INFO_GREEN) else: pbge.draw_text(pbge.SMALLFONT, 'H:', mydest, justify=-1, color=pbge.INFO_GREEN) maxi = self.model.max_health @@ -278,7 +279,8 @@ def render(self, x, y): mydest.x += field_width + 5 if show_numbers: - pbge.draw_text(pbge.SMALLFONT, 'M:{}'.format(self.model.get_current_mental()), mydest.inflate(8,0), justify=-1, color=pbge.INFO_GREEN) + pbge.draw_text(pbge.SMALLFONT, 'M:{}'.format(self.model.get_current_mental()), mydest.inflate(8, 0), + justify=-1, color=pbge.INFO_GREEN) else: pbge.draw_text(pbge.SMALLFONT, 'M:', mydest, justify=-1, color=pbge.INFO_GREEN) maxi = self.model.get_max_mental() @@ -293,7 +295,8 @@ def render(self, x, y): mydest.x += field_width + 5 if show_numbers: - pbge.draw_text(pbge.SMALLFONT, 'S:{}'.format(self.model.get_current_stamina()), mydest.inflate(8,0), justify=-1, color=pbge.INFO_GREEN) + pbge.draw_text(pbge.SMALLFONT, 'S:{}'.format(self.model.get_current_stamina()), mydest.inflate(8, 0), + justify=-1, color=pbge.INFO_GREEN) else: pbge.draw_text(pbge.SMALLFONT, 'S:', mydest, justify=-1, color=pbge.INFO_GREEN) maxi = self.model.get_max_stamina() @@ -348,7 +351,8 @@ def __init__(self, odds, modifiers, width=220, **kwargs): self.height = pbge.SMALLFONT.get_linesize() * 3 def render(self, x, y): - pbge.draw_text(pbge.my_state.huge_font, '{}%'.format(max(min(int(self.odds * 100), 99), 1)), pygame.Rect(x, y, 75, 32), + pbge.draw_text(pbge.my_state.huge_font, '{}%'.format(max(min(int(self.odds * 100), 99), 1)), + pygame.Rect(x, y, 75, 32), justify=0, color=pbge.INFO_HILIGHT) pbge.draw_text(pbge.my_state.big_font, 'TO HIT', pygame.Rect(x, y + pbge.my_state.huge_font.get_linesize(), 75, 32), justify=0, @@ -914,6 +918,60 @@ def render(self, x, y): pbge.draw_text(self.font, "Armor: 0/0", mydest, color=pbge.INFO_GREEN, justify=0) +class CreditsBlock(object): + def __init__(self, camp, font=None, width=220, **kwargs): + self.camp = camp + self.width = width + self.font = font or pbge.SMALLFONT + self.update() + self.height = self.image.get_height() + + def update(self): + self.image = pbge.render_text( + self.font, '${}'.format(self.camp.credits), self.width, justify=0, color=pbge.INFO_GREEN + ) + + def render(self, x, y): + self.update() + pbge.my_state.screen.blit(self.image, pygame.Rect(x, y, self.width, self.height)) + + +class EncumberanceBlock(object): + def __init__(self, model, font=None, width=220, **kwargs): + self.model = model + self.width = width + self.font = font or pbge.SMALLFONT + + @property + def height(self): + if hasattr(self.model, "carrying_capacity"): + return self.font.get_linesize() * 2 + else: + return self.font.get_linesize() + + def render(self, x, y): + mydest = pygame.Rect(x, y, self.width, self.height) + mymass = self.model.get_inv_mass() + mycolor = pbge.INFO_GREEN + if hasattr(self.model, "carrying_capacity"): + mycapacity = self.model.carrying_capacity() + if mymass > mycapacity * 1.25: + mycolor = pbge.ENEMY_RED + elif mymass > mycapacity: + mycolor = pygame.Color("yellow") + else: + mycapacity = 0 + pbge.draw_text( + self.font, self.model.scale.get_mass_string(mymass), mydest, mycolor, justify=0 + ) + if mycapacity > 0: + mydest.y += self.font.get_linesize() + pbge.draw_text( + self.font, "/{}".format(self.model.scale.get_mass_string(mycapacity)), mydest, mycolor, justify=0 + ) + + + class MechaStatusDisplay(InfoPanel): # A floating status display, drawn wherever the mouse is pointing. DEFAULT_BLOCKS = (FullNameBlock, HostilityStatusBlock, ModuleStatusBlock, PilotStatusBlock, EnchantmentBlock) @@ -1044,6 +1102,7 @@ def get_shortform_display(model, **kwargs): tex_name="sys_defbackground.png", tl=0, tr=3, bl=4, br=5, t=1, b=1, l=2, r=2 ) + class InfoWidget(pbge.widgets.Widget): # A widget that holds an info panel. Works just like a normal widget. Provide your own info panel and make sure # that the dimensions are compatible, @@ -1056,4 +1115,3 @@ def render(self, flash=False): pbge.my_state.screen.set_clip(mydest) self.info_panel.render(mydest.x, mydest.y) pbge.my_state.screen.set_clip(None) - diff --git a/history.md b/history.md index 1ac8c55f..5c12c620 100644 --- a/history.md +++ b/history.md @@ -1,3 +1,7 @@ +* Mouseover info will list items in tile +* Destroyed items appear red in inventory display +* All hidden models get revealed at the end of combat +* Window close button should now properly close the game * Scenes and rooms will expand if larger area is needed for contents * Weapon is_operational bug fixed * Items on floor should always appear behind characters and mecha diff --git a/pbge/rpgmenu.py b/pbge/rpgmenu.py index 1a5a38e9..f0a37ec2 100644 --- a/pbge/rpgmenu.py +++ b/pbge/rpgmenu.py @@ -200,6 +200,9 @@ def query(self): while no_choice_made: pc_input = wait_event() + if my_state.got_quit: + return(None) + if pc_input.type == TIMEREVENT: # Redraw the menu on each timer event. self.render()