Skip to content

Commit d00f24a

Browse files
committed
Foundry: Import Traps as NPC's
1 parent ab423f5 commit d00f24a

8 files changed

Lines changed: 365 additions & 72 deletions

CreatureExport/CreatureExport.csproj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@
6060
<Compile Include="CommandState.cs" />
6161
<Compile Include="Common.cs" />
6262
<Compile Include="FoundryCreatureHelper.cs" />
63-
<Compile Include="CreatureHelper.cs" />
63+
<Compile Include="FoundryTrapHelper.cs" />
64+
<Compile Include="Roll20CreatureHelper.cs" />
6465
<Compile Include="ExportEncounterAndSubsCommand.cs" />
6566
<Compile Include="ExportEncounterCommand.cs" />
6667
<Compile Include="ExportProjectCommand.cs" />
@@ -70,7 +71,7 @@
7071
<Compile Include="JSONBuilder.cs" />
7172
<Compile Include="Properties\AssemblyInfo.cs" />
7273
<Compile Include="SwitchSystemCommand.cs" />
73-
<Compile Include="TrapHelper.cs" />
74+
<Compile Include="Roll20TrapHelper.cs" />
7475
<Compile Include="UI\ResultForm.cs">
7576
<SubType>Form</SubType>
7677
</Compile>

CreatureExport/FoundryCreatureHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,9 +499,9 @@ private static Skills ProcessSkills(ICreature input, List<string> errors)
499499
}
500500

501501
var skillsHolder = new Skills();
502+
const int bonus = 5;
502503
skills.ForEach(x =>
503504
{
504-
var bonus = 5;
505505
switch (x.Name.ToLowerInvariant())
506506
{
507507
case "acrobatics":

CreatureExport/FoundryHelpers/FoundryPowerHelper.cs

Lines changed: 70 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ private static Dictionary<string, string> BuildEffectLookup()
9696
return dict;
9797
}
9898

99-
private static string newId(int length = 16) {
99+
public static string newId(int length = 16) {
100100
StringBuilder builder = new StringBuilder();
101101
Random rnd = new Random();
102102
for (int i = 0; i < length; i++)
@@ -252,7 +252,58 @@ public static FoundryPower ProcessAttack(CreaturePower power, List<string> error
252252
resultPower.data.attack.isAttack = true;
253253
resultPower.data.hit.isDamage = true;
254254

255-
// check to see if it was an elemental damage type, if not we fall back tp physcal
255+
ProcessAttackDamageAndRange(resultPower, errors, power.Details, power.Damage, power.Attack.Defence,
256+
power.Attack.Bonus, power.Range);
257+
258+
powerData.level = powerData.basicAttack ? "B" : "";
259+
260+
if (powerData.isMelee)
261+
{
262+
resultPower.img = powerData.basicAttack
263+
? "modules/foundry-4e-tools/icons/melee-basic.svg"
264+
: "modules/foundry-4e-tools/icons/melee.svg";
265+
}
266+
else
267+
{
268+
switch (powerData.rangeType)
269+
{
270+
case "melee" : // in theory should not hit this, but just in case
271+
case "reach" : resultPower.img = powerData.basicAttack
272+
? "modules/foundry-4e-tools/icons/melee-basic.svg"
273+
: "modules/foundry-4e-tools/icons/melee.svg";
274+
break;
275+
case "range":
276+
resultPower.img = powerData.basicAttack
277+
? "modules/foundry-4e-tools/icons/ranged-basic.svg"
278+
: "modules/foundry-4e-tools/icons/ranged.svg";
279+
break;
280+
case "closeBurst":
281+
case "closeBlast":
282+
resultPower.img = "modules/foundry-4e-tools/icons/close-blast.svg";
283+
break;
284+
case "rangeBurst":
285+
case "rangeBlast":
286+
case "wall":
287+
resultPower.img = "modules/foundry-4e-tools/icons/area-burst.svg";
288+
break;
289+
default:
290+
break;
291+
}
292+
}
293+
294+
return resultPower;
295+
}
296+
297+
298+
public static void ProcessAttackDamageAndRange(FoundryPower foundryPower, List<string> errors,
299+
string sourcePowerDetails,
300+
string sourcePowerDamage,
301+
DefenceType defenceType,
302+
int attackBonus,
303+
string range)
304+
{
305+
var powerData = foundryPower.data;
306+
// check to see if it was an elemental damage type, if not we fall back tp physcal
256307
var shouldAddPhysicalDamage = true;
257308
var keywordsHashSet = new HashSet<string>(powerData.keywords.Select(x => x.ToLowerInvariant()));
258309
if (keywordsHashSet.Intersect(ElementalDamageTypeSet).Any())
@@ -263,7 +314,7 @@ public static FoundryPower ProcessAttack(CreaturePower power, List<string> error
263314
// parse the power text just in case they didn't add the damage type to the keywords
264315
// single type
265316
{
266-
var damageTypeInPowerData = DamageTypeRegex1.Match(power.Details);
317+
var damageTypeInPowerData = DamageTypeRegex1.Match(sourcePowerDetails);
267318
if (damageTypeInPowerData.Success)
268319
{
269320
var damageType = damageTypeInPowerData.Groups[1].Value.ToLowerInvariant();
@@ -273,7 +324,7 @@ public static FoundryPower ProcessAttack(CreaturePower power, List<string> error
273324
}
274325
//multiple types
275326
{
276-
var damageTypeInPowerData = DamageTypeRegex2.Match(power.Details);
327+
var damageTypeInPowerData = DamageTypeRegex2.Match(sourcePowerDetails);
277328
if (damageTypeInPowerData.Success)
278329
{
279330
var damageType1 = damageTypeInPowerData.Groups[1].Value.ToLowerInvariant();
@@ -290,9 +341,9 @@ public static FoundryPower ProcessAttack(CreaturePower power, List<string> error
290341
powerData.damageType["physical"] = true;
291342
}
292343

293-
ProcessRangeAndWeapon(power, powerData, errors);
344+
ProcessRangeAndWeapon(range, powerData, foundryPower.name, errors);
294345
var def = "AC";
295-
switch (power.Attack.Defence)
346+
switch (defenceType)
296347
{
297348
case DefenceType.Fortitude:
298349
def = "Fort";
@@ -307,20 +358,20 @@ public static FoundryPower ProcessAttack(CreaturePower power, List<string> error
307358
}
308359

309360
powerData.attack.def = def.ToLowerInvariant();
310-
powerData.attack.formula = power.Attack.Bonus.ToString();
311-
powerData.description.chat += $"{power.Range}, {power.Attack.Bonus} vs {def}";
361+
powerData.attack.formula = attackBonus.ToString();
362+
powerData.description.chat += $"{range}, {attackBonus} vs {def}";
312363

313364
// reminder that details is the entire block and that Damage is Masterplans attempt to parse it out
314-
powerData.hit.detail = power.Details;
315-
var damage = CommonHelpers.parseDamageString(power.Damage, errors, power.Name);
365+
powerData.hit.detail = sourcePowerDetails;
366+
var damage = CommonHelpers.parseDamageString(sourcePowerDamage, errors, foundryPower.name);
316367
powerData.hit.formula = damage.NumDice > 0
317368
? damage.NumDice + "d" + damage.DiceSize + "+" + damage.Bonus
318369
: damage.Bonus.ToString();
319370
powerData.hit.critFormula = damage.NumDice + "*" + damage.DiceSize + "+" + damage.Bonus;
320371

321372
// attempt to get miss, effect and special out of the details.
322373
{
323-
var match = MissRgx.Match(power.Details);
374+
var match = MissRgx.Match(sourcePowerDetails);
324375
if (match.Success)
325376
{
326377
powerData.miss.detail = match.Groups[1].Value;
@@ -330,59 +381,22 @@ public static FoundryPower ProcessAttack(CreaturePower power, List<string> error
330381
{
331382
// effect detail was set by trait call
332383
powerData.effect.detail = null;
333-
var match = EffectRgx.Match(power.Details);
384+
var match = EffectRgx.Match(sourcePowerDetails);
334385
if (match.Success)
335386
{
336387
powerData.effect.detail = match.Groups[1].Value;
337388
powerData.hit.detail = powerData.hit.detail.Replace(match.Value, "");
338389
}
339390
}
340391
{
341-
var match = SpecialRgx.Match(power.Details);
392+
var match = SpecialRgx.Match(sourcePowerDetails);
342393
if (match.Success)
343394
{
344395
powerData.special = match.Groups[1].Value;
345396
powerData.hit.detail = powerData.hit.detail.Replace(match.Value, "");
346397
}
347398
}
348399
powerData.hit.detail = powerData.hit.detail.Replace("\r\n", "");
349-
powerData.level = powerData.basicAttack ? "B" : "";
350-
351-
if (powerData.isMelee)
352-
{
353-
resultPower.img = powerData.basicAttack
354-
? "modules/foundry-4e-tools/icons/melee-basic.svg"
355-
: "modules/foundry-4e-tools/icons/melee.svg";
356-
}
357-
else
358-
{
359-
switch (powerData.rangeType)
360-
{
361-
case "melee" : // in theory should not hit this, but just in case
362-
case "reach" : resultPower.img = powerData.basicAttack
363-
? "modules/foundry-4e-tools/icons/melee-basic.svg"
364-
: "modules/foundry-4e-tools/icons/melee.svg";
365-
break;
366-
case "range":
367-
resultPower.img = powerData.basicAttack
368-
? "modules/foundry-4e-tools/icons/ranged-basic.svg"
369-
: "modules/foundry-4e-tools/icons/ranged.svg";
370-
break;
371-
case "closeBurst":
372-
case "closeBlast":
373-
resultPower.img = "modules/foundry-4e-tools/icons/close-blast.svg";
374-
break;
375-
case "rangeBurst":
376-
case "rangeBlast":
377-
case "wall":
378-
resultPower.img = "modules/foundry-4e-tools/icons/area-burst.svg";
379-
break;
380-
default:
381-
break;
382-
}
383-
}
384-
385-
return resultPower;
386400
}
387401

388402
private static readonly Regex AreaBurstRgx =
@@ -410,9 +424,8 @@ public static FoundryPower ProcessAttack(CreaturePower power, List<string> error
410424
private static readonly Regex Wall2Rgx =
411425
new Regex(@"wall ([1-9][0-9]*)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
412426

413-
private static void ProcessRangeAndWeapon(CreaturePower power, FoundryPowerData data, List<string> errors)
427+
private static void ProcessRangeAndWeapon(string range, FoundryPowerData data, string powerName, List<string> errors)
414428
{
415-
var range = power.Range;
416429
var weapon = data.keywords.Contains("weapon") || data.keywords.Contains("Weapon");
417430
var implement = data.keywords.Contains("implement") || data.keywords.Contains("Implement");
418431
if (implement)
@@ -545,19 +558,16 @@ private static void ProcessRangeAndWeapon(CreaturePower power, FoundryPowerData
545558
// try to work around unset ranges
546559
else if (string.IsNullOrEmpty(range))
547560
{
548-
if ((power.Action.Use == PowerUseType.Basic) || (power.Attack != null))
549-
{
550-
data.rangeType = "melee";
551-
data.rangePower = 1;
552-
data.isMelee = true;
553-
errors.Add($"Attack {power.Name} did not have range set, assuming melee");
554-
}
561+
data.rangeType = "melee";
562+
data.rangePower = 1;
563+
data.isMelee = true;
564+
errors.Add($"Attack {powerName} did not have range set, assuming melee");
555565
}
556566
}
557567
}
558568
catch (Exception e)
559569
{
560-
errors.Add($"Failed to Parse Range: '{range}' for power {power.Name}:" + e.Message);
570+
errors.Add($"Failed to Parse Range: '{range}' for power {powerName}:" + e.Message);
561571
}
562572
}
563573
}

CreatureExport/FoundryJSONClasses.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@
55

66
namespace EncounterExport
77
{
8+
9+
public class FoundryTrapAndErrors
10+
{
11+
public FoundryCreature Trap { get; set; } = new FoundryCreature();
12+
public List<String> Errors { get; set; } = new List<string>();
13+
public bool HasError => Errors != null && Errors.Count > 0;
14+
public string Name => Trap.Name;
15+
}
16+
817
public class FoundryCreatureAndErrors
918
{
1019
public FoundryCreature Creature { get; set; } = new FoundryCreature();
@@ -43,6 +52,7 @@ public class FoundryTokenData
4352
{
4453
public bool actorLink { get; set; } = false;
4554
public int displayBars { get; set; } = 40; //OWNER
55+
public bool hidden { get; set; } = false;
4656
public Dictionary<string, object> flags { get; set; } = new Dictionary<string, object>();
4757
}
4858

@@ -128,11 +138,16 @@ public class IntValueWithBonuses : IntValueHolder
128138
{
129139
public List<Bonus> bonus { get; set; } = new List<Bonus>();
130140
}
141+
142+
public class Initative : IntValueWithBonuses
143+
{
144+
public string ability { get; set; } = "dex";
145+
}
131146

132147
public class Attributes
133148
{
134149
public IntValueHolderWithMax hp { get; set; } = new IntValueHolderWithMax();
135-
public IntValueWithBonuses init { get; set; } = new IntValueWithBonuses();
150+
public Initative init { get; set; } = new Initative();
136151
}
137152

138153
public class Defence : IntValueHolder

0 commit comments

Comments
 (0)