A 2-in-1 Post

Started by Flash1225, September 05, 2016, 05:59:09 PM

Previous topic - Next topic

Flash1225

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.
Considering how many turns my life has taken (good and bad), I'm still fairly neutral to it all. I take the hits, I don't react overly.

Nicant

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 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
Hopefully this answers your question!
CW4 hype!!

GoodMorning

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)

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.
A narrative is a lightly-marked path to another reality.

Flash1225

...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!
Considering how many turns my life has taken (good and bad), I'm still fairly neutral to it all. I take the hits, I don't react overly.

GoodMorning

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.
A narrative is a lightly-marked path to another reality.

Flash1225

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...
Considering how many turns my life has taken (good and bad), I'm still fairly neutral to it all. I take the hits, I don't react overly.

GoodMorning

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.
A narrative is a lightly-marked path to another reality.

Flash1225

-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.
Considering how many turns my life has taken (good and bad), I'm still fairly neutral to it all. I take the hits, I don't react overly.

GoodMorning

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.
A narrative is a lightly-marked path to another reality.

Flash1225

#9
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)
Considering how many turns my life has taken (good and bad), I'm still fairly neutral to it all. I take the hits, I don't react overly.

GoodMorning

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]
A narrative is a lightly-marked path to another reality.

Flash1225

-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.
Considering how many turns my life has taken (good and bad), I'm still fairly neutral to it all. I take the hits, I don't react overly.

GoodMorning

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).
A narrative is a lightly-marked path to another reality.

Flash1225

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]
Considering how many turns my life has taken (good and bad), I'm still fairly neutral to it all. I take the hits, I don't react overly.

GoodMorning

That is what is meant by "pseudocode". If you wish to learn, you need to start turning it into real code.
A narrative is a lightly-marked path to another reality.