Knuckle Cracker

Creeper World 3 => The Coder's Corner => Topic started by: Flash1225 on September 05, 2016, 05:59:09 PM

Title: A 2-in-1 Post
Post by: Flash1225 on September 05, 2016, 05:59:09 PM
So here's a 2-questions-in-1-comment post. The first question is out of curiosity, and the other may be helpful to other people, not just me.
Question 1: How do you keep your scripts nice and neat?
This will vary a good bit. For instance, I'm considering starting to use a "universal variables" script. That way all the variables can be modified without having to search through a large list of scripts for a particular one. This also allows you to keep track of an "automatic" variable that is necessary for other scripts to work properly.
Question 2: So this one is regarding a not-so-clear element of CRPL; what are the specific "tags" that allow core settings, such as Beam Damages or Counts for Victory, to be changed mid-game? I mean I know they're just the same general typing, but just to be sure.
Title: Re: A 2-in-1 Post
Post by: Nicant on September 05, 2016, 08:03:35 PM
I can't answer question 1 because my scripts are not tidy :P , but i can answer question 2! If you want to change some of those "tags" mid game, then use the SetUnitAttribute command. Here is a link... http://knucklecracker.com/wiki/doku.php?id=crpl:docs:setunitattribute (http://knucklecracker.com/wiki/doku.php?id=crpl:docs:setunitattribute) If you want to know the list of all of the "tags" you can change, then this next link will do just that! Here is another link... http://knucklecracker.com/wiki/doku.php?id=crpl:docs:getunitattribute (http://knucklecracker.com/wiki/doku.php?id=crpl:docs:getunitattribute)
Hopefully this answers your question!
Title: Re: A 2-in-1 Post
Post by: GoodMorning on September 05, 2016, 08:43:09 PM
For the other question, it's not entirely clear what you mean.

Is it:

For general neatness, whitespace and function definitions work well. They also force you to keep the scripts tidy. Longer variable names are also good. For a very neat script, examine CS Map #3873: Mighty Plant. The scripts in there look like an lecturer teaching programming to first-years.

For the points listed, a list and/or a manager Core can help.

In general, the rules are: Do not do twice what you can do once. Do not write twice what you can write once. Do not use the same structure for multiple purposes. (This last is flexible. A rule of thumb is that if you can describe it all in one phrase, it can go together.)

Do not repeat yourself. Do not repeat yourself. Do not...

Do add comments, whitespace, functions, and so forth.

For anything complex, the main block (that executes regularly) should be able to get away without a single <- or ->, replacing with functions. Once the script is complete, replace trivial functions with inline code (or not).

For a complex script example, look at the Sleeper creep template.

For a bad example, look at some of the code I have written.
Title: Re: A 2-in-1 Post
Post by: Flash1225 on September 05, 2016, 09:16:58 PM
...Well, there went about 99% of my brain cell count...
-Manager Core? I'm guessing that's what you're saying would use the "universal variables" script.
-Isn't multiple purposes the basic idea for a CRPL core? I mean sure, you're supposed to use it to create some unique stuff, but still...
-So, no nesting ifs? That's... gonna take some getting used to...
-Those are easy.
-So basically replace variables with functions, i.e. cut-and-paste sections of script.
-Yeah, and risk losing the other 1%...
-Something actually understandable? I'm up for it!
Quote from: GoodMorning on September 05, 2016, 08:43:09 PM
For the other question, it's not entirely clear what you mean.

Is it:

  • Script-global variables (Ex: target list for a custom Sniper)
  • Mission-global variables (Ex: The CE level in some of planetfall's maps)
  • All-in-one-place script settings (Ex: Sleeper activity, some Hydra scripts)
It's 3. I meant that there's one script dedicated to managing all the variables that the core needs, as well as some scripting, if needed to manage a variable that is needed for the other scripts. Sorry if that explanation still doesn't help, but I'm trying!
Title: Re: A 2-in-1 Post
Post by: GoodMorning on September 05, 2016, 10:31:07 PM
Ah, I see.

By a manager, I mean a single Core which has little to no function but as a variable repository and to manage these variables.

By structure, I refer to a flow control structure. Ex: a loop.

Nested ifs are fine, but try to break complex conditions out into functions. This can accelerate the execution and make it easier to read.

It's more an art than a science to make functions well. But when scripting, it's often easier to not use functions when writing in the first place, but harder to understand.

I suggested looking at the Sleeper: It is a block of init and variable definitions (ignore), then a clean algorithm (what you want), then the various functions used are defined below (Ex: @AI, @Sleep).

I attach a bit of (bad) code from a while ago. It is not quite spaghetti logic, but is by no means clear. Have a guess at the potential readability improvements (these may slightly worsen the efficiency, but the time saved developing is more significant). The script itself was a failed idea, which ends up eating (nearly) all local Creeper.


Essentially, it should be less dense than printed text, and be clear on the first read-through (This post appears denser than your code should). If you have to look up a variable or function name to understand it, it can be renamed.

I also attach the flower script mentioned above. It could use more whitespace, but is largely good.

When you are comfortable dropping warp notation, that is also helpful; as mixed "warp/not warp" is difficult, and brackets all over the place is a bad idea also.
Title: Re: A 2-in-1 Post
Post by: Flash1225 on September 06, 2016, 01:54:38 PM
Okay, got ALL of those. Boy, am I gonna need to get used to those concepts, though...
-I seriously don't like the darn flowers. Sure it's cool and they supply AC, but they can easily get flipped and they're just generally irritating with how fast they multiply! Also, images for those?
-Evolver? Sounds... interesting. I saw the "classic human mistake" thing towards the bottom of that script, and I had to look it up. So I read this thing's script as "it eats creeper to stockpile it and then after a while it deposits it all," but I may be wrong. It also has a GENETICS function!? I'm terrified... Honestly, when I see the word evolve in CW discussions I think "sleepers" or "corrupted forges" (homage to planetfall), but GENETICS takes that up a notch...
Title: Re: A 2-in-1 Post
Post by: GoodMorning on September 06, 2016, 08:46:36 PM
I'm not referring to the content or functionality of the Flower.crpl script, only to the structure, variable naming, and whitespace.
Evolver.crp was a failed idea.
Evolver.crpl

Simply put, it was intended to be a Creepivorous lifeform, which would adapt to your strategy by a evolutionary process. For example, killing any that were vulnerable to Snipers would mean that there were almost no "Snipable" genetics in the pool. And so on for Beams, Nullifiers (partially), Creeper eating/dumping, and other stats I don't currently recall (altitude?).

However, there has to be a trade-off for better stats, otherwise everything becomes invincible, lightning-fast, and dumping vast amounts of Creeper.

I chose to do this by increasing Creeper required for upkeep. The problem was that, Creeper being the limiting resource, every scrap available was used up. This meant that after an initial flood (when the population boomed) the Creeper became so thin that a single Pulse Cannon could hold it off, and most of the population died off. The map was then pure cleanup, and merely destroying Creeper was enough to starve the custom units.

It might work if there was a different trade-off, or if I had allowed for indefinite improvement.

The other problem is that for this to work correctly, there should be behavioural change, which involves more variables and thus more lag and complexity; and a "large" population. For a half-dozen variables, you want about 2^(6*2)=4096 units in order to allow a reasonable convergence rate. This is impractical due to lag, unless they worked on a very simple algorithm. Dropping to a much slower method, still with 6 "genes", we can get to 6*2^2=24 units, with high risks of genetics being lost.

Having written this (and automatically considered methods to circumvent the flaws), I might return to the concept, but not for some time. Feel free to attempt it yourself, it is likely to be a good exercise in script structuring.
[close]

THe reason that this hasn't been done is that it is difficult to do well, and even harder to balance.
Title: Re: A 2-in-1 Post
Post by: Flash1225 on September 06, 2016, 09:27:43 PM
-Yeah, I realized that with the flower script, but still.
-So this evolving organism will grow more resistant to weapons that can kill whatever is around that's less common than anything else, and less to the things that're more common than everything else? That's how I read it...
-Maybe you could've had a waste disposal function to get rid of excess creeper once a "waste creeper" limit has been reached, to keep the creeper density at a decent amount? Like say about 20-50% of the creeper that the organism ingests gets "absorbed" and goes into a variable, such as CreeperWaste. Once this variable reaches a point, the organism then disposes that creeper, setting CreeperWaste back to 0 and the excess creeper is then distributed randomly in areas the player isn't nearby.
-Yeah, behavior changes... Sleeper script? Heh, I find it funny that came to mind. It does make sense, though, the sleeper forces you to think in new ways to tackle its new tactics. This thing could possibly become a Sleeper equivalent if that became a thing, and if the script was actually practical.
Title: Re: A 2-in-1 Post
Post by: GoodMorning on September 06, 2016, 10:30:37 PM
Essentially:
If it lives, it goes into the gene pool. Then there is more of it in the next generation.
If it dies, it doesn't, and there is less.

So resistance to whatever weapon the player uses will accumulate over time.

If you stop using something, it will not increase. The trade-off is needed to make sure that it gradually lessens. (That is, there has to be a disadvantage to, say, Sniper immunity, otherwise everyone will get it and retain it even if the player deletes all Snipers. If having it makes you weak to Beams, then those which become immune to Beams instead will start to make up more of the population.)

So a better way might be to cap damage-per-frame or to adjust regeneration. Capped DpF can stop Snipers, high regen can make you all but immune to Beams. A combination will work still differently.
Title: Re: A 2-in-1 Post
Post by: Flash1225 on September 07, 2016, 05:28:51 PM
Man, putting my understanding of this into words is INSANELY difficult. I had a thought that the genes actually harmed the organism, then realized that wasn't the case.
QuoteIf it lives, it goes into the gene pool. Then there is more of it in the next generation.
If it dies, it doesn't, and there is less.
I thought that referred to the RUNNERS and SPORES. I am a baka...
The way the organisms gain these genes is via exposure to your weapons, meaning if you hit them with beams, they will progressively take less damage at the same rate, and eventually take a solid 0% amount of damage. Same for snipers. These genes, however, have a weird dominant-over-recessive relationship, hence the trade-off mechanic. As the organism is exposed more and more to one specific weapon type, the resistance gene to the other weapon type becomes "recessive," so it takes a higher percent of damage from that weapon. If the organism if exposed to the weapon type that the "recessive" gene corresponds to, that gene will become dominant again.
I think that the basic idea with your resistance genes, anyway.
(modified text is bold)
Title: Re: A 2-in-1 Post
Post by: GoodMorning on September 07, 2016, 07:07:07 PM
Version in code:
Nothing to do with your most recent post.

Version I am mentally designing as I read this:
Your idea seems easier to run and balance, and may achieve a similar effect to what I considered above. The root idea was somewhat different, but if the organisms have some shared stat to control the population (no runaway growth) then it should work better.




My idea was for genetics to spread through the population as the units bred, which rapidly becomes problematic.
Your form would neatly avoid many of the problems by having each unit descend from only one parent, and adapt within a lifetime. Perhaps these stats could be shared, either globally or with nearby units, that a "Beam front" and a "Sniper front" might be resisted separately.

So, rather then "genes", we might better refer to "configurations" when discussing your (rather simpler, likely faster, and almost certainly tougher) form.

In this case, we might say that the "organism" can "configure" its armour to either "mirror" or "rubber", or in-between. "Mirror" would be reflective, limiting Beam damage, but be smashed by Snipers. "Rubber" would have Sniper shots "bounce off", but melts under Beams.

Any child units could inherit the configuration, thus providing an effective evolutionary mechanic without the issues associated with implementing breeding.




Now, a hopefully clearer explanation of the form that I gave the code from (spoilered for length):
Code Explanation

The intended lifecycle:

Unit spawns, has stats. Eats Creeper, starves without. If killed, drops stomach contents (possibly with interest, can't recall).

Unit occasionally lays "eggs" (ish) with slightly different stats. These hatch in Creeper.

Unit has a stat that is "chance to be invisible to Beams", similar for Snipers.

If you use Beams, then there will be fewer units surviving (and laying "eggs") which are Beam-targetable. Therefore, any eggs laid are more likely to have a high "Beam-invisibility" chance. Eventually, every unit will be 99% likely to be Beam-proof.

In order to make sure that you don't end up with a crowd of organisms running around that are proof against anything, I had to put in a cost for being better. So, better armour requires it to eat more Creeper for upkeep. This means that, having higher requirements, invincible units would be out-bred by units which didn't need as much Creeper if the other units could survive even nearly as well.

If the stats could improve without any cost, then the units would become progressively better, until they were unkillable.

However, with a trade-off, if there is no advantage to a given stat rising, then it will tend to fall, because there is a cost but no benefit.

The Creeper-appetite was my choice for a trade-off, because it also seemed like a tidy way to limit the population without (patently artificial) global variables. If there was insufficient Creeper to feed all of the units, they would die off until the Creeper could feed all of those which remained. If there was plenty, then the units would breed up until they ate it all.

The "ate it all" killed the balance, though, because the player weapons are designed to be balanced against vast amounts of Creeper.

The other flaw in this form is that without a vast population (about 5^gene count), it takes a number of generations for the genetic balance to adjust. Quite possibly, the probability-based genes, like Sniper-proofing, would not have more than three oherwise-weak units carrying them (and actively feeling the effects) at the time when the player attacks. This means that everything is vulnerable to something when the assault begins, and you can prevent the evolutionary mechanic from emerging by killing everything indiscriminantly.
[close]




The real idea behind this was to make something that was dynamically self-optimising. And the ability to change the unit itself, rather than descendants, works well with this goal.




Some more thoughts on your formulation:

Having a bacteria-like genetic exchange within the same generation can further accelerate this, and probably would be moderated by another Core.

This might also be easier to "speciate", allowing a number of parallel populations, each carrying their own stat-balance. So there might be a Sniper-proof species and a high-Emit species.




Now, I would like to issue you a challenge (good practice and possibly a fun result):
Challenge

Build a Runner-like unit, which has the capacity to split in two. More size means more health, less speed. Also more sight (only in H/V lines). Skip sight if you wish, moving randomly. Smaller units can regenerate in parallell, because there are twice as many. Larger units gain a resistance to an absolute amount damage each frame. All of these units will gradually grow. Each time you split, change the intended split size slightly on each child.

The variable that will auto-optimise is the size at which it splits.

Note that the population size and stats are not capped. However, there should be an optimum point (not necessarily the same) against any opposing setup. Cap damage limitation at 19 or so if it turns out to make invincible units.

Without a player killing units, this script will auto-generate a varied population, making it resistant to the "apocalypse rush" attack.

If it works, add a Core that picks two units and swaps their "split size" attribute, at random.
[close]
Title: Re: A 2-in-1 Post
Post by: Flash1225 on September 07, 2016, 08:23:18 PM
-Configurations sounds about right. Also like your "mirror" and "rubber" ideas for armors, it sounds like in Pokemon, the Dragon-Dragon match-up to me, oddly enough. (Better comparison in the spoiler.)
Spoiler
A better comparison might be in some Castlevania games that used elements. The elements in question are mainly holy and dark: holy beats dark, yet dark still beats holy.
[close]
-So when you say bacteria-like, do you mean 2 organisms will meet, then exchange parts of their genetic code? I really want to see where that could go.
-Now that challenge might be tricky... Right now, though, I'm working on a Choix "anomaly field," (don't worry, I checked the map name) I'll share my script for that once I release the map. I know I went off-topic, but remember, I'm not exactly good with really complex stuff, but I can possibly make a general command list (not in any particular coding language per-se) for that unit.
Title: Re: A 2-in-1 Post
Post by: GoodMorning on September 07, 2016, 09:23:48 PM
The procedure is approximately, each frame:

Grow.
Adjust damage resistance based on size.
Check/adjust health.
Modify max health and speed based on size.
Look around (two loops, one looking UD, one for LR) and react (this line optional).

Check if you've grown to splitting size. If not, go back to the start and wait for next frame. Otherwise, continue.

Create two units. Add the script.
Set the child splitting size to something like the splitting size here.
Set the child current size to half of yours.
Self-destruct.

The initialization block will be something like:
Set picture, image scaling (optional).
Don't create a PZ, and be targetable by Beams, Snipers, (Thor?).

I haven't played either game which you compare to, and yes, that is what I mean (ish, there will be a moderator so that an external force does the swapping).
Title: Re: A 2-in-1 Post
Post by: Flash1225 on September 07, 2016, 10:00:27 PM
That's a general idea of what I mean by a general command script, it won't necessarily work with conventional script languages, but it easy enough to read that it can be made into a script. When I saw the challenge at first I thought "This can EASILY be done via Rail Rider and Hydra Emitter..." Of course, though, that's cheesing my way out of something, I really can't make something complex.

(Meanwhile, on the topic of Anomaly fields...)
Spoiler
I'm already done with the script, I just need to finish play-testing the map. Sadly, I intentionally implemented a "go big or go home" thing to be able to get the resources, though. I haven't implemented a "safe level" feature (where anomalies don't occur), so it's even worse.
[close]
Title: Re: A 2-in-1 Post
Post by: GoodMorning on September 07, 2016, 11:18:38 PM
That is what is meant by "pseudocode". If you wish to learn, you need to start turning it into real code.
Title: Re: A 2-in-1 Post
Post by: GoodMorning on September 08, 2016, 03:39:52 AM
Here's an example that looks reasonably neat. Guess which parts are not good enough.
Title: Re: A 2-in-1 Post
Post by: Flash1225 on September 08, 2016, 09:13:58 AM
Lemme just say that being an idiot with scripts can be fun! I removed the image part the first time due to it compiling incorrectly. What happens while I test the script? Graphical error! And yes, it was just some flickering with the emitter, creeper, and digitalis (I got a bit of soy-lent flicker as well). Seriously, you know SOMETHING is up when a Unity engine game freaks out unintentionally (I've seen intentional glitches before!). When I do include the image part, the core just pops out of existence. Might be on my end, though, I don't have an up-to-date computer.
Title: Re: A 2-in-1 Post
Post by: Grayzzur on September 08, 2016, 11:08:41 AM
Usually never hurts to make sure you have up-to-date graphics drivers for whatever video card you have.
Title: Re: A 2-in-1 Post
Post by: Flash1225 on September 08, 2016, 11:29:21 AM
So far it's been just that one moment of derpiness for me in-game. I don't even know where in my computer is this video card.
Title: Re: A 2-in-1 Post
Post by: GoodMorning on September 08, 2016, 06:28:02 PM
It should seem to blink out. However, after 30 seconds or so, it should have grown back to normal size, then split.

I hadn't tried compiling the script, so it is almost certainly broken. However, the worst that generally occurs with broken scripts is that the Core becomes invisible. (Although planetfall managed to get the graphical layering to break completely by combining certain scripts and Ore packs.)
Title: Re: A 2-in-1 Post
Post by: Flash1225 on September 08, 2016, 07:26:09 PM
-Using your version of the script as you included it, it won't compile since the image-setting variable's current default isn't a number, so it's already broken because of that.
-I forget if I've waited around 30 seconds, gonna have to go back and fiddle around with the script some more to test that.
-I gotta see that damage! Oh wait, are you referring to planetfall's "cursed map" thread? Still, gotta see that!
Title: Re: A 2-in-1 Post
Post by: GoodMorning on September 13, 2016, 08:51:21 AM
Here (attached) we have the variant of the Splitter without a trade-off. There is exponential population growth, and under the settings I'm using for testing, I need multiple Thors to keep the units under control.

What should the cost be? With this kind of growth rate, merely taking different amounts of damage won't be enough. The cost that was intended to limit the number of smaller units was the fact that Beams would kill them quickly, but if they're out of Beam range, that breaks down. Too much GetCoresWithVar or GetEnemyUnitsInRange produces lag fast, so dying of overcrowding will fail.

Also, merely having Runner-like units to hunt down is not enough. Currently they're more of an annoyance than a threat. What power should they have to make them worthy? Dropping Creeper is a stock response, but could be said to be overdone.

For clearing lag-sized populations quickly, I can recommend the other attached script, which wipes out every CRPL Core on the map without cluttering with PZs.
Title: Re: A 2-in-1 Post
Post by: Flash1225 on September 15, 2016, 08:53:36 AM
Sorry about my rather late reply, I've been out of town for the past 2 or so days.
-This might end up sounding like the Evolver, but make it so that the smaller units will die out on their own after a random amount of time.
-Can't say for sure on that. Maybe it should release several spores on death? Also, you still need to fix the custom image default:

$Image:"CustomSpore"
$Image_Scale_Per_Kilosize:1.5

-That actually sounds nice! Especially for map devs who use a lot of cores. (Now that I think about it, would planetfall's modified runners (emitters, flamthrowers on their backs, etc.) use a lot of cores?)
Title: Re: A 2-in-1 Post
Post by: GoodMorning on September 15, 2016, 09:21:20 AM
Many. However, more than three Cores becomes a debugging nightmare unless two are running pre-tested scripts.
Title: Re: A 2-in-1 Post
Post by: Flash1225 on September 15, 2016, 10:49:32 AM
Anything complex can be a nightmare. Heck, even Planet-fall's corrupted forge must've been insane to do so. Speaking of which, I have an idea regarding that script, and it combines that script with a sorta reversed connect-all-totems-to-win script.
Spoiler
Basically the unit upgrades specific enemy units (normal enemies are static), but it does so in a slightly different way. Rather than gathering upgrade points from corrupted totems, the unit gathers these points from uncharged totems. For each uncharged totem, the point gain interval decreases by a set amount. You can make this 15 frames, or even 1 full second.
[close]
Edit: Now that I think about it, we may need 1 or 2 things for this idea to work well and provide an adequate challenge:
-Either we decrease the amount each uncharged totem decreases the interval by,
-Or we have several pre-charged totems around the map. This one in particular definitely adds to the strategical consideration of when to build your forge.