How to work better with records

https://gist.github.com/IXLLEGACYIXL/e3c5575656de0bebf314096699e9d42c I have this and want the modified item after breakthrough is applied, but i dont want to modify the original item but it seems like this shouldnt be the way to work with records... can i simplify that syntax?
Gist
gist:e3c5575656de0bebf314096699e9d42c
GitHub Gist: instantly share code, notes, and snippets.
42 Replies
Pobiega
Pobiega6mo ago
your Apply method should return the new record instance so it can't be a void
Joreyk ( IXLLEGACYIXL )
yes it was more about the changing of the record itself
Pobiega
Pobiega6mo ago
you don't change records. you can't without doing some quite evil stuff also, why are you using full syntax instead of record syntax?
Joreyk ( IXLLEGACYIXL )
like line 10-13 should this "be the way" its intended to be? thats the question that i wanted to ask how to write it in better syntax whats the record syntax? or how could i write the lines i have "better" in a better syntax
Pobiega
Pobiega6mo ago
internal record ComboDice(int Count, int Sides, int Fix)
{
public virtual int Roll()
{
int total = 0;
for (var i = 0; i < Count; i++)
{
total += IDice.Random.Next(1, Sides + 1);
}
return total + Fix;
}
}
internal record ComboDice(int Count, int Sides, int Fix)
{
public virtual int Roll()
{
int total = 0;
for (var i = 0; i < Count; i++)
{
total += IDice.Random.Next(1, Sides + 1);
}
return total + Fix;
}
}
thats how you declare a record. if you're going to manually create the props, then why bother with records in the first place?
Joreyk ( IXLLEGACYIXL )
the reason i dont have it this way is that the engine cant handle it
Pobiega
Pobiega6mo ago
I don't really understand what you are trying to do, because what you have right now does not work
internal record class Breakthrough : ComboDice
{
public void Apply(Character target, Character source, Item targetItem, Item sourceItem)
{
var x = targetItem with {
Base = targetItem.Base with {
Fix = targetItem.Base.Fix - Roll()
}
};
}
}
internal record class Breakthrough : ComboDice
{
public void Apply(Character target, Character source, Item targetItem, Item sourceItem)
{
var x = targetItem with {
Base = targetItem.Base with {
Fix = targetItem.Base.Fix - Roll()
}
};
}
}
this does absolutely nothing
Joreyk ( IXLLEGACYIXL )
imagine it returns targetitem XD
Pobiega
Pobiega6mo ago
but why is this its own class?
Joreyk ( IXLLEGACYIXL )
how do you mean?
Pobiega
Pobiega6mo ago
its just a method. so add it as an extension method, or a normal method Breakthrough doesn't add or change anything in ComboDice
Joreyk ( IXLLEGACYIXL )
because i want a List of "buffs" with for example breakthrough to reduce armor and imagine that i have return targetItem.... so i have the original one and a "modified" version thats an example armor how it should look like in yaml
Armor :
Base : { Rolls : 4 , Side : 8 FIx: 12 }
Buffs:
- BreakThrough : { Rolls : 0 , Sides : 0 Fix: 4 }
- ArmorIncrease : { Rolls : 1 , Sides : 6 Fix: 0 }
Armor :
Base : { Rolls : 4 , Side : 8 FIx: 12 }
Buffs:
- BreakThrough : { Rolls : 0 , Sides : 0 Fix: 4 }
- ArmorIncrease : { Rolls : 1 , Sides : 6 Fix: 0 }
breakthrough reduces armor and armorincrease increases it but i dont want to modify "the original armors base" as i apply the buffs in each combat thats why records as they are good for "keeping the original" and getting a copy that i can modify with the buffs
Pobiega
Pobiega6mo ago
okay, sure you're gonna have some issues with how the code is written thou. public ComboDice Base { get; init; } = new ComboDice(); for example that new ComboDice does nothing, if Item is intended to be deserialized
Pobiega
Pobiega6mo ago
in general, records without constructors are not going to work very well here
Joreyk ( IXLLEGACYIXL )
what would you advise for "modification" and keeping the original
Pobiega
Pobiega6mo ago
im not sure about yaml deserializers specifically, but the json ones create the object (either via a parameterless ctor or the "best" ctor match) then use reflection to access the property setters
Joreyk ( IXLLEGACYIXL )
we have yamlsharp from 2008 and my yaml serilaizer that i wrote cant handle it either
Pobiega
Pobiega6mo ago
how would the API look for this? ie, how do you "activate" the buffs?
Joreyk ( IXLLEGACYIXL )
how do you mean? if i get the collision event from the weapon, i take the source ( attacking wepaon and character ) and calculate it against the targets armor and character now all buffs get applied and at the end its just damage - armor armor would be modified if the weapon has breakthrough so in the last step it would resist less thats the plan to do
Pobiega
Pobiega6mo ago
but.. your armor value isnt fixed. its not part of the record its made by calling the Roll method
Joreyk ( IXLLEGACYIXL )
if my current armor has this as base { Rolls : 4 , Side : 8 FIx: 12 } then the new record will have { Rolls : 4 , Side : 8 FIx: 8 } with a breakthrough of a roll of 4 if i would calculate now the armors value it would be 4 dices a 8 sides + 8 so its reduced
Pobiega
Pobiega6mo ago
Ah I see, so they modify the base roll they dont make their own rolls
Pobiega
Pobiega6mo ago
I see.
Joreyk ( IXLLEGACYIXL )
a 1 roll of 6 sides for armor increase with a result of 3 would increase the armors fix value by 3 after all modifications, the armor rolls with the end result
Pobiega
Pobiega6mo ago
well then the result of applying all the buffs should be an IDice I guess?
Joreyk ( IXLLEGACYIXL )
oh ye it should be
Pobiega
Pobiega6mo ago
but even then this seems a bit weird each buff shouldnt care about the target etc, no? it should only care about the dice its modifying, and itself?
Joreyk ( IXLLEGACYIXL )
the idea was if you have high fire resistance then ice damages you more
Pobiega
Pobiega6mo ago
is there an individual stat for ice resistance? or is fire resistance actually... "heat modifier"? ie, low values block ice, but make you vulnerable to fire and vice versa
Joreyk ( IXLLEGACYIXL )
there is not yet an extra stat for ice didnt think that far so an armor would have Base Ice Fire ... and the buffs as values hmmm
Pobiega
Pobiega6mo ago
public record Item(Dice Base, List<IBuff> Buffs);

internal record class Breakthrough(int Count, int Sides, int Fix) : Dice(Count, Sides, Fix), IBuff
{
public Dice Apply(Dice baseDice)
=> baseDice with { Fix = baseDice.Fix - this.Fix };
}

public interface IBuff
{
public Dice Apply(Dice baseDice);
}
public record Item(Dice Base, List<IBuff> Buffs);

internal record class Breakthrough(int Count, int Sides, int Fix) : Dice(Count, Sides, Fix), IBuff
{
public Dice Apply(Dice baseDice)
=> baseDice with { Fix = baseDice.Fix - this.Fix };
}

public interface IBuff
{
public Dice Apply(Dice baseDice);
}
im playing around with something like this atm
Joreyk ( IXLLEGACYIXL )
okeeee
Pobiega
Pobiega6mo ago
public int Attack(Character target)
{
// this applies all the buffs in order, giving us the final modified value
var dice = Weapon.Buffs.Aggregate(Weapon.Base, (current, buff) => buff.Apply(current));

var roll = dice.Roll();

// TODO: modify the damage by armor

return roll;
}
public int Attack(Character target)
{
// this applies all the buffs in order, giving us the final modified value
var dice = Weapon.Buffs.Aggregate(Weapon.Base, (current, buff) => buff.Apply(current));

var roll = dice.Roll();

// TODO: modify the damage by armor

return roll;
}
lets you apply buffs like this
Joreyk ( IXLLEGACYIXL )
okeee i gotta play with that
Pobiega
Pobiega6mo ago
you could easily send in the source and target char/items here too
Joreyk ( IXLLEGACYIXL )
falsely understood XD i have to play with it i didnt use aggregate too much
Pobiega
Pobiega6mo ago
the idea is that it takes the base then sends that to the first buff, gets a result sends that result to the next buff repeat until done
Joreyk ( IXLLEGACYIXL )
that sounds good yep thats what im going with
Pobiega
Pobiega6mo ago
ok let me implement another buff and see how it goes also, currently breakthrough ONLY affects Fix so if you give it a value for side or count, it wont do anything