Thursday, September 27, 2012

Monday, September 24, 2012

The Advanced Hellcore $action Tutorial

This post is a continuation of the Hellcore $action tutorial.  It is broken up into three parts: a complete listing of the default $action properties, a complete breakdown of the extended $action verbs that can be overridden by your custom actions, and special usage of action on non $action objects.

$action properties

These properties can be set on your action objects to control messages and behavior:

  • .duration (FLOAT) - number of seconds the action takes (from _start to _finish or _continue to _finish)
  • .preemptible (INT) - can this action be pre-empted by another action?  [unused]
  • .unstoppable (INT) - can this action be stopped by the player?
  • .doing_msg (STR, default "%ting") - the doing message (eg the action play would become "playing")
  • .doing_to_msg (STR, default "%ting %il") - the message printed when doing an action to something (eg the action play, on space bagpipes, would print "playing the space bagpipes")
  • .oabort_msg (STR) - the message displayed to other players when the player executing the action types STOP.
$action verbs

These verbs can be overridden with your own versions for customized behavior.
  • _forbidden(OBJ source, LIST callbacks) - do any clean up when the action is forbidden by the room or area.
  • is_being_done_by(OBJ who)  - returns 1 if who is executing this action.
  • unstoppable(OBJ who) - by default, returns this.unstoppable.  Can be overridden to allow stopping of an action in certain circumstances.
  • _abort(OBJ who) - by default tells who that the action has been stopped.  If this.oabort_msg is valid, prints it to the room.
  • duration() - by default returns this.duration.  Customize and pass arguments to vary duration based on circumstances.
  • doing_msg(OBJ who, LIST callbacks) - by default prints doing_msg or doing_to_msg based on the length of callbacks.
Special $action usage

* Executing non $action objects as an $action

Aside from using $action objects, you can use any object, providing it has appropriately defined _start and _finish verbs.  An example might be creating a throwing spear item with a THROW verb on it:
player:queue_action(this, {player.target});

The above example would queue the spear itself as an action (first calling _start, which would then return duration as normal) and passing player.target as the first callback argument.

* $actions.verb

A default action called verb is available in hellcore.  Similiar to executing a non action, this allows you to call any verb as an action (instead of requiring _start or _finish).  Example:
player:queue_action($actions.verb, {some_object, "_start_action", {callback1, callback2}, 5.0, 1}, "custom action message");

Where some_object is an object number or variable of type OBJ, "_start_action" is the actual name of the verb you want to call, callbacks are the callback arguments, 5.0 is any float representing the duration, and custom action message is a string to display as the doing_msg.

The Hellcore $action Tutorial

Hellcore provides a 'game loop' in the form of the $heart object.  This object accepts registrations (for example of creatures and players) and every 30 seconds does a 'heartbeat' on every registered object.  When an object beats, the heartbeat verb is called.  NPCs, when doing nothing, can select an action via the verb suggest_next_action.  If the creature or player is already executing an action, the action is checked for duration and moves to the next step or resolves.

When to create an $action:
- a looping or multi step process
- a process where you'd like a delay between starting and finishing
- when you would like players and creatures to share the same code for executing a process

To initiate an action on a creature or player, you call :queue_action, like so:
player:queue_action($actions.some_action, {callback1, callback2, callback3});

Callbacks can be anything that the action is setup to handle.  For instance, here is a mock attack action being queued:
player:queue_action($actions.mock_attack, {player.weapon, player.target});

This would send the player's weapon and target properties to the action.  The player or creature executing the action is always available inside the action.

Actions begin at the _start verb.  Using the mock attack action as an example again, here is what one might look like, with commentary:

$actions.mock_attack:_start
"The player or creature executing the action is always the first argument.";
who = args[1];
"Next we retrieve the callback arguments provided when the action was queued.";
{weapon, target} = args[2];
"Print a message to the room or something, usually.";
who:aat( $su:ps( "%DN attacks %it!", who, target ) );
"At the end of start, after the duration has passed, _finish will be called with the same arguments.";
return {this:duration(), {weapon, target}};

After _start finishes and the duration has passed, the action's _finish verb is called.  We'll use the mock attack as an example again:

$actions.mock_attack:_finish

"The player or creature executing the action is always the first argument.";
who = args[1];
"Next we retrieve the callback arguments provided when the action was queued.";
{weapon, target} = args[2];
"Let's roll some dice and call it a hit on an arbitrary number.";
if(random(100) <= 25)
  who:aat( $su:ps( "%DN lands a hit with %p %t!", who, weapon ) );
  "For this example, we'll assume weapon has two properties indicating the damage type and amount.";
  target:take_damage(weapon.damage_type, weapon.hit_damage);
  "Returning E_NONE from any stage of an action ends the action.";
  return E_NONE;
endif
"If we got this far, we missed.";
who:aat( $su:ps( "%DN misses %it!", who, target ) );
"Now we could just print a miss message and end the action, but for example purposes, let's try hitting again until we succeed.";
"When an action object is returned from _finish, the action is not ended and instead calls _continue.  This allows for repeating or looping actions.";
return {this, {weapon, target}};

You do not have to use a _continue verb.  The attack could simply terminate one way or another in _finish and be resolved.  But for this example, we'll use a _continue verb to loop the action until a hit is made.

$actions.mock_attack:_continue
"The player or creature executing the action is always the first argument.";
who = args[1];
"Next we retrieve the callback arguments provided when the action was queued.";
{weapon, target} = args[2];
"Print a message before passing back to _finish and rolling our attack dice again.";
who:aat( $su:ps( "%DN attempts another attack with %p %t.", who, weapon ) );
"From continue, we return a duration and our callbacks just like in _start.";
return {this:duration(), {weapon, target}};

Now we can use our mock attack action, either through a verb the player can access, or by returning it from an NPC's suggest_next_action verb.  If written correctly, you can use the same $action for players and creatures without modification, and using an $action allows for great control of the timing and interaction of the executing game codes.

For more information, see the HELP $action command as an admin on Hellcore.  I have also written an Advanced $action Tutorial which contains a full breakdown of the $action properties, verbs, and special uses.

Tuesday, September 18, 2012

Changelog 9/18/12

* Starship hulks!
* Respawn terminals for returning to starships, moons, etc
* Supply Expert skill command - REQ (allows the player to requisition items in the field):

* Quality control skill command - INSPECT (allows the player to view blueprints a material or component is used in):

Monday, September 17, 2012

Belated updates 17/09/12

Whilst it may seem that nothing's going on as far as updates go, nothing could be further from the truth-


This is VN-1229. It's horrid and blocky but it's a test bed for a world generation layer which makes the equator hotter and the poles colder, whilst manipulating the biomes near the poles to give some semi-realistic replication of polar terrain. Currently this makes the entire planet look like a bizzare giant cylinder but with a little work and a perlin injection it should look a lot nicer.


What you see here is a bleak, no-frills map of temperature values which for some strange reason has been turned on it's side. The far left and right of the image show polar temperature values, and the center of the image shows equatorial temperature values. Since the majority of the planet is desert the temperature values are affected little by polar fluctuation, making some areas of the image redundant. It still gets the point across though, it works, sort of.

On top of this, moon dungeons now have a hibernation system in which they'll hibernate, then junk any npcs inside them if there's nobody in them.

On the mundane side however many unannounced updates have been made, such as advanced materials from exotic asteroids and gas clouds in distant systems finding use as materials for advanced armor and weapons, as well as various improvisable items, new materials, new weather types, new biome types, etc.

Not far to go, beta gets closer by the day.


Wednesday, September 5, 2012

Alpha Roundup & Last Objectives

Let's go over the alpha roadmap and see what the status is:

Objective: NPC factions must be working (invading, colonizing, and building)
Status: COMPLETE! (Aphteroid)


Objective: NPC AI must be "working" (travelling to destination, all basic actions available, driving/flying enabled)

Status: Almost complete.  NPC flight and space travel still to do.  (Aphteroid again)

Objective: Factories must be working
Status: COMPLETE! (Aptheroid)

Objective: It must be possible to build and launch a solar spacecraft and travel between planets in the same solar system
Status: COMPLETE!  In addition, travel between systems is working and four solar systems are currently active.

Objective: Player & wildlife attacks must be complete
Status: Incomplete.  This and biomes still need multiple man hours of work.

Objective: Skill rolls integrated and related actions complete.
Status: Partial, maybe 75%.

Objective: the biomes must be complete (wildlife, resources, artifacts, scavenger objectives, biohazards, weather)
Status: Partial - maybe 30%.  The more extreme biomes especially are lacking in detail.

Objective: major weather objects must be complete
Status: COMPLETE!  The weather system itself was also drastically improved.

Objective: backgrounds and reroll mechanics must be complete
Status: Incomplete.  This still needs a fair amount of work.  Some reroll improvements were made.

So, not terrible, given the hobbyist level of effort.  In addition to these goals a lot of other stuff was added, including a fair amount of content, improvements to the underlying systems, etc.  At this point there is one more set of goals and then Wayfar can be 'beta' instead of alpha.  Here are those goals:

* Complete the sector defense minigame
* Complete the robot/civilian management terminal
* Complete law enforcement mechanic
* Complete the vital crew terminals for starships: engineering, communications
* NPC pilots and spacefarers
* Complete the background scripting and reroll mechanics (again!)
* Complete the data entry for all 30 odd biomes, including wildlife, artifacts, objectives, biohazards, weather, and underground elements

In addition to these main goals, there are dozens of ideas and bugs that must be addressed, several minigames not mentioned, and loads of content.  But completing the above would satisfy the basic core of the game and let us move into 'beta'.