Code Day #1

This discussion was created from comments split from: Announce Post #3375: Reports Opening.

Comments

  • Copy of Discord conversation, with reordering of interleaved Q and A. Ctrl+F is your friend.

    Index of 22/03/2024 Code Day Topics:

    64-bit architecture
    aetherspace
    Ais bakes
    bikeshedding
    bugs, small
    clients, MUD
    coder, being a
    curio: collections, types
    Darvellan
    gender
    influencing, influencing criticals
    instancing
    Marani
    mob oacts
    Rapture
    village: commodity pricing, feelings, tithing
    Welch, Peter

    Uilani — 22/03/2024 11:01
    Code Question Day has now begun! Questions do not have to be combat focused or report-oriented, feel free to ask about the mechanics of just about anything.

    Some systems are more difficult than others to decipher so some answers might take time to put together, or we might defer to a specific person to get to the bottom of it later. We'll tag you in the replies so you can find your answers easily, which will help especially if the answers are delayed.

    Valinea —
    Whoa, a code question day? I wish I got into this game like a week earlier so I'd have questions XD On that note, how often does something like this (Q and A event) happen?

    Uilani —
    This is our first dedicated Code Question Day! Generally we answer questions as they come up in #general_questions and other [Discord] channels if it's something that requires admin assistance though, so if you come up with a question later, nothing missed.

    Valinea —
    Good to know, thank you :3

    Active: Monday, Thursday, Friday, Saturday EST

    Avatar made through Picrew
  • How MUD Clients Send Commands

    Cheliyi —
    How does the translation/compling of other code languages work with rapture? This feels like a silly question but I know everyone else writes their more complicated reflexes and mudlet code in JavaScript, etc. Is there a special converter that lets the game read the code?

    Uilani —
    :consider: Not exactly sure I understand the question, sorry if I'm misunderstanding. One option is that you're asking about player systems for a client like Mudlet, which are often Lua or other languages. All of that is handled by Mudlet and what the game gets is just commands as if a player normally inputted them. They are just commands that whatever system the player uses has prepared to send to the game. So we don't do anything at all on our end. If you are asking about other languages actually interfacing with Rapture, on our end not player end, there's at least one Perl script if I recall and it's calculating essence offering totals.

    There's some additional things happening between clients and the game, like GMCP, the API, but bottom line is that Rapture just sends and receives info.

    Cheliyi —
    It's okay, I'm not sure if I made sense. I just know that Nexus lets someone run JavaScript scripts on login, and I was wondering how that like... Worked, if the game is coded in a different language.

    Cheliyi —
    If it's just the code executing like player commands, that makes sense, tbh.

    Uilani —
    Ah then my first answer was on that topic. No, that JavaScript does not get sent to the game. Mudlet, Nexus, or another client, do all of that work on its own side and it results in normal commands being sent to the game, similar to what you can enter by hand. So whether it's some sort of system written in a language of choice doing it, or you, it's all the same to the game because the output still has to be game-friendly.


    Gender Coding

    Esei —
    Why is gender coded... Like That

    Uilani —
    You'll need to expand on that 😄 If I were to guess from the general question, the issue is that it was binary forever and being coded that way, it's pervasive and very difficult to change. So much so that, for instance, Aetolia coded NB in such a way as to avoid issues with verb pluralisation altogether (but the lines do look a bit off as a result), and Achaea struggled as well with their own integration.


    Use of Rapture Manual

    Huskii —
    So, IRE does offer a Rapture Manual [link https://www.ironrealms.com/rapture/manual/index/General.html]. I took a quick glance at it; I'm sure most patterns and best practices are not reflected; but is that manual up to date, and is it useful as anything beyond a language reference?

    Uilani —
    Unclear on how up to date it is as not much about core Rapture changes often, and in terms of things like functions, each game often expands and adds their own utilities. It is an okay general guide to how some things work under the hood as a first time introduction though. I cannot say I ever refer to it after a first read, and if anyone is stumped, they will sooner ask on our IRE-wide coder channel than refer back to it. Every game has too much uniqueness and you need to know your game's quirks and systems to get anywhere in my experience. There is also a style guide though: https://lusternia.com/local/styleguide/

    Uilani —
    Additional response from one of our mortal coders:
    Rapture came about in the time of C. Best practices certainly have evolved since, although the structure of the language also has its advantages. Coders have contributed various utilities and support, and these are part of our specific code base rather than what the manual documents as the base Rapture language.

    Active: Monday, Thursday, Friday, Saturday EST

    Avatar made through Picrew
  • Influencing Interactions

    Irrillian —
    How much influence does the influencing system actually have on the other systems it interacts with? For example, does begging pull from the same gold pool from the mob that bashing does? How big of a change is empowering/weakening/etc really?

    Uilani —
    Begging and bashing pulls from the same gold pool. Empowering and weakening has an impact but I'd say it's small (from eyeballing it). Mob levels go from 1 to 255. Empowering and weakening adjust the level by 10-20 levels (random roll). Level is factored in gold drop both for influencing and bashing. So are a few other things, like time since last gold drop for the mob, blessings, additional modifiers that are even for both charity/bashing.

    There's some fun math happening there. It's mob experience worth rather than level that is being used for the calculation. With experience being a function of level, speed of attack, additional multiplier that compensates for higher level mobs shielding more often, additional mob modifier for having extra health (which we can set by hand). That this value is used in treasure calculation and divided by (random(100)+100). Then the gold is passed through at least two extra functions.

    So in short, weakening/empowering will impact gold generation, but due to all the filters and the randomness included in all the functions involved, you are unlikely to see it clearly and it is unlikely to be worth the time. When bashing/influencing for gold specifically.

    Begging and Gold Drop Calculations

    Uilani —
    Some bits and pieces for those code-inclined, it's a rather convoluted maze I'm afraid or I'd post all of it.
    modification from influencing weaken or empower

    charity_success
    charity success

    mob death
    mob death drop treasure

    Mob treasure calculations.
    mob treasure calculations

    adjust_npc_influence_gold and adjust_npc_death_drop_gold do the same thing ultimately

    Influencing Criticals

    Huskii —
    How do influencing criticals work? Is there a base rate? Is mostly dependent on wonderitems? Is there a influence_crit(ply) function that could be added to something like bodyscan?

    Uilani —
    All of this happens in

    do_influence_attack
    function. It first eyeballs all sorts of additional factors to determine damage done, like prestige, meld, feature curios, any other buffs or artifacts. Then finally gets to crits. If there was no crit from a wonderbrazier, Zarakido AttitudeFlux effects are considered for users.
    soulspark bonuses

    It could in theory be added to bodyscan, but there is nothing else that technically qualifies as influence crit chance. It's just SoulSpark. All other calculations are just ego damage strength calculations.

    Huskii —
    Ahh so Soulspark is a 5% crit rate, a 0.25% crit rate for double crit, then a 0.0125% for the quad crit.

    Uilani —
    Pretty much all there is to it, yep.

    Mob Oacts (Attacks)

    Huskii —
    What is an Avatar? Is that just shorthand for non-crit smobs?

    Uilani —
    Non_crit is a separate flag that we can apply. Avatars do very strong, room-wide attacks and scale damage to amount of players in the room.
    So ethereal avatars, cosmic plane mobs, etc.

    Huskii —
    Marani would be an Avatar then, whereas trench beasts would just be non-crit... kk

    Uilani —
    Yes, trench mobs are just non crit. Marani is an avatar.

    Trench mobs are made difficult by non crit and strength and weighing of oacts (attacks) that they do. For instance.

    oact set of weights for namiraa trench jellyfish
    Where:

    namiraa:jellyfish_tentacles1 - dmg_poison damage x2 botulinum
    namiraa:jellyfish_tentacles2 - dmg_poison damage dmg_psychic damage inyoka 
    namiraa:jellyfish_tentacles3 - dmg_poison damage mantakaya crotamine entangle
    namiraa:jellyfish_tentacles4 - dmg_psychic damage dmg_poison damage dulak
    namiraa:jellyfish_tentacles5 - dmg_poison damage x2 luminosity
    

    Huskii —
    so weight is the number of 'damage ticks' that they do, can be split between types... That seems weird to me, but I think I follow

    Uilani —
    Weight is how often that attack will be picked to do instead of a different attack.
    So 3 is meant to happen the least, and that's the one with entangle.
    So we didn't want it entangling people nonstop.
    And the others all have equal chance of happening.

    Clean Code

    Cheliyi —
    the code looks so clean...

    Uilani —
    In places...

    Huskii —
    I think @Cheliyi is asking to see verbs.r?

    Uilani —
    Behold the lack of indentation, no db aliases being used, and general ughness of the following:
    sample of messy code in verbsr

    Valinea —
    love code ughness
    at least it's not yanderedev levels

    Uilani —
    We definitely refactor while touching old stuff, helps everyone.


    Active: Monday, Thursday, Friday, Saturday EST

    Avatar made through Picrew
  • Curio Summary [Collection]

    Ferelith —
    I'd love to know about the Curio system - I'm not sure what to ask so this question may help me order my thoughts: Why do some lack a set/collection?

    Uilani —
    So there's two designations on our end. Collection and Type. I think type might be what you mean by Set. Example:



    This would be the Curry collection of type/set Magic Bottle.

    Ferelith —
    What about for those without:

    *****************************[ Completed Curios ]******************************
    Id        Type     Set                  Collection   Location                  
    -------------------------------------------------------------------------------
    97059     Complete Red Heart            None         being held by Ferelith
    

    Ferelith —
    Set = type (while type for us is Status)
    Collection - none makes Curio Summary an awful mess.

    Uilani —
    Right, so collection lets us define power for the whole set. Some things do not have collections if they are not intended to have collection powers and are more of a collectible kind of thing. For example, Zemeran Toys are just that. They have a Set/Type so you know what kind they are, but no Collection because gathering 4 toys does nothing.
    Most Collections are within the same Set. Pretty much all of them with exception of 4 Sets which need to be combined together to form a Collection (power). Those are Magic Item, Damage Resist, Damage Enhance, Travel.

    Uilani —
    Bone Collection:
    curios of bone collection

    The Curry one:
    curios of curry collection

    And then there's Zemeran Toys which just has none:
    curios of Zemeran Toys

    Ferelith —
    The 'old' curios or 'general' ones.
    Is it possible to give them a collection with a power of nothing, for organization?

    Uilani —
    It's been a while since I personally dealt with curio views player side, could you explain why seeing the Set is not enough for organisation purposes? Since Zemeran Toys do have a Set and... oh wait I think I see.
    Let me spawn some more curios for myself, hold on.

    Ferelith —
    I'll post an example:

    * = part of a partial
    ******************************** CURIO SUMMARY *********************************
    
    [(None)]
            R      1      2      3      4      5      6      7      8      9
        Sequined Squid
            -      1*     -      -      -      -      -      -      1*     -
        Harlequin Mask
            1*     -      -      -      -      -      -      -      1*     -
        Treasure Map
            2*     1*     2*     2*     -      -      2*     2*     2*     2*
        Ice Bubble
            -      -      -      -      -      1      -      -      -      -
        Sand Bubble
            -      1      -      -      -      -      -      -      -      -
        Conflict Bubble
            1*     -      -      -      1*     1*     -      -      -      -
        Purple Bubble
            -      -      -      -      1*     -      -      -      1*     -
        Black Bubble
            1      -      -      -      -      -      -      -      -      -
        Sable Bubble
            1*     1*     1*     -      -      1*     -      -      1*     1*
        Scarlet Bubble
            -      -      -      -      -      -      1*     1*     -      -
        Poteen Pot
            1      -      -      -      -      -      -      -      -      -
        Mouldy Cheese
            -      1*     1*     1*     1*     -      1*     1*     1*     1*
    
    this goes on for a while until collections break it up:
    [Feather]
            R      1      2      3      4      5      6      7      8      9
        Bronze Feather
            1      -      -      -      -      -      -      -      -      -
    
    [Figure]
            R      1      2      3      4      5      6      7      8      9
        Wooden Soldier
            -      -      -      -      -      1      -      -      -      -
    

    Ferelith —
    curio summary [collection] is the command, pardon.
    Having the Masks be in a collection called 'Zemeran Masks' would help a lot for general glancing/listing. Even if the power is nothing
    without collections, it's like all those 'None' curios are a major hassle.

    Uilani —
    I see what you mean.
    Unless you know what's what, there's no making heads or tails of this mess.

    Ferelith —

    curio summary none
    * = part of a partial
    ******************************** CURIO SUMMARY *********************************
    
    ********************************************************************************
    
    curio summary fireworks
    * = part of a partial
    ******************************** CURIO SUMMARY *********************************
    
    [Fireworks]
            R      1      2      3      4      5      6      7      8      9
        Baton of Wands
            -      -      -      -      -      1      -      -      -      -
        Baton of Pentacles
            -      -      -      -      -      -      -      1      -      1
        Baton of Chalices
            -      -      -      -      -      -      -      1      -      -      
    
    ********************************************************************************
    

    Uilani —
    Okay, so one of the issues is that it would be nice if summary had an option to exclude none, so you can see your actual collections better. And another is that if 'none' could organise according to their type/set, that would also be helpful.

    Ferelith —
    If possible, I'd just give all of the old curio 'Collections' a name and a power that's silly - maybe shoot firework of the name of the collection 1/day

    That would be great, yes. Sorting by 'Group' for the most part is what I'd like. I have a deep desire to collect them all. An *obsessive * desire.

    Uilani —
    Collections only take 4 curios into it at a time due to how powers are set up. I can't force more inside without reworking that db (probably doable though). We can't assign all curios of Winter Curio type/set to a Collection because of that.

    Ferelith —
    AH
    I see.

    Huskii —
    can we update curio summary to show the Curio Type next to collection? Also update the verb to allow us to filter by Curio Type?
    (wait, no... Bad grouping... 😦 )

    Uilani —
    What we could probably do is have the Collection printout show Type/Set in lieu of Collection if it would otherwise be None though.
    And just add an asterisk to indicate it's not a real 'collection' in the sense of powers or something.
    Same for the summary printout.
    And still add the option to see just the real collections, to exlude the nones anyway. That sounds useful either way.

    Ferelith —
    That would be excellent. I know someone filed a large report on curios recently.

    Uilani —
    Yes, there's a big report in on curios. For those interested in said report, it's such a big topic that we wouldn't really be doing just one sol probably. We'd mix and match and just see what all is possible and grab whatever else useful from comments.

    Ferelith —
    This is what I thought was excellent.
    What's the code look like that displays them? :3

    Uilani —
    Does this summarise what we discussed well?
    CURIO SUMMARY option to just show all Collections, ignoring curios with 'None'. CURIO SUMMARY and CURIO LIST tweak to display the Set/Type of the Curio in place of 'None' in the Collection column to be able to tell what type the curio is at a glance.

    Ferelith —
    You continue to be amazing. Thank you.

    Uilani —
    Okay, added it as a comment to the report for future reference. Looking at the code now. All tables are very similar.

    Uilani —
    Spoke too soon, all the list options make it rather convoluted.

    subroutine curio_table(ply,target,type) ...
    [more at ">https://pastebin.com/eV2j6JUf]

    Ferelith —
    It's not too bad.

    Uilani —
    I was hoping for a simple table 😄
    Can easily adjust the collection part.

    Ferelith —
    I love how this was designed around a type = numeral system.

    Uilani —
    Pretty common in newer, more granular stuff like this. Much as we complain about Rapture and the black void that is families.r and such, it's really not that difficult to pierce or edit on the whole.

    Irrillian —
    The seeming use of single equals for both assignment and comparison makes my eye twitch a little

    Ais —
    Agreed.

    Active: Monday, Thursday, Friday, Saturday EST

    Avatar made through Picrew
  • edited May 21

    How Rapture Loads Fast

    Huskii —
    I'm confused. It looks like most .r files are compiled? When "time slows down", is that just rapture updating to our new build? I'm just a little surprised to see no downtime with changes.

    Ais —
    Rapture is a bytecode virtual machine. Effectively, after lexing and parsing, the code is condensed into a bytecode format not too dissimilar in idea (though very dissimilar and far more simple in implementation) to x86 or ARM instructions. Loading of the code is just loading the new bytecode blob into memory and executing the kernel subroutine, and if it doesn't error, it swaps it into place of the old one. Overall, this takes about a second with the size of the codebase + loading prog memory blobs + initialization, which is why it doesn't feel like there's downtime (when really there is, just not in a way that matters to players)

    Valinea —
    woo we love <1s downtime

    Ais —
    Prog is done similarly, except instead of one massive linked bytecode blob, each individual prog is its own blob

    I should also clarify that the time slowing down message is optional. Coders can choose to omit it, which is sometimes why you'll get this random one second lag spike out of nowhere while running around.


    Uses and Implementation of Instancing

    Huskii —
    How expensive is instancing? Can we instance more areas? Is the instancing/cleanup why Grimkeep is so bad once the run ends?
    If we instance the pools quests, for example, do we have to worry about a 2-3 second cleanup once one of the quests is completed?

    Ais —
    Instancing is simultaneously very easy and very difficult. The short answer is the game wasn't built for it and that makes it really difficult. The long answer is we implement room/area instancing as a clone of all rooms and objects. This has a lot of issues such as the fact that this spawns new room ids and object ids, we have to track all of these object ids somewhere, and so on.

    Another big issue is player ergonomics - because the internal id doesn't match up to what's in the map XML file that's used by player clients to generate map data, your client-side maps and path tracking (and our game ones, more on that later) don't map to the original data if given raw, so we have to adjust pretty much every system that outputs information to the player around them. GMCP and ATCP, we have to map and store the original room number and, when != 0, send that to the player instead. For the game generated maps, we do similar where we output the map of the similar room.

    There's also the issue of prog. To write prog in a way that's able to be instanced, you have to write everything relatively. Every part of how admins are trained to write prog involves referencing direct ids for constants rather than doing a map lookup (which is an order of magnitude slower, as map lookups in prog are O(N)) or using relative relationships rather than direct, so it requires twisting your brain to even write. Changing an area to do it would require a full rewrite of every single prog, really.

    The final issue is, as you said, cleanup. What happens to prog states and instances there? How do you handle anything taken outside of the instance? How do you handle all the oddities we've gathered over the last 20 years in how replicas are handled, NPCs are handled, how replica deletion is handled. How do you even store this data. What happens if somebody puts a random item from the instance in a nodecay container. tl;dr: It's not expensive, it's just really hard, time-consuming, and bug-prone.

    Here's a fun bit of mental gymnastics for you. Room ids are reusable if the room is deleted. If a player logs out in an instance, the instance is destroyed, and somebody builds a manse room with the same id, where does that player log in? What happens if the room id isn't reclaimed by that time?
    Answer 1: The player wakes up in the manse, permissions be damned.
    Answer 2: Aetherspace. Along with all the floating aetherspace cabinets and the aspace mobs.

    Huskii —
    I thought the usual solution was to yeet them through the portal :p

    Ending Up in Aetherspace

    Ayisdra —
    Are aetherspace 'rooms' just fancy normal rooms with special flags? Is that how sometimes we get players into aetherspace?

    Ais —
    Usually it is. But in this case, aetherspace. If you try to look or walk, you throw an error

    Aetherspace uses the same system as Achaea's wilderness (I think this is the right thing) under the hood, but without any of the handling they have around it. So it will generate you a temporary room if you somehow end up in it That room, however, is not expected so all the code around it breaks

    Ayisdra —
    I haven't played Achaea, I'm not sure what that exaclty means by wilderness rooms, but I guess that makes sense they aren't actual rooms.

    Darvellan the Navigat... err?

    Uilani —
    Fun fact, we sometimes fly around in an aethership ourselves if we need to check something due to those constrains. Last time Darvellan and I did that, we got owned by dragons.

    Huskii —
    Empath needs to start pulling their weight :p

    Uilani —
    After that I went into aetherspace proper live myself on my test server instead.
    Not going to say which of us was on the grid. :enHANCE:

    Xenthos —
    Well as the starry navigator, Darvellan absolutely should have been the pilot

    Darvellan —
    [a very big] :bee_happy: [emoji]

    Xenthos —
    You are making me doubt your steering abilities, here. xD

    Darvellan —
    How many times have I gotten lost in the Void?

    Xenthos —
    I think Shikari might have you beat on that one. Viravain too!

    Malarious/Malayn —
    I mean, Darvellan is the navigator, right? Doesn't say the captain

    Xenthos —
    On aetherships, aren't they generally the same role?

    Malayn —
    not for a God apparently? <_<

    Ayisdra —
    Darvellan the Lost

    Uilani —
    Okay, I need to fess up. I was piloting and I flew us right into dragons. Now see, if the Navigator had been piloting, we might have been better off. Alas

    Darvellan —
    Narrator: They wouldn't have been.

    Active: Monday, Thursday, Friday, Saturday EST

    Avatar made through Picrew
  • What 64-bit Architecture Changed

    Ayisdra —
    With IRE going 64 bit some time ago, how easy is it to 'upgrade' various things that were built when 32bit was the norm? Would this be as easy as changing whereever it is defined and adjusting the checks?
    Or I guess this is also of a question too of why are some things like mob levels 8 bits when it could much larger (which can allow for harder mobs without resulting to noncrits or higher resists)?

    Ais —
    The 64-bit thing doesn't quite work the way it might sound like under the hood. That change affected a few things and didn't affect a number of others.

    Did affect:

    • 64-bit integers in Rapture maths are now possible (somewhat)
    • More shifting in bitmaths. This also broke clothing for a few minutes.
    • We now no longer have to install a bunch of system libraries in a 32-bit arch, meaning Rapture can be run a lot easier by coders who don't have a lot of Linux experience (and be dockerized without going through hell)
    • We can now make use of more than 4GB of memory

    Did not affect:

    • Storage. Even if we generate a 64-bit integer in Rapture, we only have 32 bits of storage in our largest integral data type. To store a full 64 bit integer, to serialize them we'd need to do something akin to
      persona[foo].valA = temp & ((1 << 32)-1)
      persona[foo].valB = temp >> 32
    • Other things.

    Interwoven Code

    Luce —
    So, we've all had jokes for days about Ephs vanishing into the Family Code to never be seen again, etc. but what exactly is it about that code that makes it so onerous?
    See also, Dreamweaving

    Ais —
    Most of the ephemerals we get up here do not have a coding background, even ones who end up working with Rapture. Beyond that, you're dealing with a 20-30 year old 500-700kLOC codebase that has been written majorly by people who are no longer around. Most of the documentation is "fuck" and, for the longest time, it required a very solid understanding of Linux too because there was no good way to run it on Windows or Mac for testing or code editing/compilation. Learning Linux, Rapture, vim or emacs (take your pick), while also having to learn every other system in Lusternia (prog, building/OLC, how to do admin tasks, how to roleplay, customer service, etc) is daunting.
    Having to do it on the fly with maybe one person, two if you're lucky, who can actually help you, chances are with a full time job and conflicting hours, is worse.

    Uilani —
    What Ais said. Also, it's a huge complicated system. To move any one piece of it, you often need to understand the whole. There's easy tweaks, like length of adoption that was tweaked recently, but there's lots of things that would make the system explode if we tried to make them happen. Ais might be able to say more about Dreamweaving specifically but far as I can tell, it's one of those "trying to melt Rapture" things like aetherspace. Dreamweaving treats interactions with just about everything differently, so it's threaded throughout many (often ancient) systems.

    Dreamweaving

    Ais —
    Dreamweaving is magical. For the actions of dreamweavers to be invisible to non-dreamstate folks and vice versa, and all that separation, the code gets weird. The can_see_* set of checks and scope calls (most lines get sent through these) just skip over anybody not in the same state as you. For literally anything to be visible, we have to manually take people out of dreamstate, send the message/do the needful and then pop them back into it. If you forget one or both of these calls when doing an output, weird things happen.

    Luce —
    Is that what previous folks meant by saying that it treats the dreamweaver as being in two places at once?

    Ais —
    Yeah
    As Uilani pointed out in our private chat just now, we use the dreamweaving trick all over the place with other things. It's an effective way to have replicas (or players) interact with each other without being able to interact with each other. This is used in a lot of progged quests, but another place it's used is catalogues. When you read a catalogue to get somebody else's designs, it just logs in that player (sometimes a second time, we can cheat like that), runs the command as them to check their designs, forwards the output to the reader, and then logs that player out.

    Active: Monday, Thursday, Friday, Saturday EST

    Avatar made through Picrew
  • Fixing Small Bugs

    Ayisdra —
    More of an administrative question, but how much freedom do coders (I guess probably more of the mortal coder type) have in viewing the bug list? How much oversight do they need with the smaller things - There are a ton of small bugs that as a player feel like they are just an messed up check that would only take a couple of seconds to fix. These bugs seem to get lost among the larger things and sit forever unfixed.

    Uilani —
    All coders, admin or mortal, have access to the full bug list. Non coder Ephemerals get trained after they release their first project and from then can also help work on bugs.

    When it comes to code, what Ais said covers this question as well. It's very, very rare that something takes "just a couple of seconds to fix" for the vast majority of coders. Take for instance the earlier question about curios. I've worked with curios a lot, both code and game side, but it's been years since I looked at the player view of them. To tweak anything in that system, even if it's a "small bug", I need to understand how that bit is coded and why. Or the question about gold drops. The number of adjustments that gold goes through is immense and to be sure my fix is not actually undermining the system, I need to understand all the adjustments. Some people will be way faster at it, some slower. If you've worked with that code before, sure you'll find the issue/understand it faster but with so many systems, it's rarer than not that you worked with something before if you're working through a bug list.

    Nobody's editing anything live either (version control!), so it's not just 5 seconds even if it does in fact take 5 seconds. You need to read the bug, understand it, possibly check out provided logs, grab latest code, find the right place and then, if indeed it's something absurdly easy, make a new branch and tweak code. Test it on your server, commit the change, make the PR, tag the right folks to review it, provide info on which bug it is. Then someone needs to review it, accept it, merge it, load it, resolve the bug, changelog it if necessary.
    Most folks will usually do several bugs in a row because of that.

    With game side bugs, which covers anything from prog/quests to crafts, room typos, and other systems, unless it's a typo it's also rarely 5 seconds. Some quests were designed 20 years ago and have no documentation and use some pretty outdated techniques. Knowing how to test and resolve quest bugs is a whole other skillset.

    Ais —
    Adding to Uilani's answer, what feels like a small check might not be. For example, 'line displaying to random person' or 'line displays to everybody on the plane instead of in the room' sound like small bugs, but they have a lot of context to them. The former problem could be as something as simple as mixing up node and persona ids (an easy fix that's hard to spot and might require crawling 30 potential call stacks to even find), or as difficult to find as screwing up an actor scope and somehow hitting a colission because somebody's doing something really dumb (really easy to fix, yes, but it'll probably take you 4 or 5 tries to find it). The latter could be a bad check in a loop, or it could be something like "this skill check is running on a scope of 7 rather than 3 because it does something weirdly aggressive throughout the area and something got caught up in this" which, forget even finding it and remembering what these undocumented scope constants do in the first place, fixing it will involve recoding the skill from the ground up most times

    Uilani —
    Here's another example from quest bugs. Tracing through code is one thing because it's 99% of the time all going to be in there, but tracing through a quest bug in something really old is made difficult by it being all over the place. Searching is already made difficult by inability to search like you do with VSC or whatever is your poison. WebOLC (what we use for prog) will list progs matching the search criteria and from there, good luck, open each and search for that bit yourself.

    But imagine you're looking for something sending a message to one of the replicas and it's just not in any prog. It must be somewhere because the prog is executing the actions related to the message but it's just nowhere to be found. Unless someone taught you about crons, or you figure out to ask around (a coder ideally), you might not find it. Some quests use a mix of prog and code, undocumented to boot. And then there's the cron jobs system in game that sends messages to replicas of choice at certain IG times. For several years now we've been doing all that scheduling prog-side, not game-side, but some old stuff does still use crons.

    Coder Availability

    Ayisdra —
    Ais largely answered it but my original question came from looking at the many artifact/skill bugs out there and it just feels bad when I rediscover a thing is still broken and see it has been a year since I bugged it.

    Ais —
    Yeah. It's not just the bugs being difficult, it's also time. Every active coder right now, mortal or otherwise, has a demanding full-time job. I can't speak for anybody else, but there are days or weeks where I can't even log in let alone code because I've spent the last 6 days, ~12 hours a day, building staff bike sheds for nuclear power plants. It took a concerted effort for me to even be here today to help Uilani answer questions, I've only been doing so between meetings, and I gave up my weekly stress relief ritual of baking to do so. And unfortunately new coders don't fully solve the issue, because each one of them, mortal or otherwise, needs support from somebody who can train them properly and answer questions, review their pull requests, and so on.
    The coders we do have are great. The mortal coders are amazingly productive for what the role ends up being and their own constraints. The situation is what it is though.

    Uilani —
    Just too few cooks in the kitchen as Ais said. We have people working on bugs as they're able to, but we're always juggling multiple plates and there's also always higher priority bugs to deal with too so we start on those first a lot of the time. One way that we try to prevent this is by more thorough reviews on new quests for instance, for game side things. You're unlikely to find a mess like in old quests in anything new, and documentation is solid.

    Ais —
    Because somebody will ask, the bike shed thing was a reference. https://en.wiktionary.org/wiki/bikeshedding

    Active: Monday, Thursday, Friday, Saturday EST

    Avatar made through Picrew
  • edited May 21

    Mortal Coders and Cookies

    Luce —
    It's been brought up before, but how viable would it be to bring on a coder whose sole/initial balliwick is going through old code and documenting it?

    Ais —
    A technical writer, you mean? About the same viability as a coder with considerably far fewer people willing to do it. Realistically, it's less documentation of old functions we need and more a cleanup and reorganization of them. It's not hard to find things or figure out what to do with grep, but it is hard when main.r crashes nvim

    Uilani —
    Applications for Mortal Coder are open
    😄

    Ferelith —
    ooh

    Uilani —
    A mortal coder would like me to let all interested know: Join the team! We have make_replica_from_template(COOKIES)

    Ais —

    Compiling coders.r
    src/coders.r:4098: warning: undecl of i.COOKIES in 1
    src/coders.r:4098: `COOKIES' undeclared
    src/coders.r:4098: (Each undeclared identifier is reported only once
    src/coders.r:4098: for each function it appears in.)
    make: *** [Makefile:58: coders.o] Error 1
    

    Uilani —
    What do we do now? Which file do we yeet them into?

    Huskii —
    Clearly someone updated main.r to unschedule the ais.baking event?

    Otherwise, there should obviously be cookies in coders.r

    Uilani —
    Said coder has now honourably offered to jump headfirst into replicas.r and/or redo the welcome back package to spawn cookies and not roast chickens for coders. But really, if we're handing out cookies it should be cookies for everyone.

    Far as I understand it, the ais_baking subroutine is scheduled by a weekly task so can be restarted.

    Favourite Code

    Esei —
    Ok, we know that there are a few bits of code that nobody wants to touch, like Family, Library, and Stage. What is your most favorite one? By most favorite it could be the best one to work on, the most evil one that you actually hate, the one you understand the most, etc (probably other parts of the code are Like That but I don't know about them)

    Uilani —
    I sadly hate the library code, whilst loving libraries the most in general. Library book data's in mysql, and complicated to boot, and I have not yet transcended to that level of understanding.

    Ais —

    "Every programmer occasionally, when nobody’s home, turns off the lights, pours a glass of scotch, puts on some light German electronica, and opens up a file on their computer. It’s a different file for every programmer. Sometimes they wrote it, sometimes they found it and knew they had to save it. They read over the lines, and weep at their beauty, then the tears turn bitter as they remember the rest of the files and the inevitable collapse of all that is good and true in the world.

    This file is Good Code. It has sensible and consistent names for functions and variables. It’s concise. It doesn’t do anything obviously stupid. It has never had to live in the wild, or answer to a sales team. It does exactly one, mundane, specific thing, and it does it well. It was written by a single person, and never touched by another. It reads like poetry written by someone over thirty.

    Every programmer starts out writing some perfect little snowflake like this. Then they’re told on Friday they need to have six hundred snowflakes written by Tuesday, so they cheat a bit here and there and maybe copy a few snowflakes and try to stick them together or they have to ask a coworker to work on one who melts it and then all the programmers’ snowflakes get dumped together in some inscrutable shape and somebody leans a Picasso on it because nobody wants to see the cat urine soaking into all your broken snowflakes melting in the light of day. Next week, everybody shovels more snow on it to keep the Picasso from falling over."
    Peter Welch, "Programming Sucks", Apr 27, 2014

    Esei —
    do you listen to german electronica while coding...

    Ais —
    With my ears.

    Luce —
    Every coder does.

    Irrillian —
    It's true, you don't get to stay in the club if you don't

    Luce —
    It has a good beat, and you can't understand a [KUPO!] word of it.
    Especially if you speak German

    Ais —
    For an actual, non-joking answer, my favourite bit of code in the codebase is a file called states.r which is, for the most part, invisible to players but makes a lot of really difficult tasks much easier by abstracting things like temporary player flags and timed states considerably easier to deal with. My most hated piece of code is clans.r

    And if it makes you feel any better, my coding music leans toward pop, indie rock, punk, and bluegrass, not electronica. Current song: Moonlight by Kali Uchis. Current code: FoundryVTT module for a friend who hates their current safety tooling and wants something closer to Roll20's.

    Marani "My Power Grows" Veloske

    Luce —
    Is there a cap on how scary Marani can get, or is she basically Estarra-level now?

    Uilani —
    Marani actually has a piece that doesn't work/isn't finished as intended, so there's definitely a cap and I think she's at it now. No promises on that lasting. :ImpJoy:

    Ayisdra —
    Is that piece something that should have been working but never has since it was coded?

    Uilani —
    I haven't read it through that carefully yet. Just generally eyeballed her prog recently to see where she's at now and found notes on how she's meant to be working.

    Active: Monday, Thursday, Friday, Saturday EST

    Avatar made through Picrew
  • Village Feelings and Revolt Influencing

    Luce —
    Oh! Have the numbers for village feelings and crusades ever been talked about? Like, how much impact village feelings actually has during a revolt, how crusade campaigns work, etc.?
    Also, are the influencing attacks stronger/weaker than one another, or just different so that targets get willfull more slowly?

    Ais —
    The other one is a Uilani question. For [influencing attacks], they just spread the resistance more. Begging does the same amount of 'damage' wheedling does.

    Uilani —
    I've spent a few hours not long ago working through that, intermittently going Ohhhh and also:
    facepalm
    So give me a moment.

    Ayisdra —
    Some past math nerd admin making Feelings as complex as possible?

    Uilani —
    One thing I'd like to clear up upfront is the misconception that trying to influence village feelings actively is pointless. It's not, it's just so well-hidden and the brackets so large, that you are unlikely to see it without dedicated work and taking notes. It's so well-hidden in fact that I was sure it's not working at first because the active impact gets translated into adjustments hourly and there's no trace it happened without looking at code.

    Ayisdra — This is what a lot of us felt who tried. That it was designed around a game of 60+ people and everyone doing it. And that in today's ~30 pop game, and likely only 1 or 2 people doing, it takes a full time job's worth of effort/hours to even see the tiniest increase. Is this not the case then when you say 'adjustments hourly'?

    Uilani —
    It hourly translates the work done into score is what I mean. Yes, I am not sure it is balanced the best way right now. There is a certain limitation there, you can only influence the denizens hourly for instance. So that is a hard limit already. All of it is also impacted by other things which I'll get to in a moment. Looking at village feelings impact on revolts first.

    When you successfully influence a denizen in a revolt, this results in a number of points being added to the total for the village. The number of points gets doubled if the room had crusade in it. All of this is still filtered through village feelings and such but for the moment, just on successful influence, you generate an amount of points based on the level of the denizen. For instance, in Estelbar Yojimbo is level 50. So you get 50 points or 100 if you're crusading.
    Now we move to the rest of the calculation.

    During revolts, villages have a different resistance level for every org. It's a 1-7 scale to begin with, with 1 being the best, based on just village feelings towards your org.

    There is information about increased resistance for holding rival villages either in a helpfile or floating about as general wisdom, and I was about to mention that too but apparently that is presently commented out. Unclear when that happened, stopped looking when I got to 5 years back and didn't find it.

    So we get to those calculations now, resistance adds a buff/debuff to the total amount of points gained from each denizen influenced.

    So say you're good with Estelbar, that would get you [50] from Yojimbo.
    So the difference in points can be significant. Your standard 50 could turn into 75 or 25.
    In totally peaced revolts, the score is doubled automatically, to make them as fast as revolts with crusade available.

    To win, it's not just a matter of getting enough points, but you need to be ahead of the closest challenger by some percentage. That calculation, and how the whole final calculation is done is something I can write down some other time. It's giving me a headache at this hour.

    Uilani —
    Does that answer the question sufficiently?

    Luce —
    *furiously scribbling notes.* Yup!

    Thank you guys for doing this, I can't speak for anyone else, but it's definitely helped me understand some of the stuff on y'all's plate if nothing else.

    Uilani —
    We're practicing some very advanced multitasking round here. Good thing human brains are multithreaded. I'm plotting with Darv, pondering a thing with Val, verifying a bugfix from Grimr, edifying Iceman on lore wonders of [REDACTED], making a custom beast, and analysing village feelings all at the same time. 💪 People are unlikely to see any of this unless it directly affects them, but plates are spinning all the time in this kitchen.

    Active: Monday, Thursday, Friday, Saturday EST

    Avatar made through Picrew
  • Village Comm Pricing and Tithing

    Xenthos —
    What is the code behind the pricing in village comm shops? They just never seem to go down ever, even if nobody buys from them.

    For example:

    ledger wood
    ************************[ Wood Commodities by Village ]************************
    Village               Amount   Price (gp) 
    -------------------------------------------------------------------------------
    Stewartsville           2         954
    Estelbar               147        919
    Acknor                  59        919
    Delport                 59        919
    Dairuchi                2         954
    Paavik                  59        919
    Shanthmark              69        910
    Rikenfriez              89        919
    ******************************************************************************* 
    

    Uilani —
    All villages have specific commodities that they produce, and those are the ones that they will increase the count of naturally. This happens hourly and has some slight randomness built in. All villages also have a built in 'target' that they produce towards which represents their production capacity. For example, Estelbar's target for wood is 500, but Acknor's is 200.

    All villages also have a base price for each commodity. This is presently the same across all villages. If their stock is exceeding the target, the price will go down dramatically compared to base price, if they are far from the target, the price will be above the base price.

    So in the example seen above, nobody is even close to their target.
    My view:

    Xenthos —
    But they never get close to their "target" because they tithe things, right?

    Uilani —
    That will require another journey into the wild.
    I have some notes from Orael's investigations but the facts there are either at odds with each other, or there is some interplay between two systems.
    So, hold on.

    Xenthos —
    I don't think I've seen a village at its target level since the comm shops opened. Or, at least, at a level where prices were much less than as displayed above.

    Uilani —
    Long story short: ish. Tithing is composed of 3 steps. A pool gathered every hour when production happens, some percentage is set aside from that production. Hourly production is based on base, government adjustment, additional global variable, and Lyraa multiplier for mining villages. Second pool is anything over 1000 comms (which might have been produced but not listed). And third pool is percentage of current stock, which are also adjusted for a variety of things including comm quests. And that finally gets tithed. So yes, tithing is slightly to blame for targets being harder to hit, but not entirely. Production is probably too slow altogether.

    Xiran —
    Serenwilde recently mulched and I did notice there's a threshold/target that differs between villages, but we brought it down to 1 gold in each village (before buying it out). Villages that don't naturally produce may have lower threshold.

    Uilani —
    That's likely true.
    We have a variety of tools to make adjustments and run tests, also lots of this is logged. So some data crunching is necessary to even it out.

    Ayisdra —
    But also villages were given very high prices to stop people from buying out their stock and just selling to the Peak shop (when that was first released). Wasn't the plan to lower the village prices once things settled down?

    Uilani —
    Unsure, I'd have to ask Orael what his plan was. I think we can make adjustments and see how it goes.

    Xenthos —
    Even when mulching I can only get it down to 1 gold each in a village that produces wood when it's at 1000.
    It's 10gp per at 990.
    And a village will never get to 900 naturally, as near as I can tell. It just isn't able to do so because it dumps into tithes even when it is low.
    That's why I asked really, it takes an absolutely enormous amount of player effort to impact the prices and that impact is temporary because it vanishes at the next tithing.
    So I don't quite understand how it all works out together.

    Uilani —
    Tithing is only a percentage, remember, not all of it gets swiped. And a considerable amount of tithing happens during production already. I'd need to pull some tithing logs and run some tests on my server though. Like I said before, it's possible the tweaks that were done slowed down production too much or there is something else at play there.

    Uilani —
    [...]I forced some production and tithing with debugs on my server, along with running some other tests.

    Uilani —
    Production slows down the closer to target it gets. So if Estelbar was at 0 wood with target of 500, and at 0 cloth with target of 200, then it would produce 15 wood and 6 cloth for a few hours before it changed to 14 wood and still 6 cloth after a few hours. So on and so forth, total being 211 wood and 84 cloth over the course of the day. Of that, 119 wood and 48 cloth would be tithed, but only 100 wood and 40 cloth would be removed from Estelbar as the rest is part of production tithes.

    Shop pre-tithing Day 1: (not including prices as it's lost in the scroll)
    Wood                        211
    Cloth                        84
    
    Shop post tithing Day 1:
    Wood                        111          919 gp
    Cloth                        44         1120 gp
    
    Another full day of production:
    Wood                        230          901 gp
    Cloth                        92         1098 gp
    
    Shop post tithing Day 2:
    Wood                        121          919 gp
    Cloth                        48         1120 gp
    

    So suppose nobody touched the shop at all, it would probably eventually, after a long and ardurous journey with many passport stamps, get to the target.

    Uilani —
    This is just straight production, not affected by comm quests and such.

    Xenthos —
    Hmm. Is anyone actually buying from the shops in live (aside from mulching)? Paying 900 for wood there is a lot more than from the commshop or other places.
    Also: What's the price like when it reaches the target?

    Uilani —
    high
    Base for wood is 928.

    Xenthos —
    Like Estelbar is currently at 229/500, but I don't know that I've ever seen it get to 500 naturally
    oof
    Ok well that right there is probably what's skewing it the most lol.
    Maybe I could have just asked what the base price was! xD

    Uilani —
    The prices in what's above don't reflect the base price, that is, are lower than base, because base is lower on my test server for whatever reason.
    I need to check if something else is affecting it outside of what we set by hand because I have new data on my server.

    So it should be the same.
    So, price is an issue, sure. But also production towards target seems slow. But if we increase production, also need to look at tithing, so it doesn't go overboard. 🤹‍♀️

    Xenthos —
    Well, increased production and reduced tithing would make it build faster towards the target... Then could do normal tithing when it hits the target? Hrm. It does feel like resources get shifted out of the village too fast.

    Uilani —
    Also government styles, comm quests, other quests (orcs do have an impact!), etc.

    Xenthos —
    Thanks for looking at it!

    Uilani — Anytime.

    Active: Monday, Thursday, Friday, Saturday EST

    Avatar made through Picrew
  • Re-ordering bump.
    Active: Monday, Thursday, Friday, Saturday EST

    Avatar made through Picrew
  • Images here, since I cannot edit above:

    Begging and Gold Drop Calculations

    Uilani —
    Some bits and pieces for those code-inclined, it's a rather convoluted maze I'm afraid or I'd post all of it. modification from influencing weaken or empower

    charity_success

    mob death

    Mob treasure calculations.

    Influencing Criticals

    Uilani —
    All of this happens in do_influence_attackfunction. It first eyeballs all sorts of additional factors to determine damage done, like prestige, meld, feature curios, any other buffs or artifacts. Then finally gets to crits. If there was no crit from a wonderbrazier, Zarakido AttitudeFlux effects are considered for users.
    oact set of weights for namiraa trench jellyfish

    Mob Oacts (Attacks)

    Uilani —
    Trench mobs are made difficult by non crit and strength and weighing of oacts (attacks) that they do. For instance.


    sample code from verbs
    Where:

    namiraa:jellyfish_tentacles1 - dmg_poison damage x2 botulinum
    namiraa:jellyfish_tentacles2 - dmg_poison damage dmg_psychic damage inyoka 
    namiraa:jellyfish_tentacles3 - dmg_poison damage mantakaya crotamine entangle
    namiraa:jellyfish_tentacles4 - dmg_psychic damage dmg_poison damage dulak
    namiraa:jellyfish_tentacles5 - dmg_poison damage x2 luminosity
    

    Clean Code

    Huskii —
    I think @Cheliyi is asking to see verbs.r?

    Uilani —
    Behold the lack of indentation, no db aliases being used, and general ughness of the following:

    Active: Monday, Thursday, Friday, Saturday EST

    Avatar made through Picrew
  • Curio Summary [Collection]

    Uilani —
    So there's two designations on our end. Collection and Type. I think type might be what you mean by Set. Example: This would be the Curry collection of type/set Magic Bottle.

    Uilani —
    Bone Collection:
    curios of bone collection

    The Curry one:
    curios of curry collection

    And then there's Zemeran Toys which just has none:
    curio pieces of Zemeran Toy

    Village Feelings and Revolt Influencing

    Uilani —
    So we get to those calculations now, resistance adds a buff/debuff to the total amount of points gained from each denizen influenced.

    So say you're good with Estelbar, that would get you [50] from Yojimbo.
    So the difference in points can be significant. Your standard 50 could turn into 75 or 25

    Active: Monday, Thursday, Friday, Saturday EST

    Avatar made through Picrew
Sign In or Register to comment.