def play_vfx(self, target, parameters): vfxnames = parameters.get('vfx', []) duration = parameters.get('duration', 1.0) if isinstance(vfxnames, str): vfxnames = [vfxnames] def create_vfx(vfxname): particles = ParticleEffect() if pman.is_frozen(): vfxpath = f'assets/vfx/{vfxname}.ptf' else: vfxpath = f'.built_assets/vfx/{vfxname}.ptf' particles.loadConfig(vfxpath) particles.set_shader_auto(True) return particles vfx = [create_vfx(i) for i in vfxnames] def start_particle(effect): effect.start(parent=target.as_nodepath) return intervals.Parallel(*[ intervals.Sequence( intervals.Func(start_particle, i), intervals.Wait(duration), intervals.Func(i.cleanup), ) for i in vfx ])
def template_simple(self, target, parameters): sequence = intervals.Sequence() if 'stat' not in parameters: parameters['stat'] = 'current_hp' if 'start_range' in parameters: parameters['range'] = parameters['start_range'] sequence.append(self.move_to_range(self.combatant, parameters)) if 'animation_name' not in parameters and self.ability.type == 'magical': parameters['animation_name'] = 'magic' if 'vfx' not in parameters and self.ability.type == 'magical': parameters['vfx'] = ['dust'] elif 'vfx' not in parameters: parameters['vfx'] = ['sparks'] sequence.extend( intervals.Sequence( self.play_animation(self.combatant, parameters), self.play_vfx(target, parameters), self.change_stat(target, parameters), )) if 'start_range' in parameters: if 'end_range' in parameters: parameters['range_index'] = parameters['end_range'] else: parameters['range_index'] = parameters['start_range'] sequence.append(self.move_to_range(self.combatant, parameters)) return sequence
def __init__(self, rendernp, combatant, ability, combat): self.rendernp = rendernp self.combatant = combatant self.ability = ability self.combat = combat hit_chance = calculate_hit_chance(combatant, combatant.target, ability) roll = random.randrange(0, 99) self.is_hit = hit_chance > roll #print(hit, hit_chance, die) crit_chance = calculate_crit_chance(combatant, combatant.target, ability) roll = random.randrange(0, 99) self.is_crit = crit_chance > roll self.strength = calculate_strength(combatant, ability) if self.is_crit: self.strength = round(self.strength * 1.5) self.sequence = intervals.Sequence() self.initial_self_position = combatant.tile_position self.initial_other_position = combatant.target.tile_position self.initial_position = None for effect in ability.effects: self.sequence.extend(self.parse_effect(effect)) self.sequence.append( intervals.Func(combatant.play_anim, 'idle', loop=True), )
def _fadeOutRepairSpotModel(self, locIndex): if locIndex in self._repairSpotIvals: self._repairSpotIvals[locIndex].pause() self._repairSpotHoles[locIndex].setTransparency(1, 100) ival = IG.Sequence(IG.Wait(DistributedPlayerSimpleShip.RepairSpotFadeAfter), IG.LerpColorScaleInterval(self._repairSpotHoles[locIndex], DistributedPlayerSimpleShip.RepairSpotFadeDur, Vec4(1.0, 1.0, 1.0, 0.0), blendType = 'easeInOut')) ival.start() self._repairSpotIvals[locIndex] = ival
def func(): textnp.set_pos(target.as_nodepath, 0, 0, 2) intervals.Sequence( intervals.Func(textnp.show), intervals.LerpPosInterval( textnp, 1.0, textnp.get_pos() + p3d.LVector3(0, 0, 0.5)), intervals.Func(textnp.remove_node), ).start()
def _removeRepairSpotHoles(self): for locIndex in PVPGlobals.ShipClass2repairLocators[ self.modelClass].getValue(): self._removeRepairSpotModel(locIndex) if self._repairSpotHoleFixed: self._placeRepairSpotModel(locIndex, self._repairSpotHoleFixed) self._fadeOutRepairSpotModel(locIndex) self._repairSpotIvals[locIndex] = IG.Sequence( self._repairSpotIvals[locIndex], IG.Func(self._removeRepairSpotModel, locIndex))
def use_ability(self, ability, target, controller, effect_node): self.target = target target.target = self return intervals.Sequence( intervals.Func( controller.display_message, f'{self.name} is using {ability.name} ' f'on {target.name}'), effects.sequence_from_ability(effect_node, self, ability, controller))
def accept_move(): selection = self.combatant_in_tile(self.selected_tile) if selection == combatant: selection = None in_range = self.arena.tile_in_range(self.selected_tile, self.starting_tile_position, 0, combatant.movement) if selection is None and in_range: intervals.Sequence( self.move_combatant_to_tile(combatant, self.selected_tile), intervals.Func(self.set_input_state, 'ACTION', combatant)).start()
def move_combatant_to_tile(self, combatant, tile_pos, immediate=False): if immediate: duration = 0 else: duration = self.arena.tile_distance(combatant.tile_position, tile_pos) * 0.2 combatant.tile_position = tile_pos newpos = self.arena.tile_coord_to_world(tile_pos) sequence = intervals.Sequence( intervals.Func(combatant.play_anim, 'walk', loop=True), intervals.LerpPosInterval(combatant.as_nodepath, duration, newpos), intervals.Func(combatant.play_anim, 'idle', loop=True)) if immediate: sequence.start() return sequence
def set_camera_x(self, newx): campos = base.camera.get_pos() campos.x = newx intervals.LerpPosInterval(base.camera, 0.1, campos, blendType='easeInOut').start()
def enter_end_turn(self): combatants_by_ct = sorted(list(self.combatants), reverse=True, key=lambda x: x.current_ct) next_combatant = combatants_by_ct[0] ctdiff = 100 - next_combatant.current_ct if ctdiff > 0: for combatant in self.combatants: combatant.current_ct += ctdiff next_combatant.current_ct = 0 self.selected_tile = next_combatant.tile_position self.starting_tile_position = next_combatant.tile_position if next_combatant in self.player_combatants: self.set_input_state('ACTION', next_combatant) else: sequence = self.aicontroller.update_combatant( next_combatant, self.get_remaining_player_combatants()) def cleanup(): if self.input_state != 'END_COMBAT': self.input_state = 'END_TURN' sequence.extend([ intervals.Func(cleanup), ]) sequence.start()
def show_result(self, target, value): textnode = p3d.TextNode('effect result') textnode.set_align(p3d.TextNode.ACenter) textnode.set_text(value) textnp = self.rendernp.attach_new_node(textnode) textnp.set_billboard_point_eye() textnp.set_bin("fixed", 0) textnp.set_depth_test(False) textnp.set_depth_write(False) textnp.set_shader_auto(True) textnp.set_color_scale((0, 0, 0, 1)) textnp.set_light_off() textnp.hide() def func(): textnp.set_pos(target.as_nodepath, 0, 0, 2) intervals.Sequence( intervals.Func(textnp.show), intervals.LerpPosInterval( textnp, 1.0, textnp.get_pos() + p3d.LVector3(0, 0, 0.5)), intervals.Func(textnp.remove_node), ).start() return intervals.Func(func)
def _startMoveIval(self, entranceId, startT): self._stopMoveIval() unitVecs = (Vec3(1, 0, 0), Vec3(0, 1, 0), Vec3(-1, 0, 0), Vec3(0, -1, 0)) machineDistance = 4 entranceDistance = 60 startPos = unitVecs[entranceId] * entranceDistance endPos = unitVecs[entranceId] * machineDistance walkDur = (endPos - startPos).length() / GameConsts.CogSettings.CogWalkSpeed.get() sceneRoot = self.getGame().getSceneRoot() moveIval = IG.Sequence(IG.Func(self.reparentTo, sceneRoot), IG.Func(self.setPos, startPos), IG.Func(self.lookAt, sceneRoot), IG.Func(self.loop, 'walk'), IG.LerpPosInterval(self, walkDur, endPos, startPos=startPos)) interactIval = IG.Sequence(IG.Func(self.loop, 'neutral'), IG.Wait(GameConsts.CogSettings.CogMachineInteractDuration.get())) flyIval = IG.Sequence(IG.Func(self.pose, 'landing', 0), IG.LerpPosInterval(self, GameConsts.CogSettings.CogFlyAwayDuration.get(), self._getFlyAwayDest, blendType='easeIn')) self._moveIval = IG.Sequence(moveIval, interactIval, flyIval) self._moveIval.start(globalClock.getFrameTime() - startT)
def move_to_range(self, target, parameters): target_range = parameters['range'] hit_required = parameters.get('is_hit_dependent', False) if hit_required and not self.is_hit: return intervals.Sequence() seq = self.combat.move_combatant_to_range(target, target.target, target_range) return seq
def change_stat(self, target, parameters): stat = parameters['stat'] local_str_fac = parameters.get('strength_factor', 1) seq = intervals.Sequence() strength = self.strength * local_str_fac if parameters.get('show_result', True): if self.is_hit: result = self.CHANGE_STATE_PREFIX.get( stat, '') + f'{strength * -1:+}' if self.is_crit: result += ' (CRIT!)' else: result = 'Miss' seq.append(self.show_result(target, result)) def func(): if self.is_hit: setattr(target, stat, getattr(target, stat) - strength) seq.append(intervals.Func(func)) return seq
def accept_target(): selection = self.combatant_in_tile(self.selected_tile) in_range = self.arena.tile_in_range( self.selected_tile, combatant.tile_position, *self.get_ability_range(combatant, ability)) if selection is not None and in_range: sequence = combatant.use_ability(ability, selection, self, self.root_node) def cleanup(): self.selected_tile = combatant.tile_position if self.input_state != 'END_COMBAT': self.set_input_state('END_TURN') sequence.append(intervals.Func(cleanup)) sequence.start()
def parse_effect(self, effect): sequence = intervals.Sequence() target = effect.get('target', 'other') if target == 'self': target = self.combatant self.initial_position = self.initial_self_position elif target == 'other': target = self.combatant.target self.initial_position = self.initial_other_position else: raise RuntimeError("Unkown effect target: {}".format(target)) parameters = effect.get('parameters', {}) etype = effect['type'] if etype not in self.ALLOWED_EFFECTS: raise RuntimeError("Unknown effect type: {}".format(etype)) sequence.append(getattr(self, etype)(target, parameters)) return sequence
def update(self, statedata): if not self.stats_box.is_hidden(): self._stats_menu.update(statedata) statedata.pop('show_menu', None) super().update(statedata) if 'num_form_abilities' in statedata: self._stats_num_fabilities = statedata['num_form_abilities'] if 'num_weapon_abilities' in statedata: self._stats_num_wabilities = statedata['num_weapon_abilities'] if 'num_golems' in statedata or 'max_golems' in statedata: self.num_golems_label['text'] = ( f'Golems: {statedata["num_golems"]}/{statedata["max_golems"]}') if 'num_power_gems' in statedata: self.num_gems_label['text'] = ( f'Power Gems: {statedata["num_power_gems"]}') if 'monster' in statedata: self.rebuild_stats(statedata['monster']) if 'show_stats' in statedata: show = statedata['show_stats'] if show and self.stats_box.is_hidden(): intervals.LerpPosInterval(self.stats_box, 0.1, self.stats_box.get_pos(), startPos=(-1, 0, self.stats_box.get_z()), blendType='easeInOut').start() self.stats_box.show() self.menu.hide() self.num_golems_label.hide() elif not show: self.stats_box.hide() self.menu.show() self.num_golems_label.show()
def move_combatant_to_range(self, *_args, **_kwargs): return intervals.Sequence()
def change_to_previous_state(self, skip_fade=False): ival = intervals.Func(self.gman.change_to_previous) if skip_fade: ival.start() else: self.transitions.fadeOut(finishIval=ival)
def change_state(self, next_state, skip_fade=False): ival = intervals.Func(self.gman.change, next_state) if skip_fade: ival.start() else: self.transitions.fadeOut(finishIval=ival)
def update_combatant(self, combatant, enemy_combatants): sequence = intervals.Sequence() # Find a target target = self.targets.get(combatant, None) if target is None or target.is_dead(): target = random.choice(enemy_combatants) for enemy in enemy_combatants: dist_to_closest = self.arena.tile_distance(combatant.tile_position, target.tile_position) dist_to_current = self.arena.tile_distance(combatant.tile_position, enemy.tile_position) if dist_to_current < dist_to_closest: target = enemy # Pick an ability available_abilities = [ ability for ability in combatant.abilities if combatant.can_use_ability(ability) ] if not available_abilities: return sequence ability = random.choice(available_abilities) # Update facing sequence.append( intervals.Func(self.controller.face_combatant_at_tile, combatant, target.tile_position)) # Find a tile to move to tiles = self.arena.find_tiles_in_range(combatant.tile_position, 0, combatant.movement) tiles = [ tile for tile in tiles if self.controller.combatant_in_tile(tile) is None ] target_tile = None dist_to_target = self.arena.tile_distance(combatant.tile_position, target.tile_position) range_min, range_max = self.controller.get_ability_range( combatant, ability) for tile in tiles: tile_dist = self.arena.tile_distance(tile, target.tile_position) if range_min <= tile_dist <= range_max: target_tile = tile dist_to_target = tile_dist break elif tile_dist < dist_to_target: target_tile = tile dist_to_target = tile_dist if target_tile: self.controller.selected_tile = target_tile sequence.extend([ self.controller.move_combatant_to_tile(combatant, target_tile), ]) # Update facing sequence.append( intervals.Func(self.controller.face_combatant_at_tile, combatant, target.tile_position)) # Use an ability if able if range_min <= dist_to_target <= range_max: sequence.extend([ intervals.WaitInterval(0.25), combatant.use_ability(ability, target, self.controller, self.effects_root), intervals.WaitInterval(1), ]) return sequence
def actor_interval(self, anim): mapped_anim = self.get_anim(anim) if mapped_anim is None: self._anim_warning(anim) return intervals.Sequence() return self._path.actor_interval(mapped_anim)