Skip to content

Commit

Permalink
Support rolling damage for hand weapon
Browse files Browse the repository at this point in the history
  • Loading branch information
Socolin committed Apr 14, 2024
1 parent 0dd8204 commit c5c5f76
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 2 deletions.
17 changes: 17 additions & 0 deletions src/app/chat/skill-roll-chat-message.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,23 @@
</ng-container>
</div>
}
@case ('hand-damage') {
<hr>
@if (data.extraData.data.weapon) {
<div class="weapon">
<span class="icon"><img width="32" height="32" [src]="data.extraData.data.weapon.icon"></span>
<span class="name">{{data.extraData.data.weapon.name}}</span>
<span class="details">Dégâts: {{data.extraData.data.weapon.damageRollFormula}}<span *ngIf="data.extraData.data.weapon.element"> ({{data.extraData.data.weapon.element | translate: 'Element.NameForWeaponDamage'}})</span></span>
</div>
}
<div class="damage">
<ng-container *ngIf="data.result == 'success' || data.result == 'criticalSuccess'">
<lvl0-roll-detail [roll]="data.extraData.data.damageRoll!">
Dégâts: <i class="fa fa-dice"></i> {{ roundDamageUp(data.extraData.data.damageRoll?.total) }}
</lvl0-roll-detail>
</ng-container>
</div>
}
@case ('shield-damage') {
<hr>
<div class="weapon">
Expand Down
9 changes: 9 additions & 0 deletions src/app/chat/skill-roll-chat-message.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ export type SkillRollChatExtraDataMessageData = {
} | {
kind: 'shield-damage',
data: SkillRollExtraDataShieldDamageMessageData
} | {
kind: 'hand-damage',
data: SkillRollExtraDataHandDamageMessageData
}

export type SkillRollExtraDataShieldDamageMessageData = {
Expand All @@ -28,6 +31,12 @@ export type SkillRollExtraDataShieldDamageMessageData = {
shield: SkillRollExtraDataItemInfoMessageData;
}

export type SkillRollExtraDataHandDamageMessageData = {
damageRollFormula: string;
damageRoll?: ChatRoll;
weapon?: SkillRollExtraDataItemInfoMessageData;
}

export type SkillRollExtraDataDamageMessageData = {
damageRollFormula: string;
damageRoll?: ChatRoll;
Expand Down
120 changes: 120 additions & 0 deletions src/app/skill/scripts/roll-hand-damage-skill-script.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import {SkillScript} from "./skill-script";
import {Lvl0ItemHandWeapon} from '../../data-accessor/models/lvl0-item';
import {IRoll} from '../../shared/roll';
import {RollFactory} from '../../shared/roll-factory';
import {SkillRollChatExtraDataMessageData} from "app/chat/skill-roll-chat-message.component";
import {SkillRollOutcome} from '../skill-roll-util';
import {firstValueFrom} from 'rxjs';
import {selectCharacterItemsOfType} from '../../data-accessor/selectors/character-selectors';
import {CharacterAccessorService} from '../../data-accessor/character-accessor.service';
import {selectCharacterBasicStats} from '../../data-accessor/selectors/character-basic-stats-selector';
import {selectCharacterEffects} from '../../data-accessor/selectors/character-effects-selector';
import {SystemDataDatabaseService} from '../../system-data/system-data-database.service';

export type RollHandDamageSkillResult = {
damageRollFormula: string;
damageRoll?: IRoll;
damageElement?: string;
weapon?: RollHandDamageSkillItemInfoResult;
}

export type RollHandDamageSkillItemInfoResult = {
name: string;
icon?: string;
damageRollFormula: string;
element?: string;
};

export class RollHandDamageSkillScript extends SkillScript<RollHandDamageSkillResult> {
actorId: string;
handWeapon?: Lvl0ItemHandWeapon;

constructor(
private readonly rollFactory: RollFactory,
private readonly characterAccessorService: CharacterAccessorService,
private readonly systemDataDatabaseService: SystemDataDatabaseService,
) {
super();
}

override async prepare(actorId: string): Promise<number> {
this.actorId = actorId;

let handWeapons = await firstValueFrom(this.characterAccessorService.selectCharacter(actorId).pipe(selectCharacterItemsOfType<Lvl0ItemHandWeapon>('handWeapon')), {defaultValue: [] as Lvl0ItemHandWeapon[]});
let equipedHandWeapons = handWeapons.filter(x => x.system.equiped);
if (equipedHandWeapons.length === 0) {
return 1;
}

this.handWeapon = equipedHandWeapons[0];
return 1;
}

async postRoll(rollResult: SkillRollOutcome): Promise<RollHandDamageSkillResult> {
let actorBasicStatValues = await firstValueFrom(this.characterAccessorService.selectCharacter(this.actorId).pipe(selectCharacterBasicStats()));
let baseDamageRollFormula = Math.ceil(actorBasicStatValues.phy / 2).toString();
if (this.handWeapon) {
baseDamageRollFormula = this.handWeapon.system.damage.replace('phy', actorBasicStatValues.phy.toString())
}

let characterEffects = await firstValueFrom(this.characterAccessorService.selectCharacter(this.actorId).pipe(selectCharacterEffects(this.systemDataDatabaseService)));
let damageBonus = 0;
for (let characterEffect of characterEffects) {
for (let modifier of characterEffect.modifiers) {
if (modifier.stat === 'damage')
damageBonus += +modifier.value;
}
}
let damageRollFormula = baseDamageRollFormula;
if (damageBonus) {
damageRollFormula += `+${damageBonus}`;
}

if (rollResult === 'success' || rollResult === 'criticalSuccess') {
let damageRoll = await this.rollFactory.createRoll(damageRollFormula);
return {
damageRollFormula: damageRollFormula,
damageRoll: damageRoll,
weapon: this.handWeapon ? {
name: this.handWeapon.name,
icon: this.handWeapon.img,
damageRollFormula: damageRollFormula,
} : undefined
}
}

return {
damageRollFormula: damageRollFormula,
weapon: this.handWeapon ? {
name: this.handWeapon.name,
icon: this.handWeapon.img,
damageRollFormula: damageRollFormula,
} : undefined
}
}

postRolls(skillRollOutcomes: SkillRollOutcome[]): Promise<RollHandDamageSkillResult[]> {
throw new Error("Not supported.");
}

getRolls(data: RollHandDamageSkillResult): IRoll[] {
let rolls: IRoll[] = [];

if (data.damageRoll)
rolls.push(data.damageRoll)

return rolls;
}

getChatData(data: RollHandDamageSkillResult): SkillRollChatExtraDataMessageData {
return {
kind: 'hand-damage',
data: {
damageRollFormula: data.damageRollFormula,
weapon: data.weapon,
damageRoll: data.damageRoll ? this.rollFactory.convertToRollChat(data.damageRoll) : undefined
}
}
}

}
9 changes: 8 additions & 1 deletion src/app/skill/scripts/skill-script-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {WeaponDamageRollUtil} from '../../item/weapon-damage-roll-util.service';
import {SpellChatService} from '../../spell/spell-chat.service';
import {MacroService} from '../../shared/macro.service';
import {ActorUpdaterService} from '../../data-accessor/actor-updater.service';
import {RollHandDamageSkillResult, RollHandDamageSkillScript} from './roll-hand-damage-skill-script';

@Injectable({
providedIn: 'root'
Expand All @@ -44,7 +45,7 @@ export class SkillScriptFactory {

createScript(
skillDefinition: SkillDefinition,
): SkillScript<RollDamageSkillResult | SpellScriptResult | RollShieldDamageScriptResult, any> | undefined {
): SkillScript<RollDamageSkillResult | SpellScriptResult | RollShieldDamageScriptResult | RollHandDamageSkillResult, any> | undefined {
if (!skillDefinition.script?.name)
return undefined;

Expand All @@ -57,6 +58,12 @@ export class SkillScriptFactory {
this.weaponDamageRollUtil,
this.itemUpdaterService
);
case 'handDamageRoll':
return new RollHandDamageSkillScript(
this.rollFactory,
this.characterAccessorService,
this.systemDataDatabaseService
);
case 'castSpell':
return new RollSpellSkillScript(
skillDefinition,
Expand Down
10 changes: 9 additions & 1 deletion src/repositories/data/skills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export type SkillScriptDefinition =
RollDamageSkillScriptDefinition
| CastSpellSkillScriptDefinition
| ShieldRollDamageSkillScriptDefinition
| RollHandDamageSkillScriptDefinition

export interface RollDamageSkillScriptDefinition {
readonly name: 'damageRoll';
Expand All @@ -29,6 +30,10 @@ export interface RollDamageSkillScriptData {
readonly charge?: boolean;
}

export interface RollHandDamageSkillScriptDefinition {
readonly name: 'handDamageRoll';
}

export interface CastSpellSkillScriptDefinition {
readonly name: 'castSpell';
readonly data: CastSpellSkillScriptData;
Expand Down Expand Up @@ -220,7 +225,10 @@ export default {
name: "Combat mains nues",
icon: 'icons/skills/melee/unarmed-punch-fist-white.webp',
stat: "phy",
description: "Le personnage a une certaine connaissance des techniques de combat sans arme. S’applique : le combat de rue (+PHY), la boxe (+PHY), etc.",
description: "Le personnage a une certaine connaissance des techniques de combat sans arme. S’applique : le combat de rue, la boxe, etc.",
script: {
name: 'handDamageRoll'
}
}, {
id: "melee_combat",
name: "Combat mêlée",
Expand Down

0 comments on commit c5c5f76

Please sign in to comment.