Added a new ItemStat to CATALYSTs and OFF-CATALYSTS to allow an item to bypsass Two-Handedness

Issue with outdated particle stat regarding JSON sintax should be fixed.

Mysterious issue regarding 'FlagPlugin' may be fixed.
This commit is contained in:
Gunging 2021-01-31 12:56:49 -06:00
parent 44fc5dd9ce
commit 5edacc6e37
12 changed files with 351 additions and 92 deletions

View File

@ -1,77 +1,8 @@
package net.Indyuce.mmoitems;
import net.Indyuce.mmoitems.stat.CompatibleIds;
import net.Indyuce.mmoitems.stat.RepairType;
import net.Indyuce.mmoitems.stat.*;
import org.bukkit.Material;
import net.Indyuce.mmoitems.stat.Abilities;
import net.Indyuce.mmoitems.stat.Armor;
import net.Indyuce.mmoitems.stat.ArmorToughness;
import net.Indyuce.mmoitems.stat.ArrowParticles;
import net.Indyuce.mmoitems.stat.ArrowPotionEffects;
import net.Indyuce.mmoitems.stat.AttackDamage;
import net.Indyuce.mmoitems.stat.AttackSpeed;
import net.Indyuce.mmoitems.stat.CanDeconstruct;
import net.Indyuce.mmoitems.stat.CanDeskin;
import net.Indyuce.mmoitems.stat.CanIdentify;
import net.Indyuce.mmoitems.stat.Commands;
import net.Indyuce.mmoitems.stat.CompatibleTypes;
import net.Indyuce.mmoitems.stat.Crafting;
import net.Indyuce.mmoitems.stat.CustomModelData;
import net.Indyuce.mmoitems.stat.CustomSounds;
import net.Indyuce.mmoitems.stat.DisableAdvancedEnchantments;
import net.Indyuce.mmoitems.stat.DisplayName;
import net.Indyuce.mmoitems.stat.DyeColor;
import net.Indyuce.mmoitems.stat.Effects;
import net.Indyuce.mmoitems.stat.Elements;
import net.Indyuce.mmoitems.stat.Enchants;
import net.Indyuce.mmoitems.stat.GemColor;
import net.Indyuce.mmoitems.stat.GemSockets;
import net.Indyuce.mmoitems.stat.GrantedPermissions;
import net.Indyuce.mmoitems.stat.HideDye;
import net.Indyuce.mmoitems.stat.HideEnchants;
import net.Indyuce.mmoitems.stat.HidePotionEffects;
import net.Indyuce.mmoitems.stat.Inedible;
import net.Indyuce.mmoitems.stat.InternalRevisionID;
import net.Indyuce.mmoitems.stat.ItemDamage;
import net.Indyuce.mmoitems.stat.ItemLevel;
import net.Indyuce.mmoitems.stat.ItemParticles;
import net.Indyuce.mmoitems.stat.ItemSetStat;
import net.Indyuce.mmoitems.stat.ItemTierStat;
import net.Indyuce.mmoitems.stat.ItemTypeRestriction;
import net.Indyuce.mmoitems.stat.KnockbackResistance;
import net.Indyuce.mmoitems.stat.Lore;
import net.Indyuce.mmoitems.stat.LoreFormat;
import net.Indyuce.mmoitems.stat.LostWhenBroken;
import net.Indyuce.mmoitems.stat.LuteAttackEffectStat;
import net.Indyuce.mmoitems.stat.LuteAttackSoundStat;
import net.Indyuce.mmoitems.stat.MaterialStat;
import net.Indyuce.mmoitems.stat.MaxHealth;
import net.Indyuce.mmoitems.stat.MaximumDurability;
import net.Indyuce.mmoitems.stat.MovementSpeed;
import net.Indyuce.mmoitems.stat.NBTTags;
import net.Indyuce.mmoitems.stat.PermanentEffects;
import net.Indyuce.mmoitems.stat.Permission;
import net.Indyuce.mmoitems.stat.PickaxePower;
import net.Indyuce.mmoitems.stat.PotionColor;
import net.Indyuce.mmoitems.stat.PotionEffects;
import net.Indyuce.mmoitems.stat.RepairPower;
import net.Indyuce.mmoitems.stat.RequiredClass;
import net.Indyuce.mmoitems.stat.RequiredLevel;
import net.Indyuce.mmoitems.stat.RevisionID;
import net.Indyuce.mmoitems.stat.ShieldPatternStat;
import net.Indyuce.mmoitems.stat.SkullTextureStat;
import net.Indyuce.mmoitems.stat.Soulbound;
import net.Indyuce.mmoitems.stat.SoulbindingBreakChance;
import net.Indyuce.mmoitems.stat.SoulbindingChance;
import net.Indyuce.mmoitems.stat.SoulboundLevel;
import net.Indyuce.mmoitems.stat.StaffSpiritStat;
import net.Indyuce.mmoitems.stat.StoredTags;
import net.Indyuce.mmoitems.stat.SuccessRate;
import net.Indyuce.mmoitems.stat.Unbreakable;
import net.Indyuce.mmoitems.stat.Unstackable;
import net.Indyuce.mmoitems.stat.UpgradeStat;
import net.Indyuce.mmoitems.stat.VanillaEatingAnimation;
import net.Indyuce.mmoitems.stat.block.BlockID;
import net.Indyuce.mmoitems.stat.block.GenTemplate;
import net.Indyuce.mmoitems.stat.block.MaxXP;
@ -204,6 +135,7 @@ public class ItemStats {
VANILLA_EATING_ANIMATION = new VanillaEatingAnimation(),
INEDIBLE = new Inedible(),
GEM_COLOR = new GemColor(),
//todo GEM_UPGRADE_SCALING = new GemUpgradeScaling(),
ITEM_TYPE_RESTRICTION = new ItemTypeRestriction(),
MAX_CONSUME = new DoubleStat("MAX_CONSUME", Material.BLAZE_POWDER, "Max Consume", new String[]{"Max amount of usage before", "item disappears."}, new String[]{"consumable"}),
SUCCESS_RATE = new SuccessRate(),
@ -232,6 +164,7 @@ public class ItemStats {
REPAIR_TYPE = new RepairType(),
KNOCKBACK = new DoubleStat("KNOCKBACK", VersionMaterial.IRON_HORSE_ARMOR.toMaterial(), "Knockback", new String[]{"Using this musket will knock", "the user back if positive."}, new String[]{"musket"}),
RECOIL = new DoubleStat("RECOIL", VersionMaterial.IRON_HORSE_ARMOR.toMaterial(), "Recoil", new String[]{"Corresponds to the shooting innacuracy."}, new String[]{"musket"}),
HANDWORN = new BooleanStat("HANDWORN", Material.STRING, "Handworn", new String[]{"This item ignores two-handedness.", "", "Basically for a ring or a glove that you", "can wear and still have your hand free", " to carry a two-handed weapon."}, new String[]{ "offhand" }),
// Abilities & Upgrading
ABILITIES = new Abilities(),

View File

@ -536,17 +536,31 @@ public class MMOItems extends JavaPlugin {
return stringInputParsers;
}
/**
* Decide by which system will the RPG Requirements of the player will be checked.
* <p></p>
* For example, required level, is that vanilla XP levels, MMOCore levels, McMMO Leves or what?
*/
public void findRpgPlugin() {
if (rpgPlugin != null)
return;
for (RPGHandler.PluginEnum plugin : RPGHandler.PluginEnum.values())
// For each supported plugin
for (RPGHandler.PluginEnum plugin : RPGHandler.PluginEnum.values()) {
// Found the plugin?
if (Bukkit.getPluginManager().getPlugin(plugin.getName()) != null) {
// Load that one
setRPG(plugin.load());
getLogger().log(Level.INFO, "Hooked onto " + plugin.getName());
// Mention it
SLog("Using \u00a76" + plugin.getName() + "\u00a77 as RPG Player provider.");
return;
}
}
// Just use the default
setRPG(new DefaultHook());
}
@ -611,9 +625,18 @@ public class MMOItems extends JavaPlugin {
/**
* Logs something into the console with a cool [MMOItems] prefix :)
* <p></p>
* Parses color codes
* Parses color codes. <b>Meant for DEV testing</b>, all of them are removed every release.
*/
public static void Log(String message) {
plugin.getLogger().log(Level.INFO, "\u00a78[" + ChatColor.YELLOW + "MMOItems\u00a78] \u00a77");
plugin.getServer().getConsoleSender().sendMessage("\u00a78[" + ChatColor.YELLOW + "MMOItems\u00a78] \u00a77" + message);
}
/**
* Logs something into the console with a cool [MMOItems] prefix :)
* <p></p>
* Parses color codes, official method. Wont be removed when releasing MMOItems versions.
*/
public static void SLog(String message) {
plugin.getServer().getConsoleSender().sendMessage("\u00a78[" + ChatColor.YELLOW + "MMOItems\u00a78] \u00a77" + message);
}
}

View File

@ -2,6 +2,7 @@ package net.Indyuce.mmoitems;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.mmogroup.mmolib.MMOLib;
import org.apache.commons.codec.binary.Base64;
import org.bukkit.ChatColor;
@ -119,17 +120,13 @@ public class MMOUtils {
return item.hasItemMeta() && item.getItemMeta().hasDisplayName() ? item.getItemMeta().getDisplayName() : caseOnWords(item.getType().name().toLowerCase().replace("_", " "));
}
/**
* Is the player encumbered by carrying two-handed items?
*/
public static boolean twoHandedCase(Player player) {
int normal = 0, twoHanded = 0;
for (ItemStack item : new ItemStack[]{player.getInventory().getItemInMainHand(), player.getInventory().getItemInOffHand()})
if (item.getType() != Material.AIR) {
normal++;
if (MMOLib.plugin.getVersion().getWrapper().getNBTItem(item).getBoolean("MMOITEMS_TWO_HANDED"))
twoHanded++;
}
return twoHanded > 0 && normal > 1;
// Straight from player data
return PlayerData.get(player).areHandsFull();
}
public static String caseOnWords(String s) {

View File

@ -119,7 +119,7 @@ public class ItemStackBuilder {
// Attempt to add
try {
//
// Make necessary lore changes
stat.whenApplied(this, mmoitem.getData(stat));
// Something went wrong...

View File

@ -2,6 +2,7 @@ package net.Indyuce.mmoitems.api.item.mmoitem;
import java.util.logging.Level;
import org.bukkit.ChatColor;
import org.bukkit.inventory.ItemStack;
import net.Indyuce.mmoitems.MMOItems;
@ -32,12 +33,22 @@ public class LiveMMOItem extends ReadMMOItem {
public LiveMMOItem(NBTItem item) {
super(item);
// Reads all the stats that this type could possibly have.
for (ItemStat stat : getType().getAvailableStats())
// Attempts to load it
try {
// Will not do much if the stat is missing from the item
stat.whenLoaded(this);
// Some unknown error happened. L
} catch (IllegalArgumentException exception) {
MMOItems.plugin.getLogger().log(Level.WARNING,
"Could not load stat '" + stat.getId() + "'item data from '" + getId() + "': " + exception.getMessage());
ChatColor.GRAY + "Could not load stat '"
+ ChatColor.GOLD + stat.getId() + ChatColor.GRAY + "'item data from '"
+ ChatColor.RED + getId() + ChatColor.GRAY + "': "
+ ChatColor.YELLOW + exception.getMessage());
}
}
}

View File

@ -5,6 +5,7 @@ import java.util.logging.Level;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import net.mmogroup.mmolib.api.item.NBTItem;
import org.bukkit.ChatColor;
public class VolatileMMOItem extends ReadMMOItem {
@ -30,11 +31,20 @@ public class VolatileMMOItem extends ReadMMOItem {
@Override
public boolean hasData(ItemStat stat) {
if (!super.hasData(stat))
// Attempt to lad this stat data
try {
stat.whenLoaded(this);
// Nope
} catch (IllegalArgumentException exception) {
// Log a warning
MMOItems.plugin.getLogger().log(Level.WARNING,
"Could not load stat '" + stat.getId() + "'item data from '" + getId() + "': " + exception.getMessage());
ChatColor.GRAY + "Could not load stat '"
+ ChatColor.GOLD + stat.getId() + ChatColor.GRAY + "'item data from '"
+ ChatColor.RED + getId() + ChatColor.GRAY + "': "
+ ChatColor.YELLOW + exception.getMessage());
}
return super.hasData(stat);
}

View File

@ -8,6 +8,7 @@ import java.util.Map;
import java.util.Set;
import java.util.UUID;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
@ -148,10 +149,20 @@ public class PlayerData {
if (!mmoData.isOnline())
return false;
// Get the mainhand and offhand items.
NBTItem main = MMOLib.plugin.getVersion().getWrapper().getNBTItem(getPlayer().getInventory().getItemInMainHand());
NBTItem off = MMOLib.plugin.getVersion().getWrapper().getNBTItem(getPlayer().getInventory().getItemInOffHand());
return (main.getBoolean("MMOITEMS_TWO_HANDED") && (off.getItem() != null && off.getItem().getType() != Material.AIR))
|| (off.getBoolean("MMOITEMS_TWO_HANDED") && (main.getItem() != null && main.getItem().getType() != Material.AIR));
// Is either hand two-handed?
boolean mainhand_twohanded = main.getBoolean(ItemStats.TWO_HANDED.getNBTPath());
boolean offhand_twohanded = off.getBoolean(ItemStats.TWO_HANDED.getNBTPath());
// Is either hand encumbering: Not NULL, not AIR, and not Handworn
boolean mainhand_encumbering = (main.getItem() != null && main.getItem().getType() != Material.AIR && !main.getBoolean(ItemStats.HANDWORN.getNBTPath()));
boolean offhand_encumbering = (off.getItem() != null && off.getItem().getType() != Material.AIR && !off.getBoolean(ItemStats.HANDWORN.getNBTPath()));
// Will it encumber?
return (mainhand_twohanded && offhand_encumbering) || (mainhand_encumbering && offhand_twohanded);
}
@SuppressWarnings("deprecation")

View File

@ -42,18 +42,38 @@ public abstract class RPGPlayer {
return playerData.getPlayer();
}
/**
* Main profile level of the player.
* <p></p>
* Used in the REQUIRED_LEVEL item stat, and crafting stations with the level condition.
*/
public abstract int getLevel();
public abstract String getClassName();
/**
* The mana the player currently has.
* <p></p>
* Sometimes an internal quantity, sometimes the hunger bar, etc...
*/
public abstract double getMana();
public abstract double getStamina();
/**
* Sets the mana of the player.
* <p></p>
* Sometimes an internal quantity, sometimes the hunger bar, etc...
*/
public abstract void setMana(double value);
public abstract void setStamina(double value);
/**
* Increases or substracts mana to the player.
* <p></p>
* Sometimes an internal quantity, sometimes the hunger bar, etc...
*/
public void giveMana(double value) {
setMana(getMana() + value);
}

View File

@ -1,5 +1,6 @@
package net.Indyuce.mmoitems.comp.rpg;
import net.Indyuce.mmoitems.MMOItems;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@ -51,9 +52,27 @@ public class McMMOHook implements RPGHandler, Listener {
@Override
public int getLevel() {
//RPG*/MMOItems. Log("Getting level of \u00a7c" + getPlayer().getName());
// No errors, right?
try {
return ExperienceAPI.getPowerLevel(getPlayer());
// Get through Experience API I suppose
int r = ExperienceAPI.getPowerLevel(getPlayer());
// Log rq
//RPG*/MMOItems. Log("\u00a76 + \u00a77Found level as \u00a7c" + r);
// thats it
return r;
// A problem may have occured
} catch (McMMOPlayerNotFoundException exception) {
// Log rq
//RPG*/MMOItems. Log("\u00a76 - \u00a77No data found. Using \u00a7c0");
// Thats it
return 0;
}
}

View File

@ -0,0 +1,37 @@
package net.Indyuce.mmoitems.stat;
import net.Indyuce.mmoitems.stat.type.ChooseStat;
import net.Indyuce.mmoitems.stat.type.GemStoneStat;
import net.mmogroup.mmolib.version.VersionMaterial;
import org.bukkit.Material;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
/**
* Defines how gem stats will scale when the item they are put on upgrades.
*/
public class GemUpgradeScaling extends ChooseStat implements GemStoneStat {
public static final String NEVER = "NEVER", HISTORIC = "HISTORIC", SUBSEQUENT = "SUBSEQUENT";
public GemUpgradeScaling() {
super("GEM_UPGRADE_SCALING", VersionMaterial.LIME_DYE.toMaterial(), "Gem Upgrade Scaling", new String[] { "Gem stones add their stats to items, but you may also", "upgrade your items via crafting stations or consumables.", "", "\u00a76Should this gem stone stats be affected by upgrading?" }, new String[] { "gem_stone" });
// Create the list
ArrayList<String> applicationScalingTypes = new ArrayList<>();
Collections.addAll(applicationScalingTypes, SUBSEQUENT, NEVER, HISTORIC);
// Set the acceptable values
InitializeChooseableList(applicationScalingTypes);
// Put definitions
HashMap<String, String> definitions = new HashMap<>();
definitions.put(SUBSEQUENT, "Gem stats scale by upgrading the item, but only after putting the gem in.");
definitions.put(NEVER, "Gem stats are never scaled by upgrading the item.");
definitions.put(HISTORIC, "Gem stats instantly upgrade to the current item level, and subsequently thereafter.");
// Update
HintChooseableDefs(definitions);
}
}

View File

@ -107,9 +107,9 @@ public class ItemParticles extends ItemStat {
public void whenLoaded(ReadMMOItem mmoitem) {
if (mmoitem.getNBT().hasTag("MMOITEMS_ITEM_PARTICLES"))
try {
mmoitem.setData(ItemStats.ITEM_PARTICLES,
new ParticleData(new JsonParser().parse(mmoitem.getNBT().getString("MMOITEMS_ITEM_PARTICLES")).getAsJsonObject()));
} catch (JsonSyntaxException exception) {
mmoitem.setData(ItemStats.ITEM_PARTICLES, new ParticleData(new JsonParser().parse(mmoitem.getNBT().getString("MMOITEMS_ITEM_PARTICLES")).getAsJsonObject()));
} catch (JsonSyntaxException|IllegalStateException exception) {
/*
* OLD ITEM WHICH MUST BE UPDATED.
*/

View File

@ -0,0 +1,198 @@
package net.Indyuce.mmoitems.stat.type;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.edition.StatEdition;
import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
import net.Indyuce.mmoitems.api.item.mmoitem.ReadMMOItem;
import net.Indyuce.mmoitems.gui.edition.EditionInventory;
import net.Indyuce.mmoitems.stat.data.StringData;
import net.Indyuce.mmoitems.stat.data.random.RandomStatData;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.mmogroup.mmolib.MMOLib;
import net.mmogroup.mmolib.api.item.ItemTag;
import net.mmogroup.mmolib.api.util.AltChar;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
/**
* Choose Stats present a list of options from which the user may choose one.
* <p></p>
* You could consider them a more advanced DisableStat, while DisableStat only
* allows to choose <b>true</b> or <b>false</b>, alternating when clicked, Choose
* Stats cycle through a list instead.
*/
public abstract class ChooseStat extends StringStat {
public ChooseStat(String id, Material mat, String name, String[] lore, String[] types, Material... materials) {
super(id, mat, name, lore, types, materials);
}
@Override
public RandomStatData whenInitialized(Object object) {
// Return a string data I guess
return new StringData(object.toString());
}
@Override
public void whenApplied(ItemStackBuilder item, StatData data) {
// Add tag to item
item.addItemTag(new ItemTag(getNBTPath(), data.toString()));
// Insert lore line
item.getLore().insert(getPath(), data.toString());
}
@Override
public void whenClicked(EditionInventory inv, InventoryClickEvent event) {
Validate.isTrue(chooseableList.size() > 0, "\u00a77Invalid Chooseable Item Stat " + ChatColor.GOLD + getId() + "\u00a77' - \u00a7cNo options to choose from.");
// If removing, reset to default
if (event.getAction() == InventoryAction.PICKUP_HALF) {
// Edits into persistent files
inv.getEditedSection().set(getPath(), null);
inv.registerTemplateEdition();
// Mention that it was removed
inv.getPlayer().sendMessage(MMOItems.plugin.getPrefix() + "Successfully removed " + getName() + ".");
} else {
// Get current
String current = inv.getEditedSection().getString(getPath());
// Included?
int currentIndex = 0;
if (current != null && chooseableList.contains(current)) { currentIndex = chooseableList.indexOf(current);}
// Increase and Cap
currentIndex++;
if (currentIndex >= chooseableList.size()) { currentIndex = 0; }
// Get
current = chooseableList.get(currentIndex);
// Edits into persistent files
inv.getEditedSection().set(getPath(), current);
inv.registerTemplateEdition();
// Sends a message
inv.getPlayer().sendMessage( MMOItems.plugin.getPrefix() + getName() + " successfully changed to " + current + ChatColor.GRAY + ".");
}
}
@Override
public void whenInput(EditionInventory inv, String message, Object... info) {
// Edits into persistent files
inv.getEditedSection().set(getPath(), message);
inv.registerTemplateEdition();
// Sends a message
inv.getPlayer().sendMessage( MMOItems.plugin.getPrefix() + getName() + " successfully changed to " + MMOLib.plugin.parseColors(message) + ChatColor.GRAY + ".");
}
@Override
public void whenLoaded(ReadMMOItem mmoitem) {
// If the item has such NBT path, load it.
if (mmoitem.getNBT().hasTag(getNBTPath()))
mmoitem.setData(this, new StringData(mmoitem.getNBT().getString(getNBTPath())));
}
@Override
public void whenDisplayed(List<String> lore, Optional<RandomStatData> statData) {
Validate.isTrue(chooseableList.size() > 0, "\u00a77Invalid Chooseable Item Stat " + ChatColor.GOLD + getId() + "\u00a77' - \u00a7cNo options to choose from.");
// To display current choosing, gets the very first element
String def = chooseableList.get(0);
// Does this item have any specified value for this?
if (statData.isPresent()) {
// Put in current
def = statData.get().toString();
// Display the value of the current stat data
lore.add(ChatColor.GRAY + "Current Value: " + ChatColor.GREEN + def);
} else {
// Mention that it currently has no value
lore.add(ChatColor.GRAY + "Current Value: " + ChatColor.RED + def);
}
// Get Definition
if (chooseableDefs.containsKey(def)) { for (String deff : Chop(chooseableDefs.get(def), 50)) { lore.add(ChatColor.GRAY + " " + deff); } }
lore.add("");
lore.add(ChatColor.YELLOW + AltChar.listDash + " Right click to return to default value.");
lore.add(ChatColor.YELLOW + AltChar.listDash + " Left click to cycle through the available options:");
for (String str : chooseableList) {
// Is it the one?
String pick = ChatColor.GOLD.toString();
if (str.equals(def)) { pick = ChatColor.RED.toString() + ChatColor.BOLD.toString();}
lore.add(pick + " " + AltChar.smallListDash + " \u00a77" + str);
}
}
/**
* Contains the list of different options the player may choose from.
* <b>Make sure its is always initialized and with at least 1 element</b>
*/
@NotNull ArrayList<String> chooseableList;
public void InitializeChooseableList(@NotNull ArrayList<String> list) { chooseableList = list; }
/**
* Definitions of what each choosing type does, for display in lore.
*/
@NotNull HashMap<String, String> chooseableDefs = new HashMap<>();
public void HintChooseableDefs(@NotNull HashMap<String, String> list) { chooseableDefs = list; }
/**
* Chops a long description into several parts.
*/
ArrayList<String> Chop(String longString, int paragraphWide) {
// Ret
ArrayList<String> ret = new ArrayList<>();
boolean skip = false;
// While longer
while (longString.length() > paragraphWide) {
// Skip
skip = true;
// Get the wide
int idx = longString.lastIndexOf(" ", paragraphWide + 1);
// Chop
ret.add(longString.substring(0, idx));
// Update
longString = longString.substring(idx + 1);
// Add final.
if (longString.length() <= paragraphWide) { ret.add(longString); }
}
// Wasnt long at all
if (!skip) { ret.add(longString); }
// Thats it
return ret;
}
}