def findpath(self): start = self.locator.pos() goal = self.target.getpos() if self.range is None and self.target.isent(): self.range = self.target.ent.locator.r + self.locator.r else: self.range = 0#self.locator.r path = self.pathfinder.findpath(start, goal, self.walk, self.range) if path: # waypoints list is backwards # popping off completed points from the end is cheaper self.waypoints[:] = list(reversed(path)) # if len(self.waypoints) > 1: # # the first point is just the centre of the current cell, # # so if we have more than one point we skip this # self.waypoints.pop() # if self.range == 0: # # for an exact target we don't want the centre of the destination # # cell, so replace it with the actual goal # self.waypoints[0] = goal else: warn('no path to', self.target) self.stop()
def deduct_cost(self, ent): if self.cost.is_town_cost(): if not ent.has('town'): warn('ignoring out of town cost') return res = ent.town.town.resources res.deduct(self.cost) if self.cost.is_entity_cost(): ent.variables['mana'] -= self.cost.mana
def give(self, action): ''' Cancel all actions and do this instead ''' action.ent = self.ent if self.queue: if not self.queue[-1].interruptible(): warn('action is not interruptible!') return self.queue[-1].suspend() for ac in self.queue: ac.stop() del self.queue[:] self.queue.append(action) action.start()
def loadsector(self, sx, sy): try: return self.sectors[sx, sy] except KeyError: # TODO - hack - check for sectors existing try: self.datasrc.getmapsector(sx, sy) s = self.components.construct('sector', sx, sy) except KeyError: warn(f"sector {sx},{sy} doesn't exist") s = None self.sectors[sx, sy] = s if s is not None: self.dirty.add(s) self.onsectorloaded.emit(s) return s
def check_cost(self, ent): if self.cost.is_town_cost(): if not ent.has('town'): warn('ignoring out of town cost') return True res = ent.town.town.resources if not res.sufficient(self.cost): return False if self.cost.is_entity_cost(): if not ent.has('variables'): return False vars = ent.variables if 'mana' not in vars or vars['mana'] < self.cost.mana: return False return True
def select(self, ents, add): ''' Select ents or add ents to the current selection ''' lp = self.local.player myents = set(e for e in ents if e.ownedby(lp)) if not myents: # select highest ranked enemy ent rank = min(e.rank for e in ents) selection = [e for e in ents if e.rank == rank and e.appearance.visible_to(lp.tidmask)][:1] else: # select only my ents if add: # adding to the selection, use the tier of already selected ents myents = myents | set(self.selection) tier = self.selection[0].tier else: # new selection, use the highest tier tier = min(e.tier for e in myents) selection = [e for e in myents if e.tier == tier] if not selection: # no valid entities selected, so don't change selection warn('no entities were selected') return selection.sort(key=lambda e: e.rank) for s in self.selection: if s.has('appearance'): s.appearance.selected(False) self.selection = selection for s in self.selection: if s.has('appearance'): s.appearance.selected(True) self.onselectionchange.emit()
def activate(self, idx, target, add): ainst = self[idx] if ainst.cooldown > 0: warn('not ready - ability activate checked it') return False # not ready if not ainst.ability.check_cost(self.ent): warn('cannot pay cost - ability activate checked it') return False if ainst.ability.queue: assert self.ent.has( 'queue'), 'entity needs a queue for this ability' self.ent.queue.add(ainst, target) ainst.ability.deduct_cost(self.ent) return True else: if ainst.wait > 0: warn('already doing this - ability activate checked it') return False # not ready action = AbilityAction(ainst, target) if add: self.actions.now(action) else: self.actions.give(action) return True
def check_ability(eid): e = self.engine.entities.get(eid) if not e.has('abilities'): error('entity has no abilities') return False try: ainst = e.abilities[idx] except IndexError: error('index out of bounds - entity doesn\'t havethis ability') return False if e.proto.epid != ent.proto.epid: warn('entity does not have ability {0}', ability.name) return False if ainst.cooldown > 0: warn('not ready - game checked it') return False if not ability.queue and ainst.wait > 0: warn('already doing this - game checked it') return False #if not ability.check_cost(e): # warn('cannot pay cost - game checked it') # return False return True
def ability(self, idx, add): info(f'trying to do ability {idx}') ''' Do the ability at idx for the currently selected entities ''' if not self.selection: # nothing selected warn('no selection') return # grab the ability - defined by the first entity in the selection ent = self.selection[0] if not ent.has('abilities'): # no abilities warn('entity has no abilities') return if not ent.ownedby(self.local.player): # should never happen, player doesn't own the entity warn('entity not owned by local player') return try: ability = ent.abilities[idx].ability except IndexError: error('index out of bounds') return # get the ents - non group abilities cannot be done by # multiple entities so we pick the first if not ability.group: entids = [ent.eid] else: entids = [e.eid for e in self.selection] # verify if there are any entities in the selection that can actually # do the ability right now # * do they have the same ability - for now we compare the protos # * enough resourcea # * cooldowns not active # NOTE this is a Game check, the Engine will check again when activating def check_ability(eid): e = self.engine.entities.get(eid) if not e.has('abilities'): error('entity has no abilities') return False try: ainst = e.abilities[idx] except IndexError: error('index out of bounds - entity doesn\'t havethis ability') return False if e.proto.epid != ent.proto.epid: warn('entity does not have ability {0}', ability.name) return False if ainst.cooldown > 0: warn('not ready - game checked it') return False if not ability.queue and ainst.wait > 0: warn('already doing this - game checked it') return False #if not ability.check_cost(e): # warn('cannot pay cost - game checked it') # return False return True entids = [eid for eid in entids if check_ability(eid)] if not entids: warn('no entities can do the ability now') self.gamelog.log('No units can do this ability right now') return # create the order order = AbilityOrder(entids, idx, add) # based on ability type we either issue an order # or enter a new mode if ability.type == ability.INSTANT: order.add = True # instants never interrupt the current action self.order(order) elif ability.type == ability.ACTIVITY: self.order(order) elif ability.type == ability.TARGETED: self.modes.push_mode('targetingmode', order, allowpos=False) elif ability.type == ability.BUILD: proto = ent.team.getproto(ability.proto) self.modes.push_mode('buildmode', order, proto) elif ability.type == ability.AREA_OF_EFFECT: self.modes.push_mode('targetingmode', order) elif ability.type == ability.STATIC: pass # do nothing else: raise RuntimeError('unknown ability type!')
def destroy(self): warn('TODO - unfootprint')
def close(self): warn('closing Lua interp') self.lua.lua_close(self.L)