Jump to content
  • Pokemon Reborn Development Blog

    Hello! My name is Ame and I sometimes get ahead of myself. ^~^
    The others and I may occasionally post updates about how progress on the game is going here!

    andracass

    meow

    By andracass, in Records,

    hi there.
    i've posted nothing but the heaviest fuckin code posts for, like, 10,000 dev blogs now.
    have some cat.

    now i know what you're thinking.
    "is this cat actually that fuckin pretty"
    and yes. she is.



    this is important.
     
    oh also we made a thing for when you choose theme teams.

    that confetti thing is supposed to be an arrow, but ame's really funny so she changed it to confetti. 
    and i know what you're thinking- "hey wait isn't [character] missing?" 
    this is a spoiler free post. terra is definitely just there because it's funny.
    radomus's hat also changes.

    that's important.
    kayo imma get back to my napnap now bye
    also thanks for the support y'all its real nice

    andracass
    hi
    remember me
    i haven't posted in, like, a month- probably the longest period of time that i've gone without posting since the start of this whole optimization fuckfest.

    this post is a little difficult for me to write because i really don't feel like i'm done. over the course of this summer, i've probably spent more time coding than i've spent sleeping ("definitely. not even a contest." ame says to me as i write this) and i still do not remotely feel like i'm done. there is just so much work left and so much more that could be done on all of this that stopping now feels wrong.
    but i also, like, can't anymore.
    ame and i have kind of taken to calling this little bouts of mine, my Apeshit of the Month ™️. it's basically just rips on the fact that when i usually work on the game i just go nonstop for a long period of time before i burn out and do nothing for a little bit before just going off on another Apeshit of the Month. i think i'm now reaching the end of my energy for that.
    originally, this month was just supposed to be a mini-continuation of last month- little bit more optimization in the AI to speed up how long a turn takes to process. it then kinda blew up. some other section of the code would end up catching my attention and i'd end up getting distracted, or i'd see something and it'd annoy me so i'd start working on it- not to mention that 90% of my coding experience has come in the past few months, so i'd occasionally see something i did a few weeks ago and think "wow, this is shit" and then i'd end up redoing it.... and i think i've just reached the point where i've coded my heart out and need to do something else now.
    this post is a mix of a catalog of what i've done for the sake of actually making a record of it and also a deep-ish dive into what the code does and how it does it for those of you who are interested in coding things yourselves.
    (and likely some angy for those who enjoy that too.)
    gonna be a loooooooooong fuckin post.
     
    How many levels in a meech?'
    for my opening act, we have something that i actually forgot about until right before i started writing this post. this fix comes courtesy of our dear mr. perrence, who did this way back in june, which i then immediately forgot about because there's just been so much happening. this came up when i was running a profiler to see what functions were being called during the AI phase of a four-person double battle. four-person doubles are great for these. since you have 3 AI trainers in the fight, as well as multiple targets that each of them need to choose from, it creates a situation where the scripts are basically being stressed-tested to the greatest extent possible during normal gameplay.
    so i ran this profile, and saw that there were 244265 calls to the pbGetExpInternal function. 
    that's a lot of calls!
    so let's take a peek at what's going on here.
    (pictures with a white background are from essentials v17.2, and pictures with a black background are reborn code, for reference.)

    what you are seeing is the calculation for EXP. most of this isn't actually relevant here, since levels under 100 just need to check an exp table. it's also fairly inoccuous- if this function is being called a fuckload of times, the true culprit is the function that is calling it:

    HAHA, i've got you NOW, essentials!!!!! just wait until i tell everyone about how BAD you a- wait, no, actually, this function seems fine. the for loop explains why it's getting called so much too, i mean, look at meech:

    meech so stronk it's gotta run 100 times for her.
    ...but then why is it running 244265 time?
    and that brings me to the TRUE culprit:

    the problem here is not about what the code is doing, but rather, what it is not. and the thing that it is not doing is saving your level.
    this means that your level is manually calculated up based on exp (like it says right there) every time it's needed.
    this can be fixed by making a class variable:

    and just like that: poof. the game has obtained new knowledge. never again will unsuspecting pokmans be level checked more than once.
     
    The Compil - nope, nope, not yet, too scary
     
    uhhhh let me see what else i've got in here...
    *blows dust off the code
     
    Set HW_XYZ
    so all the way back in june again, we noticed that a bulky sprite refresh function would be called every time a sprite's attributes were changed.
    here it is now, the privrefresh function:

    there it is!
    it's 350 lines long, quite big, does a lot of math (you know how much i hate math).
    now, i'm not going to sit here and tell you to remove this function and replace it with sharktale.

    (pictured here: me, working on the code)
    that would be silly.
    but there are certainly times when the function doesn't need to be called, like when you're setting a bunch of variables before the sprite is even displayed on-screen. those calls aren't necessary.
    which brings me to the setHW_XYZ function.

    (pay no mind to the variable names. hopefully no one will throw rocks at me for this.)
    this neat little function only runs privrefresh once for five whole variables wow crazy.
    this is boring. like, this is definitely an optimization, but...god i just hate graphics. i think we ended up just putting it in the initialization functions and left it at that.
     
    let's get to the good stuff.
    grab your hazmat suit, remember the buddy system, and send some prayers to The Exalted Lord Arceus (praise be) and get ready to dive into
    The Compiler
    (ok. i can do this.)
    the compiler is-

    the compiler is just...

    don't forget about move memory. we'll come back to that. also shout out again to the Fairy of Toothpaste for patching up the battle factory. lad's killin it.
    the compiler is just....... terrifying.
    i mean, look at this!

    those aren't even words!

    how does anyone manage to look at this and not immediately have a brain aneurysm?? 

    O_O
     
    the compiler is the one place
    that no one should go
    it is such a terrible place
    or, at least,
    it was
    now? i am beeg cass. i have fought the AI. i have fought the battle system. 
    and now?
    i fite the compiler.
    let's go.
     
    last time, on Dragon Blog Z:

    we had THIS.
    hooooooo i was mad. i was all out here like 😠 thats how mad i was.
    also it turns out this wasn't the real culprit either.
    like, it was a culprit, but arresting this guy would be like giving someone a parking ticket when there's a murderer on the loose.
    the true real final ACTUAL culprit times infinity
    was this.

    this rat bastard. 
    this piece of shit was behind it all.
    lemme tell you about what this function does.
     
    FIRST
    it opens a file.
    wow. i'm so smart.
     
    BUT THEN
    it reads the file.
    incredible. how do i do it
     
    while this is, of course, a perfectly acceptable way to save and load move memory, it wasn't good enough for me.
    there are lots of ways to load and process data. this function here uses a bitstring.
    imagine a very, very, very long line of numbers, stretching off into space.
    that's what moves.dat looks like.
    the actual data that you want from moves.dat is located somewhere in that string. to find it, this function shifts to a certain section of the string (determined based on the move ID), reads the data out piece by piece, and then ends the read.
    this isn't an inherently bad way to process memory. it does work, after all. but it's definitely not efficient. the series of function calls, coupled with the frequency at which this function itself is called, means that string processing becomes a lot of what the battle system does in the background.
    so i changed it.

    feast your eyes.
    now this is how to read memory.
    moves.rxdata is basically identical to moves.dat, but instead of having data in a bitstring, it has it in an array. not only is this a lot faster to process, but it's also really easy to read.
    want the function code? it's in [id][0]. there ya go. ez.
    if, for some reason, you just randomly want the effect of move 482 in some oddball script, you can just grab it with $pkmn_move[482][6]. simple, speedy, clean.
     
    abilities wasn't off the hook, though.


    ok compiler. let's go and have a ch-

    nope nope nope im out byeeeeeee
     
    so the compiler as a whole is a little bit too large to post here; while this is a blog post about coding and script changes, i don't really want to blind you with more blind text than my lawyers recommend.
    but i also think i spent a few hours staring at this trying to understand what it did, and i don't want anyone to have to go through that.
    so i'll take pieces and explain them and we'll go from there.
    let's start with this.

    this is from essentials 17, so it won't be what our code looks like. i just don't want to get hurt this time.
    this section defines how the PBS data gets processed (pokemon.txt in particular for this). it defines: 1.) what section this pertains to, 2.) what byte the data gets written to, and 3.) what type of data gets written.
    take, for example, "Color". whatever is entered in the "Color" field in the PBS will be written to byte 6 and processed as type "e". (it also requires PBColors in order to function.)
    the problem i have with this process is pretty much the same problem that i had with moves.dat- it's a lot of data processing for very little (if any) gain. the difference here is that patching move compilation was easy.
    for moves, you just take this:

    and tell it to stop.

    "why is it moves.rxdata?" you might be wondering. and, well, idk. i'm not sure that the file extension matters a whole lot for this and it seemed like a simple way to differentiate between the two.
    dexdata compilation, on the other hand, is like what if the move compilation was tied into a knot. and written in dothraki. and you had to read it with your chin.
    instead of rewriting it, i managed to get away with just repurposing the current code to throw everything into an array rather than a bit string:
     

    pg-13 warningL there is a swear word here. if you find such language offensive, then how did you make it on a fangame for pokemon reborn
    (as you can see i was getting rather frustrated with the code.)
    this array is all of your pokemon data. you'll notice that there are a handful of nested arrays inside of it- they're placed where they are to match up with the old order that dexdata was stored in. it's super arbitrary.
    the order that data gets stored in is determined by the same parameter that determined what byte data was stored in.

    color would be the first item, type 1 would be the third item, base stats would be the fifth (and is, itself, an array) and so on. it's not really in a very intuitive order, but that's mostly because i'm not really sure an intuitive order exists for this.
    the section that allocates data to specific bytes is a little spread out, so i'm going to skip the explanation there (i didn't really do a whole lot to it and also holy shit this post is massive already)  and jump to implementing this.
    because it's a fuckin pain.
    i'll walk you through it.

    this is an example of a call to dexdata. the calls are all structurally similar: dexdata is opened, the bitstring is offset to the data you want, the data is pulled, and dexdata is closed.
    pbDexDataOffset is what's really running the show here. the number at the end of the function corresponds to the specific data it needs- in this case, the 8 refers to Type1, which you can confirm by checking the original code.
    fgetb and fgetw read a specific number of bytes of data. it reads 1 byte for the type and 2 bytes for height/weight. 
    with the new system, that code becomes this:

    $pkmn_dex is preloaded at game start, so there isn't a check to see if it exists or not. if you somehow manage to get in-game without it preloaded, then, well, i'm impressed! also please don't do that.
    you can see that it works pretty much the same as move initialization did earlier. you put in the pokemon, you put in the index of data you want, and boom. you have it.
    we are moving off some antiquated data structures one step at a time.
     
    now, for me, patching dexdata was about me looking at how this worked and going "hhhhhhhhhhhh i hate this", thus sparking a strong desire to fix
    but this code is also, like, actually bad.
    infinite fusion had to weigh adding more pokemon (its main feature) against the game grinding to a halt whenever dipping into dexdata
    rejuv can't add gen 8 without compiler edits because the compiler effectively limits the total number of abilities to 256. gen 8 has more than that.
    it's kinda bad.
    that's enough on the compiler- i've been writing this post for five hours and we're still not even on the ai.
    spoiler alert
     
    The AI
    so i spent, like, three days on the compiler?
    the rest of the apeshit of the month went in to this fuckin thing.
    there is just... so much to cover here.
    over the course of the last month, we trimmed the ai from 42,000 lines to just a bit under 25,000.
    some of this was just code cleanup
    some of this involved offloading work off into individual functions
    some of this was to fix some bugs.
    the rest..... i don't even remember. it was so long ago.
     
    first let's cover some background stuff.
    Importing Hidden Classes aka "i hope you liked talking about the compiler earlier"
    during compilation, hidden classes are made that hold the IDs of everything that you've compiled. they're hiding off to the side, in that constants.dat (or rxdata. one of them.) since they're off to the side, though, they aren't always accessible to the main script classes, which occasionally means that direct calls to them will fail. i manually imported them by modifying the compiler to yeet them out entirely instead of adding them to the constants file and then copying them into the main scripts myself.
    is this a good way to do it? no. i already know that there's a better way, but i just have really burned out hard on this and don't plan to get to it immediately. but it involves having the scripts import themselves. 's fun.
    PBStuff
    this one was me. i did this.
    i made PBStuff to store large arrays of constants that frequently get called/checked together. this was mostly for the sake of the AI, which tended to have these very long lists of moves that stretched out well beyond the incredibly small rmxp script window, but it also came in handy for making sure that ability-changed moves like role play and entrainment would, like, actually fuckin work correctly. 

    wow! comments! that explain things!
    so this was pretty important for code cleanup for two reasons.
    the first is that it makes the code much more readable if you're just calling an array of things rather than just rattling off a massive list of moves/abilities. 
    the second is that it ended up fixing a lot of issues with role play/etc, which had some abilities missing because those moves are really picky.
    in the end, it allows for stuff to go from this: 

    to this:

    i do not know for sure if it correctly gets called as an array with this syntax.
    which is just so much clearer.
     
    okay. let's get started with the real stuff.
    isConst? and hasWorkingAbility
    this'll get me some hate mail.
    i opened this post by talking about how exp/leveling functions work, and that they were called 60 billion times.
    well, these two functions were the next two worst offenders.

    (this is from one AI phase.)
    so what do these functions do?
     
    isConst?
    this one you've already seen from the Role Play screencap. isConst? takes 3 parameters: an object, the class you want to check, and the value you're checking for. isConst? puts them together like so:

    if you're still with me, this far into my gigantic post, then you might see my issue here.
    isConst? checks to see if a value exists before it gets that value.
    it has a rescue statement if the value does not exist.
    so why not just directly get the value?
    the rescue statement would catch it the same way.
    but then, later on, I realized something.
    why does this function exist?
    you can see in PBStuff that i have arrays of values that are all called like this: [CLASS]::[VALUE], which is functionally identical to what isConst? does.
    and the reason it doesn't work is because it can't directly access the hidden classes.
    fixing this is what originally prompted me to import the hidden classes into the scripts; that's what enables the use of the class/value call. nearly every single instance of isConst?(val,mod,constant) can just be replaced with
    [val] == [mod]::[constant]
    and skip out on several lookups and function calls.
    hasWorkingAbility? faces a similar situation:

    it's effectively a glorified isConst? call. 
    the checks that are made here are necessary, but they are also being run a lot. 
    these calls can be replaced by running a single check at the start of a large function, and then replacing the remainder of the calls with (abilityworks && object.ability == PBAbilities::Ability), which can then be condensed further with some organizing. (i'm also considering just making a class variable, but i only thought of it this morning. work is never done.)
     
    AI Move Memory Utilities
    remember this from earlier? the AI move memory system is part of what helps the AI just kick your ass. 
    it also takes up a lot of space in the AI. i mentioned that there were about 17k lines of code that are gone now. 10k of that was through ai memory functions.
    every AI move memory check has two basic components: it first pulls the memory, and then it pulls certain information from it. there's a lot of things that are done with the memory, but the majority of it falls into four categories.
    the memory puller is here:

    and all of the utility functions are here:

    astute readers will notice that there are five functions here. however, we all know that in ruby, the 5th element in an array is index 4. so thus i'm still correct and not just too exhausted to change that number.
    this, in combination with the PBStuff arrays allows these massive chunks of code to be condensed into single lines.
    before:

    after:

    imagine that happening hundreds of times and you know what's happened to the AI code.
     
    *checks watch
    i'm almost 8 hours into this post.
    last big thing and y'all can go home.
    AI restructure
    so i'm sitting here talking up a big game about the ai. but did you know, that our perfect ai, that even it has flaws? it's true! i was also surprised.
    when making decisions, the AI first decides if it should switch, then it decides if it should use an item, and finally it picks a move.
    every single step, the AI checks the scores of all of its moves.
    why

    pictured above: death.
    to fix this, i cut pbChooseMoves in half and put the actual movescore grabbing bit in front.

    this is a much simpler change than the others, but it slices a large chuck of the AI processing time off.
     
     
    ok. we did it. actual dev content over. y'all can go home.
    imma end this out on a more personal note.
    frequent readers of my posts (thank you! and also: why?) will recall that last time i posted, it consisted of direct screencaps of the dev server where i was Very Angry about code inefficiency.
    frequent readers of the comments (why? and also: no seriously why would you do that) will also recall that a Big Fan of essentials showed up to call bullshit on the work i've done over the past few months (despite not really understanding what i do), before calling me a memer rather than a programmer.
    this hurt me.
    likewise, this post was kind of a chore to write.
    that's never happened before.
    these posts have always been written in a certain style that i hope conveys a feeling that i am speaking to you, rather than simply putting words on a page that you then read and process. it's a stylistic choice on my part that i understand some people appreciate and some people don't.
    writing in an informal, open way, only to have someone- a rival community admin- show up on your devblog to tell you that the work you've put into your game is shit kinda fucks you up. 
    i've spent a lot of time checking over my shoulder for everything i've written. "oh hey, is this code absolutely perfect?" "if i say this, is someone from relic castle going to tell me that i'm stupid and should just upgrade my version of essentials?" (the latter here is why i've been very careful to only include code that is in essentials 17)
    but what is most troubling about this is the fact that i was bashed by someone who claimed to represent essentials for offering optimizations for other devs to use in their own games.
    i was mocked for using essentials 15. but insurgence uses 15. deso uses 15. rejuv uses 16. games that have been built on older versions often can't just upgrade to newer ones because it would require reimplementing everything they've already done. meanwhile, the changes between versions are often opaque, with little information to help developers who are stuck on older versions to get any of the benefits of upgrading.
    to blame someone who is trying to improve an older version of the engine for being stuck on an older version is not only callous, but it also shows that there is a massive disconnect between the people making tools to make games and the people who actually make the games.
    and i should be clear here- i'm not upset with the actual developer of essentials at all. when we talked he seemed pretty open to some of the things that i mentioned we had implemented.
    the problem that i see is two-fold.
    the first part of it is that there is a community that seems to be entitled to essentials to the point where they will bash people who speak out negatively regarding it. i have spent the better part of three months grinding away at the scripts. i spent more time coding than i've spent sleeping. and i want nothing to do with that place. this is a unique circumstance for me because i'm generally really happy to offer my work to people. i like making these posts where i talk about what we've been doing. i like handing out my work to people because it means that everyone can make higher quality stuff without also needing the technical knowledge to tinker with the engine. it's practically a form of elitism- we have the new version, and that makes us better than you with your old one. i suspect this matters less to newer devs, as they can just pick up the latest version and start working with it, but i feel like the fact that this situation has happened at all should still be concerning.
    the second part of it is just that...this is so much work. i have been going non-stop for months and i still don't feel like i'm anywhere close to having the code be in a state where i can consider it to be "done". and this has only included work on parts of the engine; there are still entire sections that i haven't even begun to think about, let alone look at.
    my point is that this is all just too much work for any one person to do, and it doesn't make sense for multiple people to end up doing the same work over and over again. it doesn't make sense for me to fix the bugs in my version that are still present in the current version, meanwhile there's another version that's being developed and i sure dunno if it's being fixed in there or not. and then, even if it is being fixed, there's no telling if anyone else would be able to use it in their games since there's not a lot of guidance on what the actual changes are.
    it also means that, as a result of everyone doing the same things independently of everyone else, that there's a lot of wasted scripting talent being spent on re-doing things that have already been done. for example: how many gen 8 mods are there in development right now? you've seen my scripts. gen 8 is already there. we helped out with rejuv on developing it. i've assisted deso with optimizations, and am helping rejuv implement some of this as well. when marcello heard that infinite fusion was having slowdowns due to the sheer number of pokemon in their game, i sent the compiler changes to see if that would help solve things. even aside from the major fangames, time and time again there have been fans and community members who will show up out of nowhere with their own fixes for things. i've been getting some additional mkxp support from aeodyn, who just messaged me one day saying "hey you know you could be using this better tilemap, right?" and then fuckin waynolt is out here making the entire modding system for reborn/rejuv, and then fuckin toothpastefairy fixed the goddamn battle factory before he was even on the team!
    my point here, is this:
    essentials needs to be open source.
    thanks for coming to my ted talk i'm going to go do anything else now because i have been typing for nine hours and i can't anymore

    smeargletail
    Cass suggested coming out of the shadows and be social with a dev blog post so here I be.
    Please enjoy these animations that were forged from the cursed animation editor (would not recommend using that editor) so with that here are 3 moves that haven't been seen yet

    Power Whip the canon animation of this move did not look good until gen 6 so that was a bit of a struggle to translate that 3d look into 2d but thankfully Ame made amazing vines for this thing so along with that and trying to throw a ton of graphics onto every frame we got this.

    Thousand waves went through a few changes originally I was gonna try to make the wave go directly across to the target but there were 2 issues there. The first is if you used this in doubles there was the issue of trying to make the graphics not go over your partner which required me to set every cell to back and then back to front when it got to the target. The second issue is that it's an AOE move so I had to make it look like it hit both targets in doubles.

    Water shuriken's biggest hurdle was making the shuriken stars but it seemed vital to making it look good so I just grinned and bared through that.
     
    Thanks for your time and hope you liked what you saw

    Toothpastefairy
    Well good news for you! Because today we
    are
    dealing with line breaks. A sort of intermezzo if you will. Line breaks are a pain in the butt cheeks, because there seems to be no rhyme or reason to their existence. You can change the words before the line break and it will disappear. Okay, seems logical enough. You can add words after the line break and it will disappear. Okay, what? And until one of Ame's patreons looked into things, you could do nothing and they would randomly appear and disappear. RMXP are you drunk? When doing our optimization run (ha! still talking about optimization) I noticed something which I would've bet was the cause.
     
    Dear reader, always bet against me, for I was wrong.
     
    And then I found a line break while playing. And another. And yet one more. Time to actually look into things. After putting print statements down like no tomorrow, the following conversation between me and essentials happened:
    Memsplanation.mp4  
    See, the function in question is getFormattedText. And this function is over-engineered like no tomorrow. Want to left-align stuff? seems logical. Want to right or center align, this function got your back. Want to use the weirdest font you can find? No problem for this badboy. Want to add Icons? Make only one line right align? Okay please slow down. Color certain words? Add your own line breaks? A second way to add Icons?
    Want to try splitting the text? No, stop!
    And that one is the problem. getFormattedText decides to rerun itself when a condition is met. What that condition exactly entails, I still don't know. But to spice things up, getFormattedText quickly adds a \n in the middle of the string. Which in ruby is syntax for: start a new line. And when it is rerun, it starts another new line right before the word after which the \n is placed.
    🤔🤔🤔🤔🤔
     
    That part of the function has officially been yeeted. We now are free
    after
    all this time of suffering.
     
     

    andracass
    today's devblog comes straight off of discord, where i was very angry at some things earlier.
    i had noticed while playing a certain pokemon desolation 
    that in four-person double battles (you and a partner vs two opponents)
    the AI phase of the turn would occasionally lag just a bit.
    deso uses the reborn ai (because they're not, y'know, animals), and so earlier today i took a peek at its inner functionality. 
    it is, uh, something.
    firstly, it makes the "movescore" calculations (the ai's entire claim to fame) three times per round instead of, y'know, one.
    this was kind of an oversight on our part. silly, really. with some restructuring, it was patched out and now runs a lot smoother.
    however, upon further investigation, it became clear that fixing this issue did not yield the expected improvements. i identified a culprit: the hasWorkingAbility function.
    this function does two things:
    it checks to see if you have an ability
    and it checks to see if it functions (not moldbroken, etc)
    it's not very good at those things.
    and that frustrated me.
    in a fit of righteous fury at this function that had wronged us all, i prepared to re-code all 1002 calls inside the move scoring system.
    but then.
    things changed.
    what follows is a direct transcript of my angy in its purest form.





    (for reference that 15.8s -> 14s thing is just how long it took to profile- so by the end of this the profiler ran about 20% faster)

    *sighs
    anyway
    what i'm trying to say here
    is fuck essentials.

    andracass
    so apparently it's been a week since last post???? and i didn't even notice. 
    anyway the bois n i have been at this coding shit and it's all like dam gurl so fast like wo
     
    lemme show u a sample of what we got.
     
    Zoom
    so let's start off with an easy one

    this code is parked at the end of the script that updates every single event that has a sprite. each of these lines calls a function that calculates a lot of data about where the event is relative to you, and how zoomed in its sprite should be.
    i'm mostly interested in the zoom lines.
    now, TILEWIDTH and TILEHEIGHT are both defined variables. their purpose is kind of obvious. both of them have set values since the tile size doesn't change when you're in game.
    let me show you those values.

    now, class.
    could someone please tell me what you get when you divide either of the two tilesize variables by 32?
    anyone?
    essentials?
    here's what the code looks like now.

    better.
    this probably doesn't look like that substantive of a change, and, yes, compared to the sheer number of calculations that need to be done per frame, this is kind of a drop in the bucket. to this, i counter:
    - this keeps two functions from being called per event per frame. if you're in, say, charlotte's gym, these functions would get called a grand total of 9,120 times each every second
    - it's literally just one 
    - it doesn't even do anything
    - it's just like "oh hey let's change the zoom from 1 to *shuffles notes um, 1" which is literally not even a thing
     
    which leads me to
     
    Math
    if you read through my entire last post (thx btw!) you'll remember that i was very tilted by the fact that essentials calculated the value of 128*4 a grand total of 8 times per event per frame via the in_range? function (which i'll be coming back to!). so, 72,960 times per second in charlotte's gym.
    this was not necessary. it was never necessary. it filled my heart with despair and my soul with rage.
    well.

    WE GOT A WHOLE LOT MORE WHERE THAT CAME FROM
     
    Weather Updates!

    the snow and sandstorm lines hurt me. why would you have the thing multiply something by two and then divide by four. why not just divide by two? better yet, why not just set them all to the same value in the first place and then drop the value in there? this isn't even nearly as big of an issue as the 128*4 thing but it just bugs me.

    you can't even see the whole time because rmxp's script editor is ass, but i think you can get the idea here: all this does is multiply a bunch of shit together that doesn't need to be multiplied, and it gets called thousands of times every second.
    it doesn't have to be this way.
    i could go on, but like, do you really want to see me complain about math more? no, you don't. suffice it to say that about half the time i see a function is running absurdly often or absurdly long, it tends to be doing a whole bunch of stupid math. it offends my sense of justice.
     
    are you SURE you're in range??
    this one i particularly wanted to include in the event that you also happen to make these games and are particularly interested in some shit that can help speed things up.
    good news!
    this is some easy shit that you can just grab for yourself.
    nearly every single aspect of the code that affects the overworld operates through one central script: the Scene_Map update function. nearly every aspect of your entire gaming experience has some sort of roots in that single function. it pushes all the overworld processing to two separate scripts: Game_Map which deals with the mechanics of the map itself (where events are, what maps are connected to it, etc) and Spriteset_Map, which handles everything you see on your screen. essentials comes with some helpful anti-lag scripts that use the in_range? function and the event trigger to determine if an event actually needs to be updated. it's actually helpful! it saves some time updating events that literally do not matter.
    here's the thing.
    despite the fact that the two major functions handle a lot of the same objects, they don't coordinate with each other at all. that leads to a lot of duplicated calculations.
    but there's a fix for that!
    in game_event:

    in game_map:

    in spriteset_map:

    and boom. ur game already goes at the speed of zoom.
     
    is this a deep bush?
    this is gonna be a short one because i'm getting tired.
    i've mentioned functions that run on a per event per frame basis. what this basically means is that the code runs for every event on the map regardless of what is, every single frame of the game. these functions are the core of why some places simply lag to hell: the game is updating so much shit that your computer- even with the hippest, hoppest, newest CPUs- can't keep up (especially on speedup). the reason that 18.4 was such a huge improvement is because it took a massive chunk of those updates and yeeted them.
    well, i'd now like to give you part 2: bush edition.
    when something is in a bush in pokemon, it looks different. we all know this. when something is in a big bush, it looks big different.
    but in reborn, nothing is in a big bush- except for you.
    so we just 
    yeeted the code that dealt with that!
    and wow is it faster.
    you can even see for yourself!
    (i've updated the patch on the downloads page, too, but not the main downloads. it's not worth that level of effort.)
     
    anyway. trying not to pass out on my keyboard.
    there's still a lot of fixes i haven't mentioned that will be in e19 and just require more testing before i let them out into the wild.
    but that patch has some fancy new in_range functions along with it.
    if it breaks someone's game i will cry.

    andracass
    good morning.
    let's talk optimizations.
    we all know that essentials is, uh, slow. in fact, it's so slow, that 18.4 isn't even the first release to be at least partially based on making it faster.
    what is difficult to overstate is just the sheer extent to which this is not necessary.
    everyone who makes the game knows this.



    that second meme was a big enough deal that it got me to make another release. after everything i've been through. it was just such a big speedup that keeping it to just the devs actively felt bad.
    so let's do storytime.
     
    Event Optimizing
    this is the real basic stuff. in-game events on the map (trainers, doors, anything that results in a change to the map as a result of some kind of interaction) are easily the biggest sources of lag. you can tell what maps have a large number of events simply based on how slowly the map runs. calcenon Gym is my baseline for how laggy the game is simply because of the sheer event density on that map. so a few months ago, when all this optimization shit started, it began by seeing what events were unnecessary and could simply be condensed to a smaller number without resulting in any changes to the overall gameplay. 
    an excellent example of this is spinel.
    every disappearance in spinel takes up some quantity of events. originally this was done with one event per tile that changed as a result of one teleport.
    take the pokemart. here's how it disappears in 18.4:

    the pokemart uses 16 events to disappear.
    here's how it is in e19: 

    three! one for the graphic, and two to trigger the change if you touch them. the entire graphic is just moved into the one event.
    some areas will definitely be faster because of this, but the downside of this sort of optimization is that it's limited to the areas that have been checked over- and we really have a lot of places that would need to be checked. 
    which leads me to
     
    Script Optimizing
    we've known that there's bloat in the scripts for a while, but the script-side of things is so obscenely large that it'd take ages to find anything to fix that has any sort of impact on actual gameplay.
    and then: toothpastefairy.
    toothpastefairy is our newest, freshest dev. i've mentioned him before as the person behind the battle factory- y'know, the thing that we literally did not expect to happen. this was before he joined the team, too. the sheer number of bugs on our to-do list was enough for him to be promoted from honorary dev to actual real life dev™️. since then we've been getting shit done left and right. bugs getting squished. memes gettin made.
    then, one day, he comes in with this.

    i hooked up the profiler for myself, and we just went to town on this shit.
    here's some of what we've got.
     
    Quad-calcing the terrain tag
    the above snippet of code is used to determine whether or not a sprite would reflect off the tile in front of it. in doing so, it grabbed the terrain tag four separate times- which is, itself, a time consuming process. fixing this was as easy as assigning the output to a variable and then using the variable for the comparison.
     
    is this a map?
    the terrain tag checking process itself involves taking the coordinates of a tile on the map and shuffling through every layer until you hit one that correctly has a tag.
    however, it also includes this.

    are you on a map?
    of course you are. you're playing the game.
    this was removed.
     
    128*4
    so we know that 128*4 = 512 because we can do math.

    the in_range? function calculates it again just in case.
    and it does so four times.
    and is one of the most frequently called functions in the entire scripts.
    why.
    this was changed to 512.
     
    is this a control?
    every frame, the game processes whether or not you have a button pressed down. it does so using a process along the lines of this:

    here's the thing. there aren't 256 keys on the keyboard. we barely even have half of that. 
    this was carved into three separate sections that go through the keys that actually exist.
     
    the one line change
    this is the big one.
    *breathes
    okay.

    so let's talk about what this does.
    essentials uses a function to determine whether or not a sprite should have a reflection.
    this conditional is what essentials uses to add sprites to the list of sprites that should be reflected.
    under normal circumstances, this is determined by whether the event itself specifically says it is not to be reflected. essentials will assume that all sprites should be reflected unless they are explicitly told not to.
    the issue here is that we literally have thousands of events. no one is ever going to put /noreflect/ on every single one of them
    so instead, the new code checks one thing and one thing only: whether the player is currently in serra's gym (map 506).
    do you know what's easier than quad-calcing the terrain tag?
    literally never calling that function at all.
    we've been working up a storm over at Not GameFreak HQ™️ with patching things up left and right
    but it is truly difficult to overstate exactly how huge of a change this is.
    every single event in the game used to go through this giant function, and now it doesn't.
    the change was so freakishly huge, it dropped the frame time reported by the profiler by over 60%.
    now granted the profiler isn't exactly the best at calculating the total time spent on individual functions... but look at the sheer size of that drop for such a minor change. it was inspirational- so much so that i put out another update. after everything i've been through. my computer crashed twice. i had to rebuild my mac vm. but we did it. it's here.
    it's worth noting that 18.4 only includes the one line change right now. it's small enough that it doesn't need to be tested in advance. anything else and i'm worried some weird aspect of this engine will just make everything break completely. 
    but you bet your ass this shit'll be in e19.

    andracass

    18.4

    By andracass, in Records,

    look, i know i said i was never going to do this again.
    but.
    we have another version.
    here's the entire changelog:
    added a line to the scripts and that's it.
    that's all we did.
    it is much faster than 18.3.
    and it was already fast.
    and i thought about this for exactly 5 seconds so you know it's gonna be great.
    please enjoy.
    the files are still uploading at the time of writing. i'd wait for them to finish, but the sun is coming up and i want to go to bed*. 
    so we are also featuring a patch! you can find it on the downloads page, right at the top.
    (the full length classic story-style dev blog post about it will be here tomorrow. or today- since, y'know, the sun's up.)
     
    *edit: haha lol i absolutely waited and now the files are up. 
    hello, sun. 
    my old nemesis

    andracass
    hi.
    imma get to the point.
    we have a mac version! it's in beta. online doesn't work. some places might crash the game.
    but it exists.
    and you can get it here!
     
    you might be wondering why i'm releasing the mac version now and not later.
    it's because i don't have a mac and can't really test it.
    catalina users also have literally no other option to play the game and, like, that totally sucks.
    so you'll have this! (until apple drops OpenGL support too.)
     
    please report issues you have here. especially if the game crashes.
    and there should be a windows/linux update out soon as well!

    andracass

    18.3 beta

    By andracass, in Records,

    *checks dev blog calendar
    well i see there hasn't been an update in a while. i should make a post.
    hello, [reborn player name here]!
    has your game ever been slow?
    well, no more, i say!
    introducing, from whatever joke corporation i'm a part of this post,
    18.3
    "Wow, that 3 is really big!"™
    this update contains none of what you've been waiting for (like, say, new content)
    but it does contain stuff like zoom
    and also a way to natively play reborn on a mac.
    really. 
    no wine.
    just mac.
    native.

    pictured above: native
     
    those of you who keep a side eye on the progress bars will have noticed that nothing's really changed. and as far as new content is concerned, that is certainly true. ame's been focusing on starlight, and....well, you don't want me writing dialogue. that is not my thing. pls no thx. that doesn't mean i've been doing nothing all this time- it's just stuff that the progress bars don't really reflect.
    so some backstory.
    y'all might've seen a while back that there is a way to play reborn (and other essentials games) on android.  this is not something i ever had expected to happen. i have been saying for a very long time "no. this is not a thing. you can not do this."
    and then suddenly: "wow! this is a thing! you can do this!"
    and that shit was smooth, too. like, it almost seemed to play the game better than the pc version.
    after that, i was like "wow wtf how many other things have i been wrong about". 
    which brings us to mkxp. and this is going to be a little bit more abbreviated than i'd like because the forums ate my post. thanks forums!
    mkxp is an open-source player of RPG Maker games. it's also really difficult to get to work. i like to think i'm pretty good with computers, but trying to build it from source code required a level of technical knowledge that i did not have.
    but uranium has an mkxp port.
    so i just... borrowed the exe from there.
    and it almost worked! 
    after further struggles, i contacted the dev of the uranium port.
    now, after three weeks (oh my god it's been three weeks) of hair pulling, we have a mac port.
    it's been so long.
     
    so the theme of 18.3 is performance. 18.2 had the AI updates; 18.3 will make the game go faster. i feel like everyone knows how sorely this is needed. if your hardware is even somewhat old, the game runs like ass. you know it. i know it. ame knows it. jan knows it.* everyone hates it.
    the star feature of 18.3 is the inclusion of the all new Game-z.exe. this is reborn's mkxp build. if you saw my previous dev [shit]post, you've seen a short preview of an early version. 
    but it does so much more than that.
    battles? smooth. speed up actually works there now. it's incredible.
    maps? smooth. we got full framerate in spinel while it was raining. the maps aren't perfect but god they're so much better.
    animations?
    oh boy.
    so, the animations in game-z were smooth, but because of some other issues we were having, a few internal changes made them lag hard.
    so i took a peek in the code.
    it turns out that essentials handles animations by loading the entire file and then picking a specific animation from that file.
    the file is 10MB.
    it loaded that for every animation.
    whose idea was that.
    this no longer happens. for both game and game-z. animations are now preloaded when you open up the game. that 1-2 seconds of lag that happens for every animation in battle? it happens once when you start, and never again.
    it's incredible. best coding work i've ever done, and it was only five lines.
    there is one other change: the game now uses one font. it is emerald. the game.exe fonts look downright awful on game-z.exe. instead of trying to find four new ones, we just have one, and it's what everything uses now.
    there are a few things i need to finish up before an open beta: getting the linux port to also work, and seeing if there are any other ways to speed up / shift around load times. i am hoping to finish this up this week and will throw up another devblog post / forum thread when it happens.
    Game.exe is the RMXP executable and is what 18.2 runs with. Game-z is the MKXP executable.
    we're including both game.exe and game-z.exe in 18.3 (and likely e19) in the event that people run into weird errors with game-z. kinda like how people run into weird errors with game.exe anyway! this way, hopefully, at least one of them will work for everyone.
    18.3 will also probably be the last mid-release update, with some minor changes to the release at best. i do not want to maintain two separate versions ever again. let my heart be free.
     
    *jan makes rejuv. if you haven't played it and are wondering what to do while you wait for e19, go try it out

  • E19-Main Scoreboard


    Mapping - #################### | 100%

    Eventing - #################### | 100%

    Story ------ #################### | 100%


    Total ------ #################### | 100%


    E19-Post Scoreboard

     

    Cresselia - ###̳̓###########̳̓###### | 100%

    Regis -----#################### | 100%

    Dogs ------- #################### | 100%

    Spirits ----- #########̖̳̇̌########### | 100%

    Birds ------- #################### | 100%

    Genies ----- ##### ##### ##### ##### | 63%

    Mapping - #################### | 100%

    Eventing - #################### | 90%

    Story ------ #################### | 0%

    Musketeers - ################## | 100%

    Mapping - #################### | 100%

    Eventing#################### | 100%

    Story ------ #################### | 100%

    Regigigas - #################### | 100%

    Mapping - #################### | 100%

    Eventing - #################### | 100%

    Story ------ #################### | 100%

    Celebi ------ #################### | 0%

    Mapping - #################### | 0%

    Eventing - #################### | 0%

    Story ------ #################### | 0%

    Meloetta -- #################### | 0%

    Mapping - #################### | 0%

    Eventing - #################### | 0%

    Story ------ #################### | 0%

    Victini ------ #################### | 5%

    Mapping - #################### | 0%

    Eventing - #################### | 15%

    Story ------ #################### | 0%

    Volcanion - #################### | 0%

    Mapping - #################### | 0%

    Eventing - #################### | 0%

    Story ------ #################### | 0%

    Hoopa ----- #################### | 0%

    Mapping - #################### | 0%

    Eventing - #################### | 0%

    Story ------ #################### | 0%

    Zeraora ---- #################### | 100%

    Mapping - #################### | 100%

    Eventing - #################### | 100%

    Story ------ #################### | 100%

    Magearna - #################### | 0%

    Mapping - #################### | 0%

    Eventing - #################### | 0%

    Story ------ #################### | 0%

    Jirachi ------ #################### | 0%

    Mapping - #################### | 0%

    Eventing - #################### | 0%

    Story ------ #################### | 0%

    Tapus ------ #################### | 0%

    Diancie --- #################### | 0%

    Heatran -- #################### | 0%

    Genesect - #################### | 0%

    Lati@s ----- #################### | 0%

    Manaphy- #################### | 0%

    Darkrai --- #################### | 0%

    Marshadow - ################## | 0%

    Shaymin -- #################### | 0%

    Mew? ------ #################### | 1%

    Mapping - #################### | 5%

    Eventing - #################### | 0%

    Story ------ #################### | 0%

    Dialga/Palkia - #################| 0%

    Groudon/Kyogre - ############## | 0%

    Lugia/Ho-oh - ################# | 0%

    Tau Trio --- #################### | 0%

    Xerneas/Yveltal - ############### | 0%

    Lunala/Solgaleo - ############### | 0%

    Deoxys ----- #################### | 0%

    Giratina --- #################### | 0%

    Rayquaza - #################### | 0%

    Zygarde- ##### ##### ##### ##### | 20%

    Mapping - ##### ##### ##### ##### | 60%

    Eventing - #################### | 0%

    Story ------ #################### | 0%

    Necrozma- #################### | 0%

    Mewtwo- #################### | 1%

    Mapping - #################### | 5%

    Eventing - #################### | 0%

    Story ------ #################### | 0%

    Arceus

    M#̵̤̪̰̺́̑̊̿̽ppping - #̧̠̋̈#̳̓#̮̜̘̤͈̑̽̋̕̚#̵̨̤̪̰̺̳́̑̊̿̽#̵́̑#̞̿̏̾͟͢#̱͡##͉͈̆̐̽͜#̲̤̗̃͛̈́͘͜͜͡#̢̝͍͉̍̐̍͊͘͢#̨̖̳̭͔̇̄͒́͋#̡̫̃̿̕͟#X###̞̿̏̾͟͢## | ?@

    tnevE? - #C###̞̿̏̾͟͢##nO#####͉͈̆̐̽͜#͉͈̆̐̽͜##Y#### | H%

    StoR

     

    Legendary Quest Subtotal:

    ##### ##### ##### ##### ##### |17%


    General ----- #################### | 75%

    Boss Rush -- #################### | 90%

    Theme ------- #################### | 95%

    FITE etc. ----- #################### | 80%

    Fwends ------- #################### | 0%

     

    Nightclub Subtotal:

    ##### ##### ##### ##### ##### | 66%


    Animation - ##### ##### ##### ##### | 63

    Bug Score - ##### ##### ##### ##### | 377

    Misc. -------- #################### | 670%


    EPISODE 19 TOTAL:

    ######################̖̳̇̌#####################̖̳̇̌#########################################################| 52%

    current estimated release date: if anyone has an estimate as to when this game is going to come out, they are lying to you. do not trust them or anything that they say. best case scenario is that they're a time traveler who has come back from the future with information of the release date. they must be removed before causing a paradox that ends reality.


    ame is going to pull me over to starlight so your regularly scheduled script blogs are going to be a little sparse.

    but we still here. still doin.

    (Updated 8/10)

  • 16-4.png
    16-5.png
    16-6.png
    16-7.png
    16-8.png
    16-11.png
    16-12.png

×
×
  • Create New...