-
Notifications
You must be signed in to change notification settings - Fork 0
Guide
Welcome to the STS-OrbLib wiki!
To first get started with the framework you need to add it to your mods Maven dependencies Add this to your pom file and have Maven install it.
<dependency>
<groupId>ItsLuke.OrbLib</groupId>
<artifactId>OrbLib</artifactId>
<version>1.3.1</version>
<scope>system</scope>
<systemPath>${Steam.path}/workshop/content/646570/3054196384/OrbLib.jar</systemPath>
</dependency>
It's very easy to get started using the framework. It consists of essentially a new base class for your orbs. This base class contains new helper functions to add more functionality to your orbs.
Before you would define your custom orbs like this.
public class OurOrb extends CustomOrb {
...
}
With this library you would define them like this.
public class OurOrb extends ExtendedOrb {
...
}
And that's it really.
Worry not, ExtendedOrb itself extends CustomOrb so you're functionality will remain the same but now you'll have access to the OrbLib framework. If you already have a character with Orbs changing it to ExtendedOrb will not break anything.
- Removing Orbs after x amount of turns (Effectiveness)
- Functionality to evoke all orbs when every orb slot is filled
This functionality is triggered when orbs are channelled with "new ExtendedChannelOrb(new OurOrb())", orbs channelled this way MUST extend ExtendedOrb
- Rightclickable Orbs - Can be used for specific toggle effects
- Orb Listener
The Orb listener lets you make one Orb listen out to the events of another. For example you can make OrbA listen out for when OrbB is channelled.
- Orb Targeting
When channelling an orb you can tell it to target a specific enemy much like you would a regular attack. The orb will attack the target, if the target has died any other orbs targeting that enemy will pick a new enemy at random.
- Calculate Orb damage based on Strength, Weakened, Flight
- Calculate Orb block based on Dexterity, Frail
- Evoking all orbs of a specific type
- Removing all orbs of a specific type
- Trigger channelled orb effect on victory
- Orb Intents, see intents here
- CHANNELLED
- EVOKED
- REMOVED
- REMOVED_OR_EVOKED
- RIGHT_CLICKED
Removed orbs are removed without being evoked. For example, an Orb that has effectiveness that hits its turn limit before being evoked.
- onRightClick
OrbLib lets you right click your orb slots to trigger effects. This function is what is called.
- onRemoved
OrbLib lets you remove orbs without evoking them. This function is what is called.
- onVictory(isPlayerDying)
OrbLib lets channelled orbs trigger an effect on victory. This function is what is called.
Utility functions are all static functions within OrbLibUtils.
- Removing Orbs at specific orb indexes
- Evoking Orbs at specific orb indexes
- Get random new defect orbs
- Get specific orb index
- Check if any orb exists
- Get a list of AbstractOrb of any orb you have that isn't empty.
- Increasing your max orb count without the 10 orb limit.
- Get Orbs of specific type
While OrbLib aims to keep base game patches to a minimum The Defect has been patched so that he uses orbs that use the framework rather then his usual orbs. Don't worry if your mod uses his base game orbs they still happily exist and function like usual.
The new versions his cards, potions and relics channel are:
- DefectLightningOrb
- DefectFrostOrb
- DefectDarkOrb
- DefectPlasmaOrb
Having it patched like this allows Defects orb channel cards to be compatible with other characters also using OrbLib
I've heard your feedback. I have made the Defect base game patches an optional toggle in the OrbLib mod config. This patch is DISABLED by default.
import orbLib.OrbLib;
import orbLib.orbs.ExtendedOrb;
import orbLib.util.OrbListenerAction.OrbListenerType;
public class StrikeOrb extends ExtendedOrb {
public StrikeOrb() {
// Orb constructor stuff here
// What does the Strike Orb do when a DefendOrb is channelled?
OrbLib.orbListener.AddListener(getClass(), DefendOrb.class, OrbListenerType.CHANNELLED, (channelledOrbName) -> {
System.out.println(channelledOrbName + " was channelled.");
});
// What does the Strike Orb do when a DefendOrb is Evoked
OrbLib.orbListener.AddListener(getClass(), DefendOrb.class, OrbListenerType.EVOKED, (evokedOrbName) -> {
System.out.println(evokedOrbName + " was evoked.");
});
// What does the Strike Orb do when a DefendOrb is Removed (Not evoked)
OrbLib.orbListener.AddListener(getClass(), DefendOrb.class, OrbListenerType.REMOVED, (removedOrbName) -> {
System.out.println(removedOrbName + " was removed.");
});
// What does the Strike Orb do when a DefendOrb is either Removed or Evoked
OrbLib.orbListener.AddListener(getClass(), DefendOrb.class, OrbListenerType.EVOKED_OR_REMOVED, (evokedOrRemovedOrbName) -> {
System.out.println(evokedOrRemovedOrbName + " was evoked or removed.");
});
// What does the Strike Orb do when a DefendOrb is Right Clicked
OrbLib.orbListener.AddListener(getClass(), DefendOrb.class, OrbListenerType.RIGHT_CLICKED, (evokedOrRemovedOrbName) -> {
System.out.println(evokedOrRemovedOrbName + " was right clicked.");
});
// Apply a listener to multiple orbs at once
ArrayList<Class<?>> listOfOrbs = new ArrayList<Class<?>>();
listOfOrbs.add(DefendOrb.class);
listOfOrbs.add(PoisonOrb.class);
listOfOrbs.add(WeakenOrb.class);
OrbLib.orbListener.AddListenerMultiple(getClass(), orbsList, OrbListenerType.EVOKED, (className) -> {
System.out.println("One of the listed orbs was evoked. It was " + className);
});
}
}
... Previous code example
@Override
public void onEvoked() {
if(isLastOfCurrentType()) {
RemoveAllOrbListeners();
}
}
... Previous code example
@Override
public void onRightClicked() {
// Stop listening to the CHANNELLED event of DefendOrbs
RemoveOrbListener(DefendOrb.class, OrbListenerType.CHANNELLED);
}
...Orb code
public StrikeOrb() {
OrbLib.orbListener.AddListener(getClass(), DefendOrb.class, OrbListenerType.EVOKED, (evokedOrbName) -> {
System.out.println(evokedOrbName + " was evoked.");
});
OrbLib.orbListener.AddListener(getClass(), PoisonOrb.class, OrbListenerType.EVOKED, (evokedOrbName) -> {
System.out.println(evokedOrbName + " was evoked.");
});
OrbLib.orbListener.AddListener(getClass(), WeakOrb.class, OrbListenerType.CHANNELLED, (evokedOrbName) -> {
System.out.println(evokedOrbName + " was evoked.");
});
}
@Override
public void onEvoked() {
... Evoke code
// Is this the last of our strike orbs if so remove all our evoked listeners.
if(isLastOfCurrentType()) {
// Remove our 2 EVOKE listeners we setup, the CHANNELLED one remains.
RemoveAllOrbListenersOfType(OrbListenerType.EVOKED);
}
}
... Previous code example
@Override
public void onStartOfTurn() {
boolean shouldEvoke = true;
... Code determining if the orb should be evoked or not at start of turn
if(shouldEvoke) {
evoke(); // Evoke this orb
} else {
remove(); // Just remove the orb, don't evoke
}
}
... Orb code
// Evoke the orb in our third slot
OrbLibUtils.evokeOrbAt(2);
...Orb code
// Evoke all DefendOrbs
int evokedCount = OrbLibUtils.evokeOrbsOfType(DefendOrb.class); // returns the number of orbs that were evoked
int removedCount = OrbLibUtils.removeOrbsOfType(DefendOrb.class); // returns the number of orbs that were removed
for(int i = 0; i < evokedCount; i++) {
// Add one strength for every orb that was evoked
AbstractDungeon.actionManager.addToBottom(new VFXAction(new OrbFlareEffect(this, OrbFlareEffect.OrbFlareColor.FROST), 0.1f));
AbstractDungeon.actionManager.addToBottom(new ApplyPowerAction(AbstractDungeon.player, AbstractDungeon.player, new StrengthPower(AbstractDungeon.player, 1), 1));
}
Effectiveness is essentially a turn counter for orbs. When their effectiveness reaches 0 they are removed and not evoked. Ingame their effectiveness counter is displayed below their Magic Number
public class StrikeOrb extends ExtendedOrb {
... Variables
public StrikeOrb() {
// Orb constructor stuff here
loseEffectOverTime = true; // This orb is removed after x turns
effectAmount = 1; // After 1 turn remove the orb
}
... Other code
}
OrbLib comes with a calculateDamage(int damage) function and calculateBlock(int block) function that are used to take in the amount damage you wish to deal or block you wish to gain and calculates it taking buffs and debuffs into account and outputting the correct value.
ExtendedOrb also comes with a renderText(SpriteBatch sb, int passiveAmount, int evokeAmount, int calculated) function that will render text based on where it lies in the calculate. If the calculated value is less then the passive or evoke amounts it will be red, if its more it'll be green and if its equal it'll be white.
... code here
@Override
public void render(SpriteBatch sb) {
... render code
// Color based on damage
renderText(sb, BASE_PASSIVE_AMOUNT, BASE_EVOKE_AMOUNT, (int) calculateDamage(this.showEvokeValue ? evokeAmount : passiveAmount))
}
Targeting an enemy has a few steps.
- We use the "use" method of our card to pass in the monster we wish to attack
- Add "AbstractMonster" as a paremeter in your orb constructor
- ExtendedOrb contains an orbTarget variable assign it to the one we define in the constructor
If the orbTarget is null when the OrbDamageEnemyAction is called it targets a random enemy.
// In our card
@Override
public void use(AbstractPlayer player, AbstractMonster monster) {
AbstractDungeon.actionManager.addToBottom(new ExtendedChannelAction(new StrikeOrb(monster)));
}
// In our orb
public class StrikeOrb extends ExtendedOrb {
public StrikeOrb(AbstractMonster target) {
... Other constructor code
this.orbTarget = target;
if(this.orbTarget == null) {
this.orbTarget = getRandomTarget();
}
}
@Override
public void onEndOfTurn() {
AbstractDungeon.actionManager.addToBottom(
new VFXAction(new OrbFlareEffect(this, OrbFlareEffect.OrbFlareColor.FROST), 0.1f));
int dmg = (int) calculateDamage(passiveAmount);
AbstractDungeon.actionManager.addToBottom(
new OrbDamageEnemyAction(this, this.orbTarget, new DamageInfo(AbstractDungeon.player, dmg, DamageInfo.DamageType.NORMAL), AbstractGameAction.AttackEffect.SLASH_DIAGONAL));
}
... Other code
}
... Orb code
@Override
public void onRightClicked() {
// Give the player 1 strength and remove the orb.
AbstractDungeon.actionManager.addToBottom(new VFXAction(new OrbFlareEffect(this, OrbFlareEffect.OrbFlareColor.FROST), 0.1f));
AbstractDungeon.actionManager.addToBottom(new ApplyPowerAction(AbstractDungeon.player, AbstractDungeon.player, new StrengthPower(AbstractDungeon.player, 1), 1));
remove();
}
...Orb code
@Override
public void onVictory(boolean playerIsDying) {
if(!playerIsDying) {
System.out.println("Channelled orb effect. Victory.");
}
}
Orb intents are something you can apply when you channel an orb, these can either target an enemy or the player. They are a small indicator to help you keep track of what your orbs are doing. However you will have to tell the orbs when to add or remove the intents.
NOTE: Orb intents are purely optional. You don't have to use them if you don't want too. If you want to turn off orb intents all together they can be turned off in the OrbLib mod config.
There are currently 7 orb intents.
- new OrbIntentAggressive(target, amount)
- new OrbIntentDefensive(target, amount)
- new OrbIntentBuff(target, amount)
- new OrbIntentDebuff(target, amount)
- new OrbIntentSleep(target, amount)
- new OrbIntentStun(target, amount)
- new OrbIntentUnknown(target, amount)
There are 4 functions to control adding and removing intent, these are accessible to any orbs extending ExtendedOrb
- addIntent(target, orbIntent)
- addIntentAllEnemies(orbIntent)
- removeIntent(target, orbIntent)
- removeIntentAllEnemies(orbIntent)
public class StrikeOrb extends ExtendedOrb {
public StrikeOrb(AbstractMonster target) {
... Other constructor code
this.orbTarget = target;
if(this.orbTarget == null) {
this.orbTarget = getRandomTarget();
}
int passive = (int) calculateDamage(passiveAmount);
addIntent(this.orbTarget, new OrbIntentAggressive(this.orbTarget, passive));
}
@Overrride
public void onEvoked() {
.. Evoke code
int dmg = (int) calculateDamage(passiveAmount);
removeIntent(this.orbTarget, new OrbIntentAggressive(null, dmg));
}
@Override
public void onEndOfTurn() {
... Code to damage the enemy target
int dmg = (int) calculateDamage(passiveAmount);
removeIntent(this.orbTarget, new OrbIntentAggressive(null, dmg));
}
... Other code
}
public class PoisonOrb extends ExtendedOrb {
public PoisonOrb () {
... Other constructor code
// Since we are applying to all enemies the orb intent target can be null
addIntentAllEnemies(new OrbIntentDebuff(null, passiveAmount));
}
@Overrride
public void onEvoked() {
.. Evoke code
removeIntentAllEnemies(new OrbIntentDebuff(null, passiveAmount));
}
@Override
public void onEndOfTurn() {
.. Code to apply effects
removeIntentAllEnemies(new OrbIntentDebuff(null, passiveAmount));
}
... Other code
}
public class DefendOrb extends ExtendedOrb {
public DefendOrb () {
... Other constructor code
// Apply the defensive orb intent to the player
addIntent(AbstractDungeon.player, new OrbIntentDefensive(AbstractDungeon.player, passiveAmount));
}
@Overrride
public void onEvoked() {
.. Evoke code
int block = (int) calculateBlock(passiveAmount);
removeIntent(AbstractDungeon.player, new OrbIntentDefensive(null, block));
}
@Override
public void onEndOfTurn() {
.. Code to apply effects
int block = (int) calculateBlock(passiveAmount);
removeIntent(AbstractDungeon.player, new OrbIntentDefensive(null, block));
}
... Other code
}
Applying a defense to the player and applying a debuff and aggression to the enemy
Nope, Orbs made by using AbstractOrb or CustomOrb can happily co-exist with ExtendedOrbs, do note though that those orbs may not be affected by stuff provided by the framework such as the Orb Listener.
His old orbs themselves remain intact untouched by OrbLib. OrbLib only patches the cards, relics and potions he has that channels them to channel the new versions instead. If the patch is disabled he uses his regular orbs.
Channeling a raw AbstractOrb or CustomOrb with ExtendedChannelAction will not work as it expects an ExtendedOrb. However channeling with ChannelAction will work just fine.
Of course, the ExtendedOrbs are a child of CustomOrb and will function just fine with the regular ChannelAction.
That's ok ExtendedChannelAction has an additional constructor that takes in an ExtendedOrb and a boolean. The boolean determines if it should evoke all your orbs or not at full capacity. This way you can control whether or not you want this feature to trigger.
I do, however he is not ready just yet.
Yes, inside the OrbLib config found in the mod menu you can find a small toggle for enabling and disabling it by default. Alternatively, you can choose to use ChannelAction instead of ExtendedChannelAction and that will work just fine.
Currently they do not, the system is designed to work with orbs from this framework. However if there is enough demand for it I try and find a way to make it work with CustomOrb and AbstractOrb orbs.
OrbLib by Lyraedan (ItsLuke)