Since I've started making my own Script Modules I have found that my current knowledge of scripting commands and functions isn't really satisfactory.
Is it possible for people to explain the following to me?:
Importing/Exporting Functions;
Extender Functions;
Enumeration;
Pointers;
The term "Static"(cant find anything in Help);
Structs.
I shouldn't need it spelled out to me too simply, as I think i should be able to understand most concepts rather quickly.
Again, Any Help Appreciated.
1+2:
Functions don't need to be exported, just imported.
Say you add an extender function to the global script:
function FadeOut(this Object*) {
int i = this.Transparency;
while (i<100) {
i++;
this.Transparency = i;
}
}
You can call this now in the global script:
object[1].FadeOut(); // fade out object 1 in the current room
If you add an import line to the header, you can call the function in room scripts, too.
import function FadeOut(this Object*);
Now, in a room script, you can do:
oChair.FadeOut();
3:
Enums add readability to code. Instead of arbitrary numbers, you can use words as function parameters.
// header
enum Weather {
eRain,
eStorm,
eSunny
};
From the technical side, this adds three constants: eRain and the others are integer constants with the values of 1, 2 and 3.
You can also specify a value inside the enum definition if you need.
The great thing is that you can now declare a function like this:
function ChangeWeather(Weather w) {
if (w == eRain) {
...
}
else if (w == eStorm) {
...
}
...
}
Much more readable, and in addition, if you type ChangeWeather(, the auto-complete window will show the three enums you declared.
4.
Explaining Pointers is sort of hard; one really needs to grasp the concept once, and everything will fall into place.
An ubiquitous example of a Pointer is player. It "points" to the current player character, e.g. cEgo.
So in this case, if you have "player.Walk(x, y);" written in a script, you really call cEgo.Walk(x, y);.
But if the player changed and player now pointed to cLarry, the same line would call cLarry.Walk(x, y);
Declaring your own pointers is very handy.
Consider this:
function iCellphone_Useinv() {
InventoryItem*i = player.ActiveInventory; // i is now a pointer of type InventoryItem, pointing to the
// item the player has just used on the cell phone.
if (i == iBattery) {
Display("You put the battery into the cell phone and power it on.");
player.LoseInventory(i);
}
else Display(String.Format("You're not sure how to combine the %s with the cell phone.", i.Name));
}
Instead of having to constantly type "player.ActiveInventory", a simple "i" does the exact same job.
Plus, I can change i to whatever other InventoryItem I want.
It an elegant substitute for storing the ID number of something in an integer variable.
5+6:
You'll only really need "static" if you want to write a set of module functions that begin with "MyModule."
A struct is used to combine several variables into a dataset.
// header
struct strContact {
String Name = "", // initial value of "" instead of null to avoid errors
int Age,
String Occupation = "";
import function DisplayAge();
};
// main script
strContact Roger;
strContact Larry;
function strContact::DisplayAge() {
Display(String.Format("%s's age is %d.", this.Name, this.Age));
}
You have just declared two instances of the struct, Roger and Larry. Now you can do this:
Larry.Name = "Larry Laffer";
Larry.Age = 35;
Larry.DisplayAge();
This will result in "Larry Laffer's age is 35." being displayed.
Note that you can't access the struct members directly: Calling
strContact.DisplayAge();
will result in an error.
So if you want to write a module, you'd do something like this:
// header
struct RainModule {
import static void SetDropsAmount(int da);
import static int GetDropsAmount();
import static void StartRain();
import static void StopRain();
}
// main script
int DropsAmount = 100;
static void SetDropsAmount(int da) {
DropsAmount = da;
}
static int GetDropsAmount() {
return DropsAmount;
}
static void StartRain() {
...
}
static void StopRain() {
...
}
Now you are allowed to call "RainModule.StartRain();" directly, since the static keyword is used; you are just using a struct to group the functions together, not to create a template to generate several instances from.
Phew. Long post. I hope you'll find it useful.
Thanks!
Up until now I've just Retro-Fitted code from existing modules to suit my needs. It didn't really work.
I'd also suggest reading the articles on the wiki on enums, pointers, and AGS Pointers for Dummies.
~Trent
I got an error that I cant figure out how to resolve, and as I still have an active thread I felt it should go there:
I was trying my hand at module-making, working on a script that handles movement by only allowing forward and backward movement, clockwise and anti-clockwise rotation.
I get this:
RotoMove.asc(67): Error (line 67): PE04: parse error at 'RM_CurrentDirection'
The code:
if (keycode == RM_Clockwise) {
if (RM_CurrentDirection == eDirections_SouthEast) {
RM_CurrentDirection == eDirections_South; //line 67
player.Loop = 0;
I cant figure out why it doesn't like this code!
Just above that section is code(the Anti-Clockwise "if") that uses the same variable, but it had no problems with that.
Thanks for any help.
The == operator is the boolean operator, used for comparing two values. The = operator is the assignment operator, used to assign values to variables.
DAMMIT!
why didn't I see that?
Thanks.
New problem:
I've got the current code:
function Repeatedly_execute() {
if (IsKeyPressed(RM_Forward)) {
int newx;
int newy;
if (RM_CurrentDirection == eDirections_SouthEast) {
newx = 10000;
newy = 10000;
}
else if (RM_CurrentDirection == eDirections_NorthEast) {
newx = 10000;
newy = -10000;
}
else if (RM_CurrentDirection == eDirections_SouthWest) {
newx = -10000;
newy = 10000;
}
else if (RM_CurrentDirection == eDirections_NorthWest) {
newx = -10000;
newy = -10000;
}
else if (RM_CurrentDirection == eDirections_South) {
newx = 0;
newy = 10000;
}
else if (RM_CurrentDirection == eDirections_West) {
newx = -10000;
newy = 0;
}
else if (RM_CurrentDirection == eDirections_East) {
newx = 10000;
newy = 0;
}
else if (RM_CurrentDirection == eDirections_North) {
newx = 0;
newy = -10000;
}
player.WalkStraight(player.x + newx, player.y + newy, eNoBlock);
}
}
What it's supposed to do is, quite simply, walk in the direction indicated.
I copied most of it from the keyboard movement module, but changed a few things.
It's not working.
The player doesn't move.
What am I doing wrong?
I'm not sure, but I believe that calling a .Walk command every game loop will keep a character at their current position, since they never get the opportunity to actually begin to walk.
You'd have to do:
bool forward_key_down;
function Repeatedly_execute() {
if (IsKeyPressed(RM_Forward)) {
if (!forward_key_down) {
forward_key_down = true;
.... // direction stuff
player.WalkStraight(player.x + newx, player.y + newy, eNoBlock);
}
}
else {
forward_key_down = false;
player.StopMoving();
}
}
I'll give that a try...
[Edit]
code is now:
function Repeatedly_execute() {
if (IsKeyPressed(RM_Forward)) {
if (!Forward_Key_Down) {
Forward_Key_Down = true;
int newx;
int newy;
if (RM_CurrentDirection == eDirections_SouthEast) {
newx = 10000;
newy = 10000;
}
else if (RM_CurrentDirection == eDirections_NorthEast) {
newx = 10000;
newy = -10000;
}
else if (RM_CurrentDirection == eDirections_SouthWest) {
newx = -10000;
newy = 10000;
}
else if (RM_CurrentDirection == eDirections_NorthWest) {
newx = -10000;
newy = -10000;
}
else if (RM_CurrentDirection == eDirections_South) {
newx = 0;
newy = 10000;
}
else if (RM_CurrentDirection == eDirections_West) {
newx = -10000;
newy = 0;
}
else if (RM_CurrentDirection == eDirections_East) {
newx = 10000;
newy = 0;
}
else if (RM_CurrentDirection == eDirections_North) {
newx = 0;
newy = -10000;
}
player.WalkStraight(player.x + newx, player.y + newy, eNoBlock);
}
else {
Forward_Key_Down = false;
player.StopMoving();
}
}
}
and still no results.
Might be a bit of a cheeky question; but are you sure that:
1. A walkable area exists.
2. The character starts within the walkable area.
?
Debugging 101:
Add a display line before player.WalkStraight():
Display("Calling WalkStraight.");
Does it get called?
Quote from: Hudders on Fri 08/05/2009 08:57:03
Might be a bit of a cheeky question; but are you sure that:
1. A walkable area exists.
2. The character starts within the walkable area.
?
Yes and Yes.
First thing I do when I'm testing an idea for a game is import a blank white background and bucket on a walkable area.
Quote from: KhrisMUC on Fri 08/05/2009 08:59:43
Does it get called?
No, that's what I cant figure out.
I also put a 'Display("south");' in 'else if (RM_CurrentDirection == eDirections_South)', and that isn't being called either.
Maybe I'll have to look at the Keyboard_Movement module again, to make sure there aren't any differences that would cause no effect.
I've decided to post the entire module code, maybe that will help.
// Main script for module "RotoMove"
//*******************************************************************************************************************
enum RM_Directions {
eDirections_South,
eDirections_SouthEast,
eDirections_East,
eDirections_NorthEast,
eDirections_North,
eDirections_NorthWest,
eDirections_West,
eDirections_SouthWest
};
int walkbackdir;
//*******************************************************************************************************************
//DEFUALT SETTINGS
// \/
bool RM_On = true; //must be turned on for module effect
RM_Directions RM_CurrentDirection = eDirections_South;//Defualt Direction
// /\
//*******************************************************************************************************************
//keycodes
// \/
int RM_Forward = 372;//Up
int RM_Backward = 380;//Down
int RM_Clockwise = 377;//Right
int RM_AntiClockwise = 375;//Left
// /\
//*******************************************************************************************************************
//loop numbers
// \/
int South = 0;
int West = 1;
int East = 2;
int North = 3;
int SouthEast = 4;
int NorthEast = 5;
int SouthWest = 6;
int NorthWest = 7;
// /\
//*******************************************************************************************************************
// \/
bool Forward_Key_Down = false;
// /\
//*******************************************************************************************************************
function Repeatedly_execute() {
if (IsKeyPressed(RM_Forward)) {
if (!Forward_Key_Down) {
Forward_Key_Down = true;
int newx;
int newy;
if (RM_CurrentDirection == eDirections_SouthEast) {
newx = 10000;
newy = 10000;
}
else if (RM_CurrentDirection == eDirections_NorthEast) {
newx = 10000;
newy = -10000;
}
else if (RM_CurrentDirection == eDirections_SouthWest) {
newx = -10000;
newy = 10000;
}
else if (RM_CurrentDirection == eDirections_NorthWest) {
newx = -10000;
newy = -10000;
}
else if (RM_CurrentDirection == eDirections_South) {
newx = 0;
newy = 10000;
}
else if (RM_CurrentDirection == eDirections_West) {
newx = -10000;
newy = 0;
}
else if (RM_CurrentDirection == eDirections_East) {
newx = 10000;
newy = 0;
}
else if (RM_CurrentDirection == eDirections_North) {
newx = 0;
newy = -10000;
}
Display("walking");
player.WalkStraight(player.x + newx, player.y + newy, eNoBlock);
}
else {
Forward_Key_Down = false;
player.StopMoving();
}
}
}
function on_key_press(int keycode) {
if (RM_On == true) {
if (keycode == RM_AntiClockwise){
if (RM_CurrentDirection == eDirections_South) {
RM_CurrentDirection = eDirections_SouthEast;
player.Loop = SouthEast;
}
else if (RM_CurrentDirection == eDirections_SouthEast) {
RM_CurrentDirection = eDirections_East;
player.Loop = East;
}
else if (RM_CurrentDirection == eDirections_East) {
RM_CurrentDirection = eDirections_NorthEast;
player.Loop = NorthEast;
}
else if (RM_CurrentDirection == eDirections_NorthEast) {
RM_CurrentDirection = eDirections_North;
player.Loop = North;
}
else if (RM_CurrentDirection == eDirections_North) {
RM_CurrentDirection = eDirections_NorthWest;
player.Loop = NorthWest;
}
else if (RM_CurrentDirection == eDirections_NorthWest) {
RM_CurrentDirection = eDirections_West;
player.Loop = West;
}
else if (RM_CurrentDirection == eDirections_West) {
RM_CurrentDirection = eDirections_SouthWest;
player.Loop = SouthWest;
}
else if (RM_CurrentDirection == eDirections_SouthWest) {
RM_CurrentDirection = eDirections_South;
player.Loop = South;
}
}
if (keycode == RM_Clockwise) {
if (RM_CurrentDirection == eDirections_SouthEast) {
RM_CurrentDirection = eDirections_South;
player.Loop = South;
}
else if (RM_CurrentDirection == eDirections_SouthWest) {
RM_CurrentDirection = eDirections_West;
player.Loop = West;
}
else if (RM_CurrentDirection == eDirections_NorthEast) {
RM_CurrentDirection = eDirections_East;
player.Loop = East;
}
else if (RM_CurrentDirection == eDirections_NorthWest) {
RM_CurrentDirection = eDirections_North;
player.Loop = North;
}
else if (RM_CurrentDirection == eDirections_East) {
RM_CurrentDirection = eDirections_SouthEast;
player.Loop = SouthEast;
}
else if (RM_CurrentDirection == eDirections_North) {
RM_CurrentDirection = eDirections_NorthEast;
player.Loop = NorthEast;
}
else if (RM_CurrentDirection == eDirections_South) {
RM_CurrentDirection = eDirections_SouthWest;
player.Loop = SouthWest;
}
else if (RM_CurrentDirection == eDirections_West) {
RM_CurrentDirection = eDirections_NorthWest;
player.Loop = NorthWest;
}
}
}
}
can anyone see what I'm doing wrong?
You haven't declared Forward_Key_Down
I'm not sure if that's important but it's what sticks out.
I have, just above Repeatedly_Execute().
PLEASE HELP?! :-\
I know it sounds pathetic, but that's sort of the state that my non-working code has reduced me to.
I'd start throwing breakpoints and/or Display checks everywhere and see what is being called and what isn't.
~Trent
Ok, I'll give that a try, but I'm pretty sure what's being called, as at the moment one bit does everything it's supposed to, and the bit does nothing.
If I cant track down the problem soon, then I'll do a complete makeover of the code, starting from the walk_forward part
[Edit] I just went through and put a 'display("");' between every set of curly braces in the Repeatedly_Execute function, and found that nothing in that function was going - Not even the Function itself!
Unless there is some special rule about using 'Display("");' in Repeatedly Execute, then something really weird is going on.
I know the script is being used, as the on_key_press function is being called.
Any ideas?
I just threw a Display(""); call into gamestart, and nothing happened. Apparently you have to display at least a space, but the best way is display the script lines and variables. Until we can view runtime variables while debugging (a feature I want very much, but CJ has said will require rewriting the compiler), String.Format and Display calls will be your best debugging friends. Also, if you just need to know if the lines are firing, (and not care what variables are and such) you can use breakpoints instead. Check out the manual entry 'Debugging features'
~Trent
oh, I put a string in the Display method, just to be safe, but I'll have to try break-points now, I suppose... :(
[Edit] just realised the problem. its annoyingly simple: I used a capitol "R" for repeatedly_execute.
it still doesn't quite work, but at least now I can debug it properly...