Proposal: Consider how to inoculate princesses as well as drones
rmunn opened this issue Β· 30 comments
Overall, the extra complexity of the Genetics machines in 2.0 (growth medium, three different kinds of bacteria, etc., as compared to 1.8 where all you needed was Liquid DNA) is likely to be fun for people who enjoy multi-step processes. I also like the way that you can't inoculate genetic traits into adult creatures (princesses and drones), but you have to use creatures in the early stages of development (larvae) so that the new genes have time to express themselves in the adult creature. All of that, I like.
However, there's one thing that was lost along the move from 1.8 to 2.0, and that was the ability to inoculate both the male and female bees so that the new species (or whatever trait) would be guaranteed to persist. With only the ability to inoculate drones, the Genetics mod's usefulness is immensely reduced, because you can't guarantee that the trait will be passed on to the offspring.
E.g., let's say I have a bunch of spare Rocky princesses and drones (which I have earlier given the "Fertility: 4 drones" trait to), and I want to turn them into Imperials. In 1.8, here's how the process went:
- Inoculate one Rocky princess with the Imperial species trait. It is now Imperial/Imperial.
- Inoculate one Rocky drone with the Imperial species trait. It is now Imperial/Imperial.
- Breed these two bees together.
- Result: a bunch of pure-bred Imperial bees (one princess and four drones), guaranteed to breed true as Imperial bees in the next generation(s).
In 2.0, here's how the process goes:
- Inoculate a Rocky larva with the Imperial species trait. It is now Imperial/Imperial.
- Can't inoculate princesses, so take a Rocky princess to breed. It is still Rocky/Rocky.
- Breed these two bees together.
- Result: Rocky/Imperial or Imperial/Rocky princess, and Rocky/Imperial or Imperial/Rocky drones.
- Breed the hybrid princess with one of the hybrid drones.
- Result: 25% chance of the Imperial/Imperial princess I'm looking for, 50% chance of another Imperial/Rocky hybrid, and 25% chance of losing the Imperial trait from the princess so that I end up with a plain Rocky/Rocky princess again, and I have to go back to step 1.
- I might end up going through this loop multiple times, which is no fun since it takes so long for the inoculator to do its work.
One possible solution that has its own problems would be to allow larvae to be turned into "royal larvae" by feeding them Royal Jelly in the Incubator. But the problem is:
- Do these "royal larvae" turned into Ignoble princesses? Then you'll have irate players complaining about how you can't use the Genetics machines for your "main" line of breeding (with Pristine princesses).
- Do these "royal larvae" turn into Pristine princesses? Then you've broken Forestry's bee-breeding balance over your knee by giving the possibility of multiple princesses. (Yes, there's an option in the Forestry config to turn on the chance of multiple princesses for anyone who wants an abundance of bees, but it's really only intended for skyblock maps.)
However, I think I can find a possible solution. Add another Genetics machine (maybe an Alveary block) that operates on queens -- and which has the effect of causing the queen to lay precisely one royal larva, and not leave behind a princess on death. (The royal larva is the princess, whose growth has been held back by the effect of this machine). The machine would require royal jelly as input, since it's feeding that royal jelly to the princess-in-larval-form to ensure that she grows up to become a real princess.
Or better yet, tweak the Hatchery block to do this. Create a new kind of frame, similar to the Chocolate Frame but with four Royal Jelly where the Chocolate Frame has four Cocoa. Call it the "Royal Frame". Then add a frame slot to the Hatchery, that will only accept a Royal Frame, and make sure the Royal Frame's tooltip says that it can only fit into a Hatchery frame slot. (The Royal Frame would have absolutely no effect if put into a regular frame slot in an Apiary or in a Frame Housing). Then if the Royal Frame is inserted into a Hatchery, then at the moment that the queen dies, the creation of a new princess is suppressed and the new princess becomes a Royal Larva instead. (There's a new, dedicated slot in the hatchery that can only accomodate princesses, so there's never any chance of missing out on the Royal Larva because all the hatchery's slots were full of drone larvae). That Royal Larva is ignoble if the queen was ignoble, and is pristine if the queen was pristine. Then the Royal Larva can be inoculated, just as the regular larvae can be inoculated, and the former balance from the 1.8 version of Binnie's Mods (where you could inoculate both princesses and drones) will be back. You can now inoculate drone larvae and princess larvae, but you haven't broken any of Forestry's balance: a single Pristine queen will still produce a single Pristine princess -- it's just that now, it takes longer for that princess to become an adult (and her genome might be messed with along the way).
Other ideas: instead of a dedicated slot for the Royal Larva, make the Royal Frame be a one-use-only thing, so that it vanishes when the Royal Larva shows up (and the Royal Larva lands in that frame slot, which is now guaranteed to be available). Or else dispense with the idea of a Royal Frame, and just make an extra slot in the hatchery block (the extra slot's shape could be a crown rather than a hexagon, maybe?). That extra slot takes Royal Jelly, and if it is filled with Royal Jelly, then when the queen dies the princess appears in that slot in larval form instead of appearing in the normal form.
Whatever method is settled on, I think it's a good idea to bring back the ability to inoculate princesses as well as drones, because the current method where you can only inoculate drones leads to gameplay that's just not very fun. Being able to inoculate princesses would bring a lot of the fun back, I think.
Another thought: this is, essentially, a proposal to change how the hatchery block works. Currently it produces larvae randomly (a 1/2400 chance per tick) while the alveary is operating. When combined with the incubator, that means that the player can get a large supply of drones even from bees with a "Fertility: 1 drone" trait. My current proposal changes how the hatchery works to create a royal drone at the moment of the queen's death (replacing the normal princess-creating behavior)... but what if that was how the hatchery worked for drones, too?
In other words, what if the hatchery's behavior was to simply change the output of the queen bee, having it produce larvae (one royal and 1-4 regular) at the end instead of 1 princess and 1-4 drones when the queen expires? That would make the hatchery a more consistent machine: my current proposal would have it behave differently for princesses and drones, which would probably lead to player confusion and a lot of "Where did my princess go?" threads on the forums. What if, instead, the hatchery block simply ensured that when the queen dies, the resulting drones and princess are larvae (and one royal larva) instead? (And the larvae would be output in the alveary's regular output slots, precisely where the princess and drones appear when there is no hatchery block).
The advantage of this change to the hatchery, besides making the royal-larva production more understandable, would be that the number of drones produced depends on the genetics of the queen. Currently the hatchery allows you to completely bypass the genetics of a "Fertility: 1 drone" bee, and get an abundance of drones from it. This kind of breaks the intended balance of the Forestry apiculture system. But changing the hatchery so that it simply changes the queen's output to be larvae instead of drones (and one royal larva instead of a princess) would maintain the original balance, where you need to breed the "Fertility: 1 drone" out of your bees in order to make them useful.
Perhaps this proposal (change the hatchery) should go in a separate issue so it can be discussed separately from the "allow inoculating princesses" proposal. But since the two proposals are somewhat related, I think it's worth discussing them both in the same comment thread since the resolution of each is going to be related as well.
EDIT: This proposal has been split out into #203; comments on the hatchery change should probably go there, not here.
I think that the ability to receive the princess's larvae will disrupt the current balance, in which the princesses have a limited amount. And lead to the fact that players will have so many princesses (especially pristine) that complexity and interest will fall. I do not think you want this.
Larvae of drones already very much simplify the life of the player. It seems to me normal that after the received drones, more work is needed to get the princess. The game must keep the player, and not give him the opportunity to develop very quickly.
Not in vain did Binnie remove this opportunity.
In addition, Forestry contains Swarmer block.
You'd also need to register a beeRoyalLarvaeGE
item in ItemRegistryApiculture, and check all the places where beeLarvaeGE
is used to make sure the logic can handle two types of larvae instead of just one. (E.g., the isDNAManipulable
method of BeeBreedingSystem will need to check for either kind of larvae, etc).
Also, the fact that this requires a Forestry change would mean that players would have to update Forestry at the same time that they update Extra Bees. So that just became a bigger change, which will need to be coordinated: e.g., a Forestry version of 4.3 instead of 4.2, and some code in Extra Bees that checks to make sure that Forestry is at least 4.3 (and if it isn't 4.3, then the princess-larvae feature of Extra Bees would be disabled).
I think that the ability to receive the princess's larvae will disrupt the current balance...
I agree, which is why my proposal was to replace the princess output with a royal larva. So you'd get the royal larva instead of the princess, not as well as the princess.
Then you've broken Forestry's bee-breeding balance
Not we. This is official continued from pre16+ version :)
I like the idea. If it is supported by others, I can try to do for 1.7.10. Thus, we will "run it". This block can be made disabled via config.
Doing this for 1.7.10 would allow me to test it out, so I'd be happy to give feedback.
About second feature. Sounds very cool to me.
I think we need to create new issue-questoin with this.
Okay, I've created #203 to keep track of my second suggestion.
So.
- add Royal Hatchery block (component Alveary)
- If block is installed, Queen after death turns into Royal Larvae, not Princess
- Royal Larvae inherits Ignoble or Pristine marker like Queen
- If Royal Jelly Frame is not contains in Royal Hatchery, do nothing, alveary works as expected
- After death Royal Jelly Frame adds damage
Royal Hatchery includes only input slot for Royal Jelly Frame.
Royal Jelly Frame has... 5? durability.
All right?
I'd say 4 durability rather than 5, since the recipe I'm thinking of would cost 4 Royal Jelly. (One Impregnated Frame in the center, plus four Royal Jelly in the N, S, E and W slots of the crafting grid). That way you get one Princess Larva per Royal Jelly, which seems like the right cost. (That is, you get a total of four uses out of the frame, and each use gets you a single Princess Larva. I'm NOT suggesting that you'd get four Princess Larvae at once!)
Or... in Minecraft, does an item break when it hits 0 durability? Or does 0 durability mean that it still has one use left? (I don't remember.) If 0 durability means "one use left", then the Royal Jelly Frame would have 3 durability when created, so that you get exactly four uses out of it.
Also, if #203 is implemented, then the functions of the Royal Hatchery could be merged with the revised Hatchery block, so only one version of the Hatchery would be needed instead of two. But for now while the Hatchery still functions as it currently does, adding a new Royal Hatchery block is probably the best way
If 0 durability means "one use left", then the Royal Jelly Frame would have 3
Yes, that's right
Drat. Of course the AlvearyController is an internal Forestry class. I have Forestry and Binnie's mods in the same project folder and my IDE (VS Code) lets me search through the whole thing, so I didn't notice that. I'd still suggest that approach, but since it's an internal Forestry class, my suggestion would get a little more complicated: register a set of IInventoryWrappers in the alveary controller just like it currently registers a set of IBeeListeners and IAlvearyComponent.Climatisers and so on, and then do something appropriate when getInventory() is called. (I know what would be appropriate to do then, but I have to go in a few minutes and I won't have time to write more about it today).
There's one problem with your suggestion of doing something in the onQueenDeath()
function: what if the inventory is full at the moment the queen dies? Then addProduct
returns false, and the offspring is stored in the spawn
variable, and will be placed in the inventory later, whenever an inventory slot gets freed up. That's why I decided not to go with onQueenDeath()
in my suggestion at first, because there's a chance that it could fail to replace the princess.
HOWEVER, now that I realize that AlvearyController is an internal Forestry class, it looks like onQueenDeath()
is the best way to handle this that doesn't involve rewriting Forestry. But BE CAREFUL: first, when you're swapping out inventory items on queen death, make sure that if there's a stack of drones, you leave it alone. Any stack of drones was placed there by the player, and you don't want to change the player's stack of 32 drones into 32 larvae. Only change a drone into a larva if it's the only thing in its stack. And check the dying queen (the queen hasn't been set to null
yet when onQueenDeath()
is called, and check how many generations she had -- and ONLY change the princess(es) with one more generation than the dying queen had. (And maybe you could look at the genetics as well, but that could fail if the princess mutates, because the mutated princess might not share any genes of the dying queen).
The reason I'm saying "be careful and check the generations" (and maybe the genes as well) is to avoid this situation:
- The player decides to be clever, and puts four princesses into an alveary's output slots.
- Queen (with fertility 1) dies, producing one princess and one drone.
- Your code wasn't careful, and goes through and turns all the princesses in the inventory (five of them in total) into royal larvae.
- The player just got five princesses, and only spent one royal jelly on it.
Besides the "oops, unbalanced" nature of that bug, there's also the fact that a princess (that already existed) suddenly turning into a royal larva looks like you have a magic time machine in that royal hatchery block! :-)
Anyway, the only drawback to the onQueenDeath
method that you suggested is that it would SOMETIMES not change the princess into a royal larva, because the alveary's inventory was full at the moment of the queen's death. But that's okay, because if the royal hatchery sometimes fails, you can just pretend that when the alveary is really full, it messes up the bees' normal lifecycle and the new princess matures super-rapidly (because it senses that the alveary needs a new queen RIGHT NOW), and you didn't manage to catch it in time for its larval stage. Oh well, try again next generation.
So all in all, the onQueenDeath
approach should be doable after all.
Oh, and one more thing. When you're going through the inventory looking for princesses, you can't assume they'll be in the last slot of the inventory. It might be that at some point, all the slots were full of honeycomb, pollen, royal jelly, and/or other bee products, but the player took out the products in slots 1-4 (but slots 5-7 are still full). Then let's say three drones go into slots 1, 2 and 3, and one princess goes into slot 4. You still have to search through every slot of the inventory to make sure that that slot contains a princess. So you'll want to use getSizeInventory()
from the InventoryAdapter
class, and then loop through the inventory calling getStackInSlot
and checking if that stack is a princess. (Or, once #203 is implemented, if that stack is a single drone). Then you'd create the replacement larva, and call setInventorySlotContents
on the appropriate slot to put it in there.
BTW, if the decision to make no 1.7.10 changes to Forestry is final, then another approach could be to make the current EnumBeeType.LARVAE type do double duty. If the bee has a generation value greater than 0, it's a princess larva; if its generation value is 0, it's a drone larva. That might be an approach that could work...
@mezz @Nedelosk Would you object to this going into 1.10 or 1.11? I understand that 1.7.10 is going to be closed for new features, so I won't be able to use this since I plan to stick with 1.7.10 for another few years. But is there any objection to this in principle, if we put the 1.7.10 issue aside?
@KorDum We are not against new features we are only against new features in 1.7.10 that is a difference.
@KorDum - Don't close this just yet until a decision has been made on the issue itself. Right now the only decision is "Not in 1.7.10", but nobody has yet said "Let's not do this feature at all".
I've been looking through the Forestry source thoroughly, and it looks like the perfect place to make this substitution is going to be the addProduct()
method on IBeeHousingInventory
. The InventoryBeeHousing
class declares addProduct()
as final
, so you can't override it, but there's still a way to do it.
First, write a new abstract class called BeeHousingInventoryWrapper
, which implements the IBeeHousingInventory
interface. Its constructor takes one parameter, wrappedInventory
, which is stored as a private field. It implements all the IBeeHousingInventory
methods by simply calling the same method on its wrappedInventory
. E.g.,
public boolean addProduct(ItemStack product, boolean all) {
return wrappedInventory.addProduct(product, all);
}
Then you create a class that inherits from BeeHousingInventoryWrapper
and call it BeeHousingInventorySubstituteDroneLarvaeOnly
... or something else that's not quite such a ridiculously long name (yikes). Its addProduct
function checks if the thing being added is a drone, and if it's a drone, swaps out a larva of the same genes instead. I.e.,
public boolean addProduct(ItemStack product, boolean all) {
// These are not real Forestry API names; this is just to give you the idea
if (product instanceof IBee && ((IBee)product).getBeeType == EnumBeeType.DRONE) {
IBee larva = ((IBee)product).copyBeeStack();
larva.setBeeType(EnumBeeType.LARVA);
return wrappedInventory.addProduct(larva, all);
} else {
return wrappedInventory.addProduct(product, all);
}
}
There's also a subclass of BeeHousingInventoryWrapper
called BeeHousingInventorySubstituteRoyalLarvaeOnly
. Its addProduct
function looks like:
public boolean addProduct(ItemStack product, boolean all) {
// These are not real Forestry API names; this is just to give you the idea
if (product instanceof IBee && ((IBee)product).getBeeType == EnumBeeType.PRINCESS) {
IBee larva = ((IBee)product).copyBeeStack();
larva.setBeeType(EnumBeeType.ROYAL_LARVA);
return wrappedInventory.addProduct(larva, all);
} else {
return wrappedInventory.addProduct(product, all);
}
}
And then there's another subclass of BeeHousingInventoryWrapper
called BeeHousingInventorySubstituteAllKindsOfLarvae
. Its addProduct
function looks like:
public boolean addProduct(ItemStack product, boolean all) {
// These are not real Forestry API names; this is just to give you the idea
if (product instanceof IBee && ( ((IBee)product).getBeeType == EnumBeeType.DRONE || ((IBee)product).getBeeType == EnumBeeType.PRINCESS)) {
IBee larva = ((IBee)product).copyBeeStack();
EnumBeeType replacementType = ((IBee)product).getBeeType == EnumBeeType.PRINCESS ? EnumBeeType.ROYAL_LARVA : EnumBeeType.LARVA;
larva.setBeeType(replacementType);
return wrappedInventory.addProduct(larva, all);
} else {
return wrappedInventory.addProduct(product, all);
}
}
And finally, you change the AlvearyController
class so that it has two fields referring to its inventory. One of them is inventory
, as before, and the other one is called inventoryWrapper
and is of type IBeeHousingInventory
. In the constructor, it's set to null
. In the onBlockAdded
method, you look at the block that was just added and see if it's a hatchery or a royal hatchery. If it is either one of those, you check whether the alveary now contains just a hatchery, just a royal hatchery, or both kinds. And you set the inventoryWrapper
to be new BeeHousingInventorySubstituteAllKindsOfLarvae(inventory)
, or whichever one of the three classes is most appropriate, given which hatcheries are contained in the multiblock.
FINALLY, you change the getBeeInventory
method of the AlvearyController
. It now looks like:
@Override
public IBeeHousingInventory getBeeInventory() {
if (wrappedInventory == null) {
return inventory;
} else {
return wrappedInventory;
}
}
... Phew! Now you have something that, if I've understood the Forestry code correctly, will Just Workβ’. It will ensure that any princesses or drones that are created will be substituted for larvae, BUT if the player puts drones into the inventory "by hand", they won't be substituted because that doesn't cause the addProduct()
method to be called.
you change the AlvearyController
And how to do it, if this is an internal Forestry class?
In Forestry
private static Collection<ItemStack> spawnOffspring(IBee queen, IBeeHousing beeHousing) {
...
// Princess
boolean secondPrincess = world.rand.nextInt(10000) < PluginApiculture.getSecondPrincessChance() * 100;
int count = secondPrincess ? 2 : 1;
while (count > 0) {
count--;
IBee heiress = queen.spawnPrincess(beeHousing);
if (heiress != null) {
ItemStack princess = BeeManager.beeRoot.getMemberStack(heiress, EnumBeeType.PRINCESS.ordinal());
breedingTracker.registerPrincess(heiress);
offspring.push(princess);
}
}
// Drones
...
while (!offspring.isEmpty()) {
ItemStack spawned = offspring.pop();
if (!beeInventory.addProduct(spawned, true)) {
spawn.add(spawned);
}
}
return spawn;
}
Princess (one or two) always last in beeInventory, right?
Before princess 1-4 drones (you can see the gene), right?
It is possible to operate with this and change inventory in the onQueenDeath.