PDA

View Full Version : AngelScript Requests & Help


Pages : [1] 2

Foly
Feb 15, 2013, 11:57 PM
Since there is no thread like this yet, I've decided to make one. This thread is about requests for scripts and help with JJ2 AngelScript. You can post requests for scripts you want to use in your level and ask people for help when something is not working with your code or you don't know if something is executeable.

There are a few rules/guidelines for posting:


When your code is long use a spoiler or link to the code instead.
Stay on topic, that also means no discussions about what should be added to jj2+ (there is another thread for that).
You can post critics about another code, just make sure this is really going to improve the code and not just changes the style of coding. Also if your code is criticized don't start a flamewar, let others decide if the critics are justified.
Be specific with what you want, if you want a frog to fly don't forget to mention how it will fly (i.e. floating at one tile or following the player like a bird).
If you know how to code consider asking for pseudocode instead, it is more likely people respond to pseudocode requests.
If your code is level specific consider posting the level.

Know that some requests are too hard/long or people don't always have motivation or time to spend to help you. Personally I don't mind to create some codes for other people, so don't think you shouldn't post because noone is going to help you :)

DoubleGJ
Aug 9, 2013, 03:42 AM
Digging up this thread with a plea for help.

I'm absolutely new to this scripting thing so pardon me if I ask for something completely obvious, but is it possible to write a script so a particular sucker tube will only work if a player moves with enough speed while touching it?

Violet CLM
Aug 9, 2013, 09:50 AM
You could try making your own sucker tube out of an onFunction# and the xSpeed, ySpeed, xPos, yPos, ballTime, and noClip properties, but there would still end up being some things you couldn't set at the moment, like turning off special moves. jjEventSet is probably closer to what you want.

MilloCz2
Aug 14, 2013, 03:12 PM
Could someone explain me please why jjTileSet function does not work properly?

To describe problem: I want it to create 1 tile in the air in the cords X,Y in layer 4. It does not create that 1 tile, but it creates invisible pillars all around the map. I really have no clue why.

If you haven't tried it, you can:
void onLevelLoad(){
jjTileSet(4,0,0,8);
}
You can pick any map with any tileset, but created tile (in my code, tile with number 8) should be masked.

Violet CLM
Aug 14, 2013, 04:47 PM
The 4x1 tile block you're setting a tile in is not unique to that position, therefore all other instances of that same 4x1 block receive the same change. The easiest way to ensure uniqueness is to make one of the tiles an animated tile and place an event—even one that doesn't do anything—on that animated tile.

MilloCz2
Aug 15, 2013, 01:58 AM
Hah, thanks for quick reply! I will check it out.

(1) Also, is there any way how to show int/doubles etc. in showText/in jjDebug ?

EDIT: (2) What are some good ways of player's INPUT ? I have seen pressing buttons 1-9 as weapon change; is there anything better? Such as input text via jj2 chat?

I'm just starting, both with Angelscript and C++ and I'm very interested in it, since JJ2 is one of my most favourite games.

Violet CLM
Aug 15, 2013, 02:50 AM
(1) AngelScript has a built-in (i.e. I didn't write it) function <code>formatInt</code> which does what you're looking for and can output in a variety of formats. Search the documentation for details.

(2) There's no direct way of accessing input in the most recent release, but it'll turn up later. "Player-Guided Missile" on J2O is an example of indirectly testing the left and right arrow keys (or A/D or whatever the player happens to be using).

PurpleJazz
Aug 17, 2013, 12:28 AM
Is there any way of detecting whether or not a playing is currently pressing the fire button? I'm trying to write a script where the player's ammo regenerates over a period of time, with a short delay after the last press of the fire button. This would stop ammo from regenerating continuously even when the player is constantly firing.

Violet CLM
Aug 17, 2013, 12:40 AM
Nope. But you could check whether the ammo count has gone down lately?

Seren
Aug 17, 2013, 08:16 AM
This is another possible solution that has insignificantly longer execution time but doesn't use global variables and is more flexible (can be used for players who aren't local):
bool playerHasShot(jjPLAYER@ player){
jjOBJ@ obj;
for(int i=0;i&lt;jjObjectCount;i++){
@obj=jjObjects[i];
if(obj.isActive&&(obj.eventID&lt;OBJECT::SMOKERING||obj.eventID==OBJEC T::TNT)&&obj.creatorType==CREATOR::PLAYER&&jjPlayers[obj.creator] is player&&(obj.state==STATE::FLY||obj.state==STATE::ROCKETFL Y)&&obj.counter==1) return true;
}
return false;
}

Jerrythabest
Aug 17, 2013, 01:41 PM
Whoa, that script could use some white space and comments. Is it checking whether a new bullet of a certain player has appeared?

Seren
Aug 17, 2013, 02:23 PM
If there exists an object that is active, is a bullet, was created by the player the function is called for, and has parameters that indicate it has just spawned, return true, otherwise don't.

MilloCz
Aug 29, 2013, 08:50 AM
Hey it's me again.

Could you tell me how to properly use formatInt? Since I don't understand it. I need jjAlert to display "You have X coins." (where X represents the number of coins you have)

cooba
Aug 29, 2013, 08:52 AM
jjAlert("You have " + p.coins + " coins.");

MilloCz
Aug 29, 2013, 10:06 AM
Oh, when I last tried to write it like that, I forgot to include +'s.
Thanks.

MilloCz
Sep 1, 2013, 07:54 AM
Another question: Why doesn't jjEventSet(p.xPos,p.yPos, 65) work for creating objects like, diamonds? It creates nothing instead, while 65 = Blue gem's ID. Doesn't work even for "OBJECT::BLUEGEM".

cooba
Sep 1, 2013, 08:34 AM
jjAddObject(OBJECT::BLUEGEM, p.xPos, p.yPos);?

Violet CLM
Sep 1, 2013, 09:40 AM
Also, you'd want <code>jjEventSet(p.xPos / 32,p.yPos / 32, OBJECT::BLUEGEM)</code> to the extent that worked at all, since events occupy whole tiles.

MilloCz
Sep 2, 2013, 12:13 AM
Also, you'd want <code>jjEventSet(p.xPos / 32,p.yPos / 32, OBJECT::BLUEGEM)</code> to the extent that worked at all, since events occupy whole tiles.

Well I give an example; If I place vine event on block and then I use jjEventSet BLUEGEM on the block, the vine disappears, but gem does not appear.

(this works even without dividing xPos by 32)

Toni_
Sep 6, 2013, 10:20 AM
I know nothing about angel scripting and it's possibilities, so I will ask some questions:

- is it possible to change counting on DOM level, so the checkpoint increases your points every 10 seconds? For example if your team has 3 CPs, your score increases by 3 every 10 seconds.

- is it possible to trigger somehow gems in DOM, so if your team owns checkpoint, you can spawn at that area? Otherwise you spawn at another CP you own, or your team loses.

- is it possible to make gems first neutralize and then capture, just like on beginning of the game? For example, red team captures the CP, blue player neutralizes it by standing there for 5 seconds (and nobody can spawn there when it's neutralized), and after that 5 more seconds to capture the checkpoint so players could spawn there.

I am trying to make something that looks similar to Shadowgun (https://play.google.com/store/apps/details?id=com.madfingergames.deadzone&hl=en)'s Zone Control gamemode. That could work very well in JJ2 with some changes.

Toni_
Sep 14, 2013, 10:22 AM
Could anyone answer me, please?

Foly
Sep 14, 2013, 11:39 AM
I don't think this is possible yet because there is no OBJECT:: DOMAREA. I've also tried to see if I could get the handle of a DOM object in case it's just another object with special properties but no luck there too.

Toni_
Sep 14, 2013, 01:22 PM
I have no knowledge of angel script, but is something like this possible? I will just try to show what I mean, without any real function there.

if gemCaptured = TRUE (activate some trigger)

where trigger is area (for example) 15x15 tiles around the gem, and when player spawns, he can warp there.

Violet CLM
Sep 14, 2013, 01:37 PM
JJ2+ doesn't presently allow you direct scripting access to DOM mechanics, but you could probably make your own facsimile.

Toni_
Sep 15, 2013, 03:30 AM
Not sure if I understand you what you wanted to tell me about Foly's level, but I am sad to hear that DOM scripting isn't possible. :(

Foly
Sep 15, 2013, 03:42 AM
Not sure if I understand you what you wanted to tell me about Foly's level, but I am sad to hear that DOM scripting isn't possible. :(

He means it is also possible to create your own domination area's like I did in that level, although looking back at that level I think it's a bit sloppy ;)

minmay
Oct 28, 2013, 08:15 PM
Is there any reliable way to check if a non-local player is spectating via AngelScript?

Violet CLM
Oct 28, 2013, 09:11 PM
Testing their position for being inside the level (instead of at 0,0) seems to be the preferred method at present.

minmay
Oct 28, 2013, 09:46 PM
I've tried that, but their position seems to lag a few frames behind when they actually start spectating (at least going by the console announcement)...even if they're the server!

Violet CLM
Oct 28, 2013, 09:53 PM
Console announcements are, without exception that I can think of, barely more than normal chat messages. They do not reflect the client receiving a notification to actually update any values locally.

minmay
Oct 28, 2013, 10:22 PM
Hm, I was expecting they would at least coincide in the server's case.

DoubleGJ
Oct 30, 2013, 08:43 AM
I'm having trouble with using parameters in place of numerical values. I tried making a script that would spawn an object and make it constantly float near the player, but simply inputting p.xPos and p.yPos for the object's x and y values breaks the whole script. Is there any particular syntax I must use to make this work?

Violet CLM
Oct 30, 2013, 09:03 AM
Sorry, that description's much too vague for me to diagnose your problem. My best guess is that either a) "p" is not a defined variable at the time the function is called or b) you're not passing the parameters in the correct order. If that's not it, you may have to post some more of your code for inspection.

DoubleGJ
Oct 30, 2013, 09:44 AM
Okay. Here's how it looks right now, for testing purposes:

void onFunction1()
{
jjOBJ@ angryegg = jjObjects[jjAddObject(OBJECT::EGGPLANT, p.xPos + 50, p.yPos + 50)];
angryegg.bulletHandling(HANDLING::IGNOREBULLET);
angryegg.xPos = p.xPos + 50;
angryegg.yPos = p.yPos + 50;
}

that's the whole thing so far.

cooba
Oct 30, 2013, 09:44 AM
p as a global property got deprecated. You need to use this:void onFunction1(jjPLAYER@ p)This will spawn the eggplant, but not constantly adjust its position. plusHeaven has an example of an object behaving the way you want.

Seren
Oct 30, 2013, 10:13 AM
angryegg.bulletHandling(HANDLING::IGNOREBULLET);
bulletHandling is not a function.
angryegg.bulletHandling=HANDLING::IGNOREBULLET;

DoubleGJ
Oct 30, 2013, 10:33 AM
ok after the fixes it works somewhat... the eggplant appears where it should, but when I try to make it stay there with onMain, it says I didn't declare angryegg and I don't know what to do

cooba
Oct 30, 2013, 11:06 AM
The beauty of custom behaviors is that you no longer need onMain to do anything complicated with objects:
void AngryEgg(jjOBJ@ obj) {
jjPLAYER@ p = jjLocalPlayers[obj.creatorID];
obj.xPos = p.xPos + 50;
obj.yPos = p.yPos + 50;
obj.draw();
}

void onLevelLoad() {
jjObjectPresets[OBJECT::EGGPLANT].behavior = AngryEgg;
jjObjectPresets[OBJECT::EGGPLANT].bulletHandling = HANDLING::IGNOREBULLET;
}

void onFunction1(jjPLAYER@ p) {
jjAddObject(OBJECT::EGGPLANT, p.xPos + 50, p.yPos + 50, p.playerID, CREATOR::PLAYER);
jjAlert("Eggplant added!");
}

Violet CLM
Oct 30, 2013, 11:22 AM
<code>p</code> the global object <em>should</em> still work, though&mdash;deprecated is not the same thing as removed.

Jerrythabest
Oct 30, 2013, 02:36 PM
AngryEgg? I see some Angry Birds game coming!

minmay
Oct 30, 2013, 05:28 PM
I want to make a TNT-like explosion with a custom radius. So basically I want to recreate what appears to be a part of BEHAVIOR::TNT, but I have no way to see inside that behavior, and mine needs to as close as possible. Any help? I have no idea what the shape should be, how the force parameter passed to onObjectHit should be calculated, etc.

EDIT: Aaand another question so soon. Anyone have the code (or just a mathematical description) for pickups bobbing up and down?
Seems that calling behave() with draw = false gets rid of it, which makes sense. But I want a pickup with its own sprite, and without the bobbing it looks jarringly out of place among the original pickups.
I'm having trouble replicating it from observation, e.g. it isn't in sync with other pickups and stops when shot by bullets but not when moved by belts...

cooba
Oct 31, 2013, 12:53 AM
Anyone have the code (or just a mathematical description) for pickups bobbing up and down?int frame = obj.objectID * 8 + jjGameTicks;

if (obj.yPos > jjWaterLevel) frame = frame*2 + (int(obj.xPos) + int(obj.yPos) * 256)*16;
else frame = (frame + int(obj.xPos) + int(obj.yPos) * 256)*16;

if (obj.ySpeed == 0) jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos + jjSin(frame)*4, obj.curFrame, obj.direction);
else jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction);

DoubleGJ
Oct 31, 2013, 04:11 AM
AngryEgg? I see some Angry Birds game coming!


I modeled this little script idea after the Adventure Island game for NES, where you need to eat food to stay alive, but eggplants are not edible and instead hover over you with creepy music playing and make you starve faster. In reality I'm trying this out for something completely different, but making an Adventure Island-esque level by the way isn't a bad idea. :P

Violet CLM
Oct 31, 2013, 08:55 AM
I want to make a TNT-like explosion with a custom radius. So basically I want to recreate what appears to be a part of BEHAVIOR::TNT, but I have no way to see inside that behavior, and mine needs to as close as possible. Any help? I have no idea what the shape should be, how the force parameter passed to onObjectHit should be calculated, etc.
Umm... good luck. There's a lot of code required for doing this <em>right</em> that just isn't publicly exposed in the API yet. Calling <code>onObjectHit</code> is okay, but without more direct access to the underlying collision code, I'd honestly be tempted to spawn a bunch of invisible PLAYERBULLET objects in a circle around the explosion and give them .animSpeed values based on their distance from the center. For extra credit, you could also search through the object list, decide which ones are near enough, and if they have .isBlastable set to true, change their .xSpeed and .ySpeed values.
But I want a pickup with its own sprite
For most cases, just calling <code>determineCurAnim</code> should be fine?
int frame = obj.objectID * 8 + jjGameTicks;

if (obj.yPos > jjWaterLevel) frame = frame*2 + (int(obj.xPos) + int(obj.yPos) * 256)*16;
else frame = (frame + int(obj.xPos) + int(obj.yPos) * 256)*16;

if (obj.ySpeed == 0) jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos + jjSin(frame)*4, obj.curFrame, obj.direction);
else jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction);
urge to simplify rising
if (obj.ySpeed == 0) {

int frame = obj.objectID * 8 + jjGameTicks;

if (obj.yPos > jjWaterLevel) frame = frame*2 + (int(obj.xPos) + int(obj.yPos) * 256)*16;
else frame = (frame + int(obj.xPos) + int(obj.yPos) * 256)*16;

jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos + jjSin(frame)*4, obj.curFrame, obj.direction);
}
else obj.draw();

minmay
Oct 31, 2013, 10:54 AM
int frame = obj.objectID * 8 + jjGameTicks;

if (obj.yPos > jjWaterLevel) frame = frame*2 + (int(obj.xPos) + int(obj.yPos) * 256)*16;
else frame = (frame + int(obj.xPos) + int(obj.yPos) * 256)*16;

if (obj.ySpeed == 0) jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos + jjSin(frame)*4, obj.curFrame, obj.direction);
else jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction);Wow, that's really going above and beyond. Thanks very much.



For most cases, just calling <code>determineCurAnim</code> should be fine?Correction, I want a palette-shifted pickup :P
urge to simplify risingBah, you didn't even convert those integer multiplications to bitshifts!

minmay
Oct 31, 2013, 03:45 PM
Is there any reliable way to check if a non-local player is spectating via AngelScript?
Testing their position for being inside the level (instead of at 0,0) seems to be the preferred method at present.A note to anyone wanting to use this, from my observation it only works for servers. Clients don't always get the spectating player's position updated and end up holding onto their old position (unless they pass near 0,0?). Even if the server has alwaysupdatepos on.

EDIT: After some testing it looks like spectating players hold onto their blink value and it gets sent to other players, but doesn't decrement. I can set it to -210 (any lower, or above 0, and it gets reset before it can get sent to other players). Currently I'm using that to test for spectating; if it's possible for it to get sent to other players while lower than -209, then I don't seem to be catching it in onPlayer, and even if it is I can just make sure the value stays at -210 for two consecutive frames.

DoubleGJ
Nov 1, 2013, 03:23 AM
Okay, more trouble.

I now have spawning objects in relevance to player position covered, but now I'm having trouble with object behavior. Specifically, I'm trying to spawn falling bricks that would behave exactly as if spawned by the Queen boss, minus the damage effect. Spawning works like it should, but the behavior is a problem. I looked through the documentation and I understand that enemy projectiles are unaccessible as objects as of now, so I had to experiment. Closest I got so far is modifying RF projectiles, which leave a rockety trail and explode on contact. It looks kind of cool, but because of the object type I don't know how to make them ignore walls they would fall from and I'd rather have them bump on a surface and then fall a little ways down like they originally do instead of exploding with a recoil effect (I'm doing this thing for a dramatic effect, not as harmful obstacles). Any suggestions?

cooba
Nov 1, 2013, 04:02 AM
You're looking for OBJECT::BOUNCEONCE.

Violet CLM
Nov 1, 2013, 07:49 AM
I looked through the documentation and I understand that enemy projectiles are unaccessible as objects as of now
Can you point me to what section is giving you that impression?
because of the object type I don't know how to make them ignore walls they would fall from
That's actually because of the behavior, not the object type. Behavior is the only part of an object that concerns itself with the clipping mask.

DoubleGJ
Nov 1, 2013, 08:51 AM
Wow, I didn't expect it to be that simple. Then again, BOUNCEONCE seems extremely logical, but because of how it's named I never noticed it on my own. My suggestion would be to put this right under QUEEN in the documentation... Unless nobody else finds this unobvious?

At any rate, I got my desired script scene. I even finally figured out the distinction between objects and behaviors... I guess. It's almost perfect. The only thing I could use is the screen shaking exactly like when falling rocks are triggered, except continuously. To make things harder, this has to work in tandem with a limit x scroll moving a good ways through the level. I have absolutely no idea how to even approach this problem. :B

Can you point me to what section is giving you that impression?
Expected them to be indented right under corresponding enemies, then looked around and was too blind to find them, I suppose.

Violet CLM
Nov 1, 2013, 09:12 AM
It would make a lot of sense to have it be BEHAVIOR::QUEENBULLET along with so many other boss sub-behaviors, I agree, but it has the relatively unique status of being its very own <code>jjObjectPresets</code> slot to contend with. I dunno. More extensive documentation of the various behaviors is a fine idea and also kind of a time-intensive one.

There's no AngelScript access to the camera-shaking code yet, basically because blur seemed to indicate in a comment somewhere that it was more complicated than he'd expected, so I've never taken the time to try it out. You could try shimming something together using <code>jjPLAYER::cameraFreeze</code>, but I don't know offhand how that would interact with the limit x scroll stuff.

Jerrythabest
Nov 3, 2013, 01:49 AM
In the weeks before joining the Plus team I actually annotated part of the camera control function for my Splitscreen Stereoscopy (http://www.jazz2online.com/jcf/showthread.php?t=19403) project. I've primarily focussed on the clearly controlled camera modes. Mostly the slides at the end of the level and during the Robot Boss cutscenes, and the code that keeps the camera pointed at one place. The part that I haven't fully annotated yet ('normal camera movement') almost certainly contains the nudging code (because 200 ops is somewhat more than I'd expect for just 'normal camera movement').

I figure we could hook the entire thing and expose several AngelScript functions to access its functionality.

P4rr0t
Nov 11, 2013, 06:33 AM
Hi

Can you make Enter/Exit the door with AREA::PATH code? but i can't find "Doors" in angelscript code snippets.

See picture
s9.postimg.org/46baxl0vj/jc2.png

Enter Door - Pos: 215, 85
Exit Door - Pos: 8, 8
Text Message "Press UP to enter through the door!" & "Press UP to exit through the door!"

Thanks :-)

P4rr0t
Nov 14, 2013, 03:18 AM
Soory double post!


angelscript doesn't work for me this entrance/exit door and more doors, can you help me? :confused:

void onPlayer() {
if (jjEventGet(p.xPos/32, p.yPos/32) == AREA::PATH) {
canvas.drawString(
(215*32) - 4,
(85*32) - 4,
"Press UP to entrance door!",
STRING::SMALL,
STRING::BOUNCE,
1
);
canvas.drawString(
(8*32) - 4,
(8*32) - 4,
"Press UP to exit door!",
STRING::SMALL,
STRING::BOUNCE,
1
);
}
switch () {
case 10:
x = 215; //Entrance door
y = 85;
break;
case 11:
x = 8; //exit door
y = 8;
break;

}
}
}

Thanks

cooba
Nov 14, 2013, 04:16 AM
void onMicky() {
if (bird) {
"why you no fly?",
kick = bird;
}
}

P4rr0t
Nov 14, 2013, 05:22 AM
Cooba, it is micky doesn't exist (already banned from jj.net)

Ask Violet CLM or Foly, read my code, pls :rolleyes:

Soory double post!


angelscript doesn't work for me this entrance/exit door and more doors, can you help me? :confused:

void onPlayer() {
if (jjEventGet(p.xPos/32, p.yPos/32) == AREA::PATH) {
canvas.drawString(
(215*32) - 4,
(85*32) - 4,
"Press UP to entrance door!",
STRING::SMALL,
STRING::BOUNCE,
1
);
canvas.drawString(
(8*32) - 4,
(8*32) - 4,
"Press UP to exit door!",
STRING::SMALL,
STRING::BOUNCE,
1
);
}
switch () {
case 10:
x = 215; //Entrance door
y = 85;
break;
case 11:
x = 8; //exit door
y = 8;
break;

}
}
}

Thanks

cooba
Nov 14, 2013, 06:05 AM
I did use "EragonParrot" as a name when testing Hereafter for about a week straight

P4rr0t
Nov 14, 2013, 06:32 AM
I did use "EragonParrot" as a name when testing Hereafter for about a week straight

Eragon and Parrot is fine!

ask my code #54 please?

Violet CLM
Nov 14, 2013, 10:27 AM
Some things that come to mind...
You're drawing the strings at fixed locations, which may or may not be appropriate for your own personal level layout. Certainly if you change your mind about where either of the doors are, you'll need to change the script as well, and it doesn't support multiple door pairs either. You'd be better off deriving the x and y position of the drawString calls from the x and y position of the player who triggers them.
<code>switch ()</code> is meaningless and presumably syntactically invalid. Find an article about how switch statements work, just in general, not even specifically in AngelScript. Alternatively just use <code>if</code>, since a three-possibility switch statement feels a little silly, but that's more personal preference speaking.
Your values <code>x</code> and <code>y</code> are not defined anywhere in the function and are not used anywhere in the function after being set.
Likewise, <code>canvas</code> is never defined. From context it's clear you want it to be of type <code>jjCANVAS@</code>, but you're not using a function that includes one in its parameters. Replace each <code>canvas.drawString</code> with <code>jjDrawString</code>.

P4rr0t
Nov 15, 2013, 03:53 AM
@Violet CLM

Okay, it's not working my code... :r can you fix my code? Thanks
And No triggers
See picture: s11.postimg.org/akpdji9lf/image.png

void onPlayer() {
if (jjEventGet(p.xPos/32, p.yPos/32) == AREA::PATH && jj[UP]) {
jjCANVAS@ jjDrawString(
(215*32) - 4,
(85*32) - 4,
"Press UP to entrance door!",
STRING::SMALL,
STRING::BOUNCE,
1
);
jjCANVAS@ jjDrawString(
(8*32) - 4,
(8*32) - 4,
"Press UP to exit door!",
STRING::SMALL,
STRING::BOUNCE,
1
);
}
if switch () {
case 10:
x = 7; //Entrance door
y = 7;
break;
case 11:
x = 214; //exit door
y = 84;
break;

}
}
}

Violet CLM
Nov 15, 2013, 08:47 AM
That's all but unchanged from the last time you posted your code, and I already listed several improvements you could make in it. If you're coming at this with no familiarity with coding, I'd suggest you start with something simpler. See if you can make a 'trigger zone' that turns on two different triggers at once, for example.

P4rr0t
Nov 16, 2013, 02:11 AM
That's all but unchanged from the last time you posted your code, and I already listed several improvements you could make in it. If you're coming at this with no familiarity with coding, I'd suggest you start with something simpler. See if you can make a 'trigger zone' that turns on two different triggers at once, for example.


Sorry, the code is hard for me. What about Warp with press UP key to entrance/exit door witout PATH/Trigger? can you create code "Doors" in Angelscript code snippets. I'm waiting for you :rolleyes:

http://www.jazz2online.com/snippets/

P4rr0t
Nov 17, 2013, 03:36 AM
That's all but unchanged from the last time you posted your code, and I already listed several improvements you could make in it. If you're coming at this with no familiarity with coding, I'd suggest you start with something simpler. See if you can make a 'trigger zone' that turns on two different triggers at once, for example.<br>
<br>
Sorry, the code is hard for me. Can you create code "doors" in Angelscript code snippet database.<br>
<br>
What about TEXT/WARP with message "Press UP to entrance/exit door" (p.KeyUp) and <b>no triggers</b>.<br><br>Pos: 8,8 = Entrance door<br>Pos: 215,85 = Exit door<br><br>Thanks <br>

Violet CLM
Nov 17, 2013, 11:29 AM
If you don't understand the most fundamental basics of how coding works, giving you something like that as a single unit really will not help you at all. Please do some research, read some manuals, try stuff out on your own.

P4rr0t
Nov 19, 2013, 01:56 AM
If you don't understand the most fundamental basics of how coding works, giving you something like that as a single unit really will not help you at all. Please do some research, read some manuals, try stuff out on your own.

I know, i already read angelscript readme...i ask you help me for all days




void onFunction4(jjPLAYER@ p, jjCANVAS@ canvas) {
if (p.KeyUp) {
p.DrawString(212*32, 84*32-16, "|Press UP to entrance door!",STRING::SMALL,STRING::BOUNCE);
p.WarpToTile(8,8 true); //Entrance door
}
}

i press up is nothing happened :confused:

P4rr0t
Nov 20, 2013, 01:00 AM
If you don't understand the most fundamental basics of how coding works, giving you something like that as a single unit really will not help you at all. Please do some research, read some manuals, try stuff out on your own.

Because i am not good code, i want entrance/exit doors with press UP only, please....? :(

void onFunction4(jjPLAYER@ p) {
if (p.KeyUp);
p.warpToTile(7,7, true); //Entrance door
}
jjAlert("&");
jjAlert("&");
jjAlert("&");
jjAlert("&");
jjAlert("&");
jjAlert("&");
jjAlert("|**Press UP to entrance door!**");
jjAlert("&");
}

Love & Thunder
Nov 20, 2013, 01:48 AM
Yes, but what Violet is saying is that to get good at coding you have to start fairly small.

P4rr0t
Nov 20, 2013, 05:59 AM
See picture
s23.postimg.org/ob8fx3t0r/jj2.png

Thanks a lot, zepect! :D

zepect is better than Violet/cooba has no help me all the time

* Problem Solved *

Stijn
Nov 20, 2013, 06:01 AM
If you don't understand the most fundamental basics of how coding works, giving you something like that as a single unit really will not help you at all.
It would've helped him with his immediate problem...

Love & Thunder
Nov 20, 2013, 06:20 AM
True, but...
Give a man a fish and he will be fed for a day. Teach a man to fish and he will be fed for life.

cooba
Nov 20, 2013, 06:26 AM
His immediate problem lies much deeper than not understanding AngelScript.

minmay
Nov 26, 2013, 04:17 PM
Is there any way to "just" change the amount of damage that TNT explosions cause? It doesn't seem to use animSpeed like other bullets.

Violet CLM
Nov 26, 2013, 04:30 PM
Not currently.

Slaz
Dec 22, 2013, 01:38 AM
Talking about being bad at coding, could someone point me in the right direction to create a very simple script that changes some palette colors?

I'd like to get a fixed number of jjPalette entries for a level's tileset changed at onLevelLoad during the entirety of the game.

I could probably look this up on the PlusPalette example, but I'm too lazy to dig into it. :p

Seren
Dec 22, 2013, 05:56 AM
Readme section completely dedicated to operations on palettes (http://www.jazz2online.com/jj2plus/plus-angelscript.html#jjpal)
Example of a script that changes the palette onLevelLoad (http://www.jazz2online.com/downloads/files/23228/xlmstronghold.j2as/info/)

Slaz
Dec 23, 2013, 11:35 AM
Readme section completely dedicated to operations on palettes (http://www.jazz2online.com/jj2plus/plus-angelscript.html#jjpal)
Example of a script that changes the palette onLevelLoad (http://www.jazz2online.com/downloads/files/23228/xlmstronghold.j2as/info/)

Hehe, a simple yet effective reply. My lazy butt just got the desired script to work! :7

DennisKainz
Jan 6, 2014, 02:01 PM
There's a problem.

AngelScript usually allows me to make Jazz run at higher speeds than 4 or 8, but in some levels, or maybe when I'm standing on the ground, the x speed is limited to 4 on walk and 8 on run.

I also can't find the variables corresponding to the spike boll's Sync, Speed etcetera, assuming they are part of var[11].

And I can't change any object's animation speed. The animSpeed command seems to do nothing with eg. the Labrat.

And this:
canvas.drawSprite([xPos], [yPos], [ANIM::set], [sub-anim], [frame], SPRITE::PALSHIFT, [param]);
Doesn't work. The param part isn't considered a valid part of the expression, as I keep on getting "No matching signatures for [expression]". So I can't change the deco's color.

And ... is there a way to check whether Jazz is standing on the ground? (like "platform", but checking for masked tiles instead)

And the virtual keycodes wiki doesn't tell me which are the virtual keycodes for each letter.

And I can't use the texture tools. It ALWAYS gives me "Identifier [style || texture] is not a data type".

minmay
Jan 8, 2014, 07:49 AM
animSpeed is almost never (maybe entirely never?) actually used to determine animation speed.

Seren
Jan 8, 2014, 08:18 AM
AngelScript usually allows me to make Jazz run at higher speeds than 4 or 8, but in some levels, or maybe when I'm standing on the ground, the x speed is limited to 4 on walk and 8 on run.
There is so far no reliable way to set player speed to values above 8. I would be able to write a workaround in AngelScript but I guarantee it's a better idea to wait for proper implementation.
I also can't find the variables corresponding to the spike boll's Sync, Speed etcetera, assuming they are part of var[11].
I won't look into this, but I see no reason why the objects would ever need to contain sync. Sync is only necessary on object initialization when it needs to learn about its current angle, so there's no reason to store it, it just loads it from event parameters. And the angle is kept somewhere between var[] values. Speed, I don't know, sounds to me like a var[] thing but if it's not, it might be stored in xSpeed or ySpeed, or constantly get reloaded from the event if they didn't decide to optimize its code, you'll have to check on your own.
And I can't change any object's animation speed. The animSpeed command seems to do nothing with eg. the Labrat.
animSpeed is almost never (maybe entirely never?) actually used to determine animation speed.
The animSpeed property, as far as I can tell, affects gem rings and some types of destructible scenery.
And this:
canvas.drawSprite([xPos], [yPos], [ANIM::set], [sub-anim], [frame], SPRITE::PALSHIFT, [param]);
Doesn't work. The param part isn't considered a valid part of the expression, as I keep on getting "No matching signatures for [expression]". So I can't change the deco's color.
Good thing it doesn't work because that's not what the function prototype looks like. Use the documentation. Or use the help debug messages you get.
And ... is there a way to check whether Jazz is standing on the ground? (like "platform", but checking for masked tiles instead)
Not through a direct variable, but something like <code>jjMaskedHLine(player.xPos-12,24,player.yPos+20)</code> should work. You can also perform a check for <code>ySpeed==0</code> just to be sure.
And the virtual keycodes wiki doesn't tell me which are the virtual keycodes for each letter.
Use an ASCII table instead.
And I can't use the texture tools. It ALWAYS gives me "Identifier [style || texture] is not a data type".
Because you didn't provide a sample of code you used, God knows what you did wrong but you did something wrong.

DennisKainz
Jan 10, 2014, 09:22 AM
Thank you for the advices, Sir Ementaler. You are REALLY too good to be real.

I have a new problem: I try to draw ANIM::DEVILDEVAN with jjDrawSprite, but JJ2 implicitly changes it into ANIM::JAZZ. Same with a few other animation sets, like ANIM::MENU and ANIM::BILSBOSS.

If you can help me out, I will CERTAINLY mention you in my episode's credits.

Violet CLM
Jan 10, 2014, 10:11 AM
<code>jjDrawSprite</code>, for better or worse, doesn't take the initiative to load sprites from anims.j2a if they haven't already been loaded for that level. To remedy this, either place a corresponding object or ambient sound event somewhere in JCS, or else call <code>jjOBJ::determineCurAnim</code>, which <em>does</em> try to load missing sprites.

(Please hold any concerns about that a) not making sense or b) not being documented, because you're right. There wasn't time/understanding to put in place a more elaborate/appropriate API for such things, but there needed to be <em>some</em> way of loading sprites in the meantime, so <code>determineCurAnim</code> got to be an interim solution)

DennisKainz
Jan 10, 2014, 11:04 AM
You have been very helpful! Thank you!
_______

I don't know how to use all the algebra operations. I only know how to use the % in something like "obj.xPos%32" to module the value in a range of 32.

Where can I find the whole list of algebra operations in scripting?

And how do I repeat an event many times in a game tick? For example, I would like to spawn 64 particles of pixel type on Jazz to simulate bleeding, but I can only add 1 particle per tick.

Violet CLM
Jan 10, 2014, 02:42 PM
At this point you're just asking about how the scripting language works, so I'd suggest <a href="http://www.angelcode.com/angelscript/sdk/docs/manual/doc_script.html">reading the docs</a>, particularly the first three sections. Or at least skim and look for words like "operator" and "loop."

DennisKainz
Jan 10, 2014, 10:17 PM
That is exactly the advice I needed. Thank you again.

There's one thing I can't find in the manual, though. How do I remove the decimal parts from a number?

For example, I want to check the enemy's x speed, but instead of checking it as "1.25" or "4.0625" or "3.785" I want it to be checked respectively as "1", "4" or "3".

Shortly, to check the numbers as natural, non decimal numbers.

And there's a new problem: I can't set a walking enemy's x speed to its current value minus something. I ask the game to calculate "necro.xSpeed = necro.xSpeed - 0.0625", but it converts it into "necro.xSpeed = necro.xSpeed" when I do, automatically discarding the subtraction part.

And I think it also converts xSpeed from "0" to "1" automatically when a walking enemy is on walking state.

And I can't find a behavior that respects everything. The pickup behavior respects the x and y speed, but always blocks on collision. The spark one doesn't block on collision and respects x and y speed, but ignores you in a range outside 240 or something, which isn't ok if you play in 640x480. Can the AngelScript experts create a behavior which respects everything you input to it, and you decide whether it respects collisions or not?

Also, when I kill an object and play a sound to it, the sound stops along with the object's death, and I don't want to add expressions apart to make the sound continue.

I'm sorry about bothering you so much. I swear I try to figure stuff out myself, but my logic skills aren't as high as yours.

Violet CLM
Jan 18, 2014, 10:46 AM
Editing your post didn't bump the thread, so it took me a while to see this:
There's one thing I can't find in the manual, though. How do I remove the decimal parts from a number?
I don't remember which syntax AS uses, but either <code>int(number)</code> or <code>(int)(number)</code> should work.
I ask the game to calculate "necro.xSpeed = necro.xSpeed - 0.0625", but it converts it into "necro.xSpeed = necro.xSpeed" when I do, automatically discarding the subtraction part.

And I think it also converts xSpeed from "0" to "1" automatically when a walking enemy is on walking state.
0.0625 should be large enough to register as a difference between float values. More likely this is a quirk of BEHAVIOR::WALKINGENEMY. It's built for walking back and forth at a constant speed, and the more you want that to change, the less likely it gets that it'll do everything you need.
Also, when I kill an object and play a sound to it, the sound stops along with the object's death, and I don't want to add expressions apart to make the sound continue.Post the code? I'm not sure what this would be.



In the "Requests" department: <strong>lwe9.j2l</strong>.

Love & Thunder
Feb 15, 2014, 03:15 PM
Hey, so this is probably going to make me seem like an idiot, but how do I check whether or not a player has destroyed a tile of destructible scenery? (If it's of any help, I want it to activate a trigger scenery event as a result, and all of this is supposed to be in singleplayer mode)

Violet CLM
Feb 15, 2014, 03:18 PM
<code>jjTileGet</code> would probably be simplest.

Love & Thunder
Feb 15, 2014, 03:46 PM
Okay, it's good to know that I'm doing that part right, but it also means that I've almost definitely got the syntax wrong...
void onMain {
if jjTileGet(4,11,29) == 10 {
jjSwitchTrigger(1)
}
}
(If it wasn't already obvious, I'm a complete Angelscript/C/C++ noob)

Violet CLM
Feb 15, 2014, 06:31 PM
This isn't Python, so you'll need to wrap some parentheses around the condition. <code>if (jjTileGet(4,11,29) == 10) {</code>.

Love & Thunder
Feb 15, 2014, 07:21 PM
I did try that at one point(And I just double-checked now) -- still not working.

Violet CLM
Feb 15, 2014, 08:45 PM
Oh, right... you also need <code>()</code> after <code>onMain</code>.

Remember to turn on <code>AngelscriptDebug</code> in plus.ini if you're writing code. It gives you line numbers and things for syntax errors.

Love & Thunder
Feb 16, 2014, 05:46 AM
Thanks, it works... Sort of.
New problem: If I have the destruct scenery change the tile into an animated tile(Using WebJCS), the script doesn't work(Although, if I use a non-animated tile, it works perfectly).
Here's what the code looks like now:
void onMain() {
if ((jjTileGet(4,10,28) == 0) && (jjTriggers[1] == false) == true) {
jjSwitchTrigger(1);
}
}
(The extra part I put that checks if the trigger is on prevents it from toggling the trigger every gametick)

cooba
Feb 16, 2014, 06:43 AM
(jjTriggers[1] == false) == trueWhat.void onMain() {
if (jjTileGet(4, 10, 28) == 0 && !jjTriggers[1]) {
jjTriggers[1] = true;
}
}Also, jjTileGet can check for animated tiles very simply (there's an entire appendix dedicated to that, pretty much).

Love & Thunder
Feb 16, 2014, 08:03 AM
What.
It checks two things, and if both of them return true, then it triggers.
Also, jjTileGet can check for animated tiles very simply (there's an entire appendix dedicated to that, pretty much).
Ah, my mistake was that I didn't put the "+ TILE::ANIMATED" flag on, although the real problem was me misinterpreting part of the AS Readme.
Now that I think about it, it was a really stupid mistake(Although, that's generally how I learn these things).
Anyway, thanks for the help. :)

KRSplatinum
Mar 7, 2014, 09:35 PM
Code to morph Spaz to Jazz by Nick of epictest.j2l



// The goal of this is to morph to Jazz for a test level

void onFunction1() {
p.morphTo(CHAR::JAZZ);
}

// Assume Jazz has greater than 0 health upon spawning

void onFunction2() {
p.health= 0;
switch(jjRandom() % 3) {
case 0: jjChat("/me |||Burned in Fire"); break;
case 1: jjChat("/me |||Burned in Fire"); break;
case 2: jjChat("/me |||Burned in Fire"); break;
}
}






// Access the code to automatically recognize Spaz's popularity



void onFunction3() {
p.morphTo(CHAR::SPAZ);
}

A.I.T.
Mar 11, 2014, 06:19 AM
Is there any way of giving objects shields(namely enemies so that they can shoot with them and pickups so that they hurt the player upon contact until shieldTime runs out)?

I have disabled the functions of the fire shield so far:


void onLevelLoad() {
jjObjectPresets[OBJECT::FIRESHIELD].behavior = Incendie;
}

void Incendie(jjOBJ@ boule) {
boule.behave(BEHAVIOR::MONITOR, false);
if (boule.state == STATE::KILL) boule.state = STATE::ACTION;
}
void onPlayer(jjPLAYER@ play) {
if (play.shieldType == 1) play.shieldTime = 0;
}

Pointing out the position of the specific object afterwards does not seem to work. Besides, I have gone through about 80 animations in the ''Pickups'' section and still have not found one of an active shield. I suppose the parameters shieldType and shieldTime should also somehow be added to the jjOBJ class(?).

Thank you in advance!

Violet CLM
Mar 11, 2014, 12:18 PM
Nope.

Stavros
Mar 12, 2014, 09:08 AM
When I start my level in multiplayer mode, the result of following code is always 20, but in single player there are random values.. do you know what's the reason behind that??

void onLevelLoad()
{
for(int i = 0; i <= 20; i++) jjAddObject(OBJECT::APPLE, jjRandom()%3000, jjRandom()%3000);
}
int count()
{
int x = 0;
for (int i = 1; i < jjObjectCount-1; i++) if(jjObjects[i].isActive) x++;
return x;
}
void onMain()
{
if(jjGameTicks%210 == 0) jjAlert(""+count());
}

@Sir Ementaler: Thanks! :)

Seren
Mar 12, 2014, 09:26 AM
Single player mode saves memory and improves performance by deactivating most objects when they are too far away from the player. See jjOBJ::deactivates (http://www.jazz2online.com/jj2plus/plus-angelscript.html#jjobj).

Additionally you probably do not want to use <code>jjObjectCount-1</code> in your code because that means the object will not be registered if it's the final object.

incandescentembers
Mar 15, 2014, 12:37 AM
Let me create a post with bunch of large questions regarding the possibilities of Angel Script (some of them I've already asked in SWAG thread, but I don't want to make more offtopings). I'm sorry if some of that was already explained, I just want to put all my ambiguities together. I will really appreciate if someone will take his time and patience and will give me exhaustive answers for all of these points:


Can you modify the JCS with the AngelScript? For example: can you add more layers (that would be super useful for people who love making BIG tilesets, so they wouldn't have to worry about including same tiles for million times just with different backgrounds)

Is there any way to somehow incorporate enemies' behaviors from JJ1? For example I love that mechanic snake from Orbitus in JJ1 and I would love to see that creature in JJ2. His movements seem to be very simple. The graphics for all JJ1 enemies are availible freely on the web. It looks to me like an easy job for someone who knows coding. Am I wrong?

How enemies work in JJ2 anyways? I know that there are some enemies that don't work properly, and there are some dublets just with different graphics (like Lizard and Lizard Xmas, etc.). Is there a way to add more custom enemies (and by this I mean like real ENEMIES or BOSSES that are easy to place in JCS for noobs like me who don't know any fancy coding, not some inventions like flying Pharao-rabbit from Ozymandius) to JJ2 (doing some coding, hacking or something like that) or the limitations don't allow that? If not, it is still possible to just replace the existing ones, right? By modifying their behaviors and graphics?

Is there anyway to transfer some objects from JJ1 to JJ2? I think the most interested thing was the shield, the idea of diamonds floating around the rabbit, and losing each one after getting hit.

Also I think in my head that theoretically it is possible to add the large +15 gun circles from JJ1. With the sprite editor you could modify the graphics of the JJ2 gun screens, and then somehow modify the sound. Does this sounds right?

Is there any way to set up that after killing a boss you won't finish the level and can go on playing the same level the boss was in?

Is there any way to set up that after warping the coin-warp the coins won't change into diamonds?

Is there any way to set up bonus levels? For example by collecting certain ammount of diamonds (what are they for anyways in JJ2? I always thought that for some kind of bonus stages, since they are even counted at the end of each level!).

Is there any way to set up the secret level system to work correctly?

Is there any way to elminate sugar rushes, especially that annoying music, which destroys the atmosphere of the level by stopping it's music and jumping with that not-fitting 20 seconds of madness?

Is there any way to change the ammo limit to 999, just like in Jazz 1? 99 seems veeeeeery little...

Seren
Mar 15, 2014, 02:16 AM
Can you modify the JCS with the AngelScript? For example: can you add more layers (that would be super useful for people who love making BIG tilesets, so they wouldn't have to worry about including same tiles for million times just with different backgrounds)
AngelScript doesn't modify anything but level gameplay. JCS, J2L and JJ2 don't support more than 8 layers. A visual illusion of more layers can be created with use of AngelScript functions jjCANVAS::drawTile (http://www.jazz2online.com/jj2plus/plus-angelscript.html#jjcanvas) and jjDrawTile (http://www.jazz2online.com/jj2plus/plus-angelscript.html#globalfunctions) but there may be slowdowns associated with this approach.
Is there any way to somehow incorporate enemies' behaviors from JJ1? For example I love that mechanic snake from Orbitus in JJ1 and I would love to see that creature in JJ2. His movements seem to be very simple. The graphics for all JJ1 enemies are availible freely on the web. It looks to me like an easy job for someone who knows coding. Am I wrong?
I didn't play JJ1 but I can easily answer you can script nearly any enemy behavior you want and you cannot add any graphics at all unless you include them in the tileset. If they're present in the tileset, you can probably replicate any behavior as long as it doesn't involve external sounds as well, which there is no way to add.
How enemies work in JJ2 anyways? I know that there are some enemies that don't work properly, and there are some dublets just with different graphics (like Lizard and Lizard Xmas, etc.). Is there a way to add more custom enemies (and by this I mean like real ENEMIES or BOSSES that are easy to place in JCS for noobs like me who don't know any fancy coding, not some inventions like flying Pharao-rabbit from Ozymandius) to JJ2 (doing some coding, hacking or something like that) or the limitations don't allow that? If not, it is still possible to just replace the existing ones, right? By modifying their behaviors and graphics?
If butterflies count. This question looks unclear to me because you appear to be specifically asking for modifying JJ2 and not anything related to scripting, and this is essentially a scripting thread. If this answers your question, JCS and JJ2 are limited to 256 events and the amount of behaviors (http://www.jazz2online.com/jj2plus/plus-angelscript.html#custom) is limited by a number so huge you can call it unlimited. Hacking JJ2 with a new project would be many times more difficult than scripting new enemies. JJ2+ won't add enemies on request because the amount of events is too limited and scripting is provided.
Is there anyway to transfer some objects from JJ1 to JJ2? I think the most interested thing was the shield, the idea of diamonds floating around the rabbit, and losing each one after getting hit.

Also I think in my head that theoretically it is possible to add the large +15 gun circles from JJ1. With the sprite editor you could modify the graphics of the JJ2 gun screens, and then somehow modify the sound. Does this sounds right?
This was answered in the previous questions because objects and enemies are internally the same thing.
Is there any way to set up that after killing a boss you won't finish the level and can go on playing the same level the boss was in?
Yes but there is no direct setting for that so it's hard to tell how difficult that is to do.
Is there any way to set up that after warping the coin-warp the coins won't change into diamonds?
This was directly answered in the readme in the Global Properties (http://www.jazz2online.com/jj2plus/plus-angelscript.html#globalproperties) section. Please read the manual before asking questions on forums.
Is there any way to set up bonus levels? For example by collecting certain ammount of diamonds (what are they for anyways in JJ2? I always thought that for some kind of bonus stages, since they are even counted at the end of each level!).
Yes as long as you aren't specifically asking for 3D bonus stages like those JJ1 has. JJ2 doesn't use gems for anything but points. It was supposed to give you an extra life for every 100 gems but from what I recall they couldn't get the code to work correctly and it was commented out.
Is there any way to set up the secret level system to work correctly?
It already does.
Is there any way to elminate sugar rushes, especially that annoying music, which destroys the atmosphere of the level by stopping it's music and jumping with that not-fitting 20 seconds of madness?
Yes, it was done in No Way Out.
Is there any way to change the ammo limit to 999, just like in Jazz 1? 99 seems veeeeeery little...
This was directly answered in the readme in the jjWEAPON (http://www.jazz2online.com/jj2plus/plus-angelscript.html#jjweapon) section.

incandescentembers
Mar 16, 2014, 08:42 AM
I didn't play JJ1 but I can easily answer you can script nearly any enemy behavior you want and you cannot add any graphics at all unless you include them in the tileset. If they're present in the tileset, you can probably replicate any behavior as long as it doesn't involve external sounds as well, which there is no way to add.

Can it be animated? Let's say I will put all the tiles needed for animation of some enemy - will this work?

I know I may be asking for too much, but can any one show me how can I build the easiest enemy that comes to my mind: that spiky ball from Technoir, which just moves from one wall to another. Let's just say that I have a one tile ball in my tileset and I just want to add to that ball the exactly same behavior as the mentioned enemy from Technoir: that is, moving horizontally from one wall to another. It hurts you when you touch it, you can kill it. Pretty plzzz?

If butterflies count. This question looks unclear to me because you appear to be specifically asking for modifying JJ2 and not anything related to scripting, and this is essentially a scripting thread.

Sorry. I wanted to ask if it's possible to add the new enemies to the system, so they will work in JCS just like the original enemies, so the noobs like me won't have to use any script, will just go to JCS, bring up the enemy list and place them in the level. But you already said that AngelScript does not modify JCS.

Yes as long as you aren't specifically asking for 3D bonus stages like those JJ1 has. JJ2 doesn't use gems for anything but points. It was supposed to give you an extra life for every 100 gems but from what I recall they couldn't get the code to work correctly and it was commented out.

No, absolutely no 3D bonuses. Just a regular JJ2 level which is entered like a bonus (that is, after collecting something in the previous level, at the end of that level it warps you to the bonus level).

It already does.

Maybe I'm tripping, but doesn't the original secret level in Medivo crash in JJ2? I remember that there was something wrong with that.

cooba
Mar 16, 2014, 09:33 AM
How can I make a Tuf Boss become an enemy?void onLevelLoad() {
jjObjectPresets[OBJECT::TUFBOSS].behavior = BEHAVIOR::WALKINGENEMY;
}I know I may be asking for too much, but can any one show me how can I build the easiest enemy that comes to my mind: that spiky ball from Technoir, which just moves from one wall to another. Let's just say that I have a one tile ball in my tileset and I just want to add to that ball the exactly same behavior as the mentioned enemy from Technoir: that is, moving horizontally from one wall to another. It hurts you when you touch it, you can kill it. Pretty plzzz?void onLevelLoad() {
jjObjectPresets[OBJECT::THING].behavior = Spikeball;
}

void Spikeball(jjOBJ@ obj) {
jjOBJ@ exp;
switch (obj.state) {
case STATE::START:
obj.direction = obj.xSpeed = -2;
obj.determineCurAnim(ANIM::DESTSCEN, 4); //32x32 square sprite
obj.determineCurFrame();
obj.bulletHandling = HANDLING::HURTBYBULLET;
obj.playerHandling = HANDLING::ENEMY;
obj.state = STATE::FLY;
case STATE::FLY:
obj.xPos = obj.xPos + obj.xSpeed;
if (jjMaskedVLine(obj.xSpeed > 0 ? obj.xPos + 16 : obj.xPos - 16, obj.yPos, 1)) {
obj.direction = obj.xSpeed = -obj.xSpeed;
}
jjDrawTile(obj.xPos - 16, obj.yPos - 16, 4);
break;
case STATE::KILL:
@exp = jjObjects[jjAddObject(OBJECT::EXPLOSION, obj.xPos, obj.yPos, obj.objectID, CREATOR::OBJECT)];
exp.determineCurAnim(ANIM::AMMO, 5);
jjSample(obj.xPos, obj.yPos, SOUND::COMMON_EXPL_TNT);
obj.delete();
break;
}
}Maybe I'm tripping, but doesn't the original secret level in Medivo crash in JJ2? I remember that there was something wrong with that.See the <em>Multiple Exits</em> example level.

Love & Thunder
Apr 12, 2014, 06:40 AM
Is there a simple way to create a flicker light once a trigger is activated, with the light appearing on top of the tile that the trigger activated?

Violet CLM
Apr 12, 2014, 03:42 PM
Simplest would probably be to loop through the object list, find OBJECT::TRIGGERSCENERY objects (with whatever other filters you need, like only ones in a certain area or whatever), and <code>obj.lightType = (obj.curFrame == 0) ? LIGHT::NONE : LIGHT::FLICKER;</code> After first setting the intensity, something like <code>jjObjectPresets[OBJECT::TRIGGERSCENERY].light = jjObjectPresets[OBJECT::FLICKERLIGHT].light;</code>

BadaboomAri
May 30, 2014, 04:37 PM
So I was tweaking around with changing the sprite and energy of some enemies in Castle1 using jjObjectPresets but the script doesn't work. I don't know what the problem is but hope you guys will be able to find a possible solution.

void onLevelLoad() {
jjObjectPresets[OBJECT::NORMTURTLE].determineCurAnim(ANIM::LORI, 13);
jjObjectPresets[OBJECT::BAT].determineCurAnim(ANIM::JAZZ, 14);
jjObjectPresets[OBJECT::DRAGON].determineCurAnim(ANIM::SPAZ, 5);
}

Seren
May 31, 2014, 01:13 AM
A large number of objects, including those you mentioned, contain animation changes within their behavior. Those tend to reference the animation globally rather than relative to the preset one, resulting in the desired animation being displayed either occasionally or never. To reliably and permanently change sprites of such objects, the best way is to modify their behavior. It's technically possible to write a common behavior function for that and I would consider it cleaner but it will be easier to understand if there are separate ones:
void myTurtle(jjOBJ@ obj) {
obj.behave(BEHAVIOR::NORMTURTLE, false);
obj.determineCurAnim(ANIM::LORI, 13);
obj.draw();
}
void myBat(jjOBJ@ obj) {
obj.behave(BEHAVIOR::BAT, false);
obj.determineCurAnim(ANIM::JAZZ, 14);
obj.draw();
}
void myDragon(jjOBJ@ obj) {
obj.behave(BEHAVIOR::DRAGON, false);
obj.determineCurAnim(ANIM::SPAZ, 5);
obj.draw();
}
Then you assign the behavior to the presets within onLevelLoad:
jjObjectPresets[OBJECT::NORMTURTLE].behavior = myTurtle;
jjObjectPresets[OBJECT::BAT].behavior = myBat;
jjObjectPresets[OBJECT::DRAGON].behavior = myDragon;

Zerg
Jun 18, 2014, 07:08 AM
I would like to ask, if is it possible to:
a) Make rfs affect only the player who shoots them - rf climbs don't throw others arround.
b) Uses that spawnpoint, which has a free route. (for ex. in a test:player number 1,3,4 are occupied, so it chooses 2, later 5,6... numbered player)

If one of them is possible, could someone help me out with that?

Violet CLM
Jun 18, 2014, 12:26 PM
a) would be something like this:
void onMain() {
for (int i = 1; i < jjObjectMax: ++i) {
jjOBJ@ obj = jjObjects[i];
if (obj.behavior == BEHAVIOR::RFBULLET && obj.state == STATE::EXPLODE && !jjPlayers[obj.creatorID].isLocal) //RF missiles, like most/all bullets, switch to STATE::EXPLODE in one gametick and actually run their explosion code in the next, so you have a chance to find them.
obj.delete(); //Or whatever. Changing its behavior to EXPLOSION or EXPLOSION2 might be good for showing its .killAnim animation, but the point is you don't want it to run its own death code and create a shockwave
}
}
b) I'm not sure I understand. "spawnpoint"? "free route"?

Zerg
Jun 21, 2014, 10:55 AM
Thank you for a).
I meant Start Position(Jazz/Spaz level start event). Like if they were numbered, the same as players are when they join a game. So When the player joins, it is placed to the same numbered event, as he/she has(actually order doesn't matter to me).

Violet CLM
Jun 21, 2014, 11:12 AM
Got it. What I'd probably do would be use warp targets instead of start positions, each of a different ID 0-31. (Or 200-231 or whatever, if you wanted to include an offset so that you didn't accidentally use the same ID somewhere in the level.) Then given a jjPLAYER@ play, <code>play.warpToID(play.playerID)</code>.

You certainly <em>could</em> use start positions, and do a loop through the level using <code>jjEventGet</code> in search of each one, then <code>break;</code> when you find the <code>playerID</code>th such event. Warp targets would just be easier. Up to you.

GLaDOS
Jul 3, 2014, 11:16 AM
What ways of sending information from the server to clients are there with AngelScript? I need to synchronize team ownership and capture progress of control points for a custom gamemode, and I'm currently using the /trigger command to transfer booleans to all clients, but switching those creates unavoidable "Trigger X has been ENABLED" messages, and I cannot send integer values that way.

I looked through all examples and several levels that use AngelScript, but most multiplayer scripts seem to have primarily local effects.

Are there any other values that JJ2+ currently synchronizes (preferrably without side effects) that I'm missing here?

Violet CLM
Jul 3, 2014, 12:18 PM
You can get a lot of mileage out of jjPLAYER::fireBullet.

(Obviously this is a domain that'll be much better next update.)

GLaDOS
Jul 3, 2014, 12:35 PM
Ah, I'll try this one, thank you very much!

AvalancheMaster
Jul 16, 2014, 04:01 PM
Hey, guys, I have some questions, all of which fall under one category, namely: I can't quite understand the way AS refers to objects. If I change an object behavior, would it change just for one instance of the object, for every instance created after the change, or for all instances? Here are some of the things I'm trying to achieve, bear in mind that I have very basic programming skills (some C++, some BASIC, some Python and a lil' bit of WarCraft 3 JASS):

1. How can I palshift the colors of all instances of an object, namely snow? I'm using a modified (through AS) version of Blade's FoFS tileset, and the dirt uses the same gradient as the "dirt", as seen below. I want to shift it to the "grass" (144-159) range.

http://i.imgur.com/0XnZv2r.jpg?1

2. A more complex question: how can I create a basic walking enemy that uses Jazz' stoned sprites, but with changed colors?

3. Is it possible to rotate the texture of the textured background by 90 degrees?

4. Just an additional question to Violet, is it feasible to use different J2A file through AS? I know it's not a CURRENTLY AVAILABLE option, I'm asking if it's a possible one. Of course, the palette should match the original Jazz palette.

Violet CLM
Jul 16, 2014, 06:33 PM
If I change an object behavior, would it change just for one instance of the object, for every instance created after the change, or for all instances?
It depends on what you mean by "change an object behavior." Whenever an object is added (through <code>jjAddObject</code> or by some bit of native code), the contents of the corresponding <code>jjObjectPresets</code> entry are memcpy'd into a slot in <code>jjObjects</code>. So if you make a change to an object in <code>jjObjects</code>, it'll affect only that one object; if you make a change to an object in <code>jjObjectPresets</code>, it'll affect every object created from that preset after that point, but not any objects that were <em>already</em> created. (The same applies to nearly any other object property, except for the few that get set as part of adding an object like xOrg or creatorType.)
jjOBJ@ donutPreset = jjObjectPresets[OBJECT::DONUT];
jjOBJ@ donut1 = jjObjects[jjAddObject(OBJECT::DONUT, 0, 0)];
//donutPreset.behavior == donut1.behavior == BEHAVIOR::PICKUP

donutPreset.behavior = BEHAVIOR::MONITOR;
//now donutPreset's behavior is MONITOR, but donut1's behavior is still PICKUP

jjOBJ@ donut2 = jjObjects[jjAddObject(OBJECT::DONUT, 0, 0)];
//donut2 is copied from donutPreset, so donut2's behavior is also MONITOR

donut1.behavior = BEHAVIOR::CRATE;
//only donut1's behavior is changed by this, and subsequently added donuts will continue to use MONITOR, not CRATE, unless...

jjOBJ@ donut3 = jjObjects[jjAddObject(OBJECT::DONUT, 0, 0, 0, CREATOR::OBJECT, BEHAVIOR::PADDLE)];
//donut3's behavior is PADDLE, not MONITOR, because that was explicitly provided in the jjAddObject call. This option is provided because jjAddObject calls the object's behavior function before you get a chance to initialize any of its other properties, and sometimes you might want to circumvent that.

What's important to understand is that nothing separates one object from another besides its properties, almost every one of which you can set in AS. (The only exceptions are <code>objectID</code>, for obvious reasons, and another two bytes which are only used while loading the level but never again.) If <code>jjObjects[1]</code> is a lizard, and you change its <code>eventID</code> and <code>behavior</code> and <code>curAnim</code> and so on, once you've changed enough properties, there will be <em>no</em> respect in which it is still a lizard.

After that I have some bad news for you...

1. How can I palshift the colors of all instances of an object, namely snow? I'm using a modified (through AS) version of Blade's FoFS tileset, and the dirt uses the same gradient as the "dirt", as seen below. I want to shift it to the "grass" (144-159) range.
Not in 4.3.
2. A more complex question: how can I create a basic walking enemy that uses Jazz' stoned sprites, but with changed colors?
Not in 4.3. Well, you could use SPRITE::PALSHIFT, but it doesn't work with leftward facing sprites, and SPRITE::PLAYER would require that there actually be a player with the colors you want.
3. Is it possible to rotate the texture of the textured background by 90 degrees?
Not in 4.3.
4. Just an additional question to Violet, is it feasible to use different J2A file through AS? I know it's not a CURRENTLY AVAILABLE option, I'm asking if it's a possible one. Of course, the palette should match the original Jazz palette.
Completely possible. For example, we use native JJ2 code to read from plus.j2d, changing the string embedded in Jazz2+.exe to read "plus.j2d" instead of "data.j2d" before the function gets called, and the same approach could be used for .j2a files too if that seemed like a good idea.

AvalancheMaster
Jul 17, 2014, 03:59 AM
Thanks for the answer.

A quick note: I meant that the snow uses the same palette entries as dirt, not dirt.

It depends on what you mean by "change an object behavior."

I want to change the behaviour of some enemies (though it seems that with the option for using palshifted jazz sprites gone, this one is off the list), and, more importantly, bullets & ammo pickups. Fastfire gives blaster ammo + fastfire, bouncers gives ammo + increased range, ice gives ammo + increased duration of freeze, and so on.

A minor change that I want to achieve is pal-shift some of the enemies, but if I understand correctly, you can palshift the whole image, and not some of the palette entries it uses.

Not in 4.3. Well, you could use SPRITE::PALSHIFT, but it doesn't work with leftward facing sprites, and SPRITE::PLAYER would require that there actually be a player with the colors you want.

Woah. That's sad and unexpected. Why leftwards facing sprites are any different?

Completely possible. For example, we use native JJ2 code to read from plus.j2d, changing the string embedded in Jazz2+.exe to read "plus.j2d" instead of "data.j2d" before the function gets called, and the same approach could be used for .j2a files too if that seemed like a good idea.

A future release? :rolleyes: Or too much work?

Not in 4.3.

Considered for next releases?

Those questions aside, it's good that LGR made this review, cause it made me come back to JJ2 (and finish stuff I was already working on). Which then made me realise that I have a ton of BG Warp suitable textures that might be useful for a next release. And I do mean "a ton".

http://i.imgur.com/zBbadHi.png

Seren
Jul 17, 2014, 05:31 AM
Violet's answers are perfectly correct in a way but I wanted to elaborate on the first point.

1. How can I palshift the colors of all instances of an object, namely snow? I'm using a modified (through AS) version of Blade's FoFS tileset, and the dirt uses the same gradient as the "dirt", as seen below. I want to shift it to the "grass" (144-159) range.

This is a complex question and I'm going to split it. How can you palshift the colors of all instances of an object? This is not too difficult. In most cases, all you have to do is change their preset's behavior to something like this on level load:

void newBehavior(jjOBJ@ obj) {
obj.behave(BEHAVIOR::oldBehavior, false);
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::PALSHIFT, value);
}

where the parts in red should be replaced by appropriate identifiers / literals.

Now, getting to the "namely snow" part; this doesn't solve your problem because you seem to have gotten it wrong. Snow instances are not objects. Or, to be unambiguous, they are not jjOBJ instances. They are particles, i.e. jjPARTICLE instances. As such, their options are much more limited. The main problem, as you can imagine, is that you cannot change their behavior. This is a major obstacle but can be overcome by creating snow that is either stored in jjOBJ instances or, preferably, instances of a custom class created for it. In either case you would need to know the default behavior of snow instances, which I believe I'm allowed to provide, and base the new one on that, and that would essentially do the trick, but you would have to prepare to face another problem - this time of much more prosaic nature. You said "144-159". You should be informed that the default snow sprite uses entries 128-136 and entry 201. I suspect that last one could, depending on the exact palette, force a change in your plans.

Anyway, the point is, although it requires an inadequate amount of effort, applying PALSHIFT to snowflakes is essentially possible.

Seren
Jul 17, 2014, 10:07 AM
Here's the kind of code I meant:
interface Iparticle {
void draw(jjCANVAS@) const;
bool process();
}
class Tsnowflake : Iparticle {
private float x, y, xSpeed, ySpeed;
private uint8 frame;
private int deathCounter, noClipCounter, speedModifier;
Tsnowflake(float xPos, float yPos) {
x = xPos;
y = yPos;
uint random = jjRandom();
xSpeed = -0.5f - (random &amp; 4095) / 16384.f;
ySpeed = ((random &gt;&gt;= 12) &amp; 8191) / 4096.f;
frame = (random &gt;&gt;= 13) &amp; 7;
deathCounter = 0;
noClipCounter = 35;
speedModifier = ((random &gt;&gt; 3) &amp; 15) &lt;&lt; 6;
}
void draw(jjCANVAS@ canvas) const override {
canvas.drawSprite(int(x), int(y), ANIM::SNOW, 0, frame, 0, SPRITE::PALSHIFT, 16);
}
bool process() override {
if (deathCounter == 0) {
uint random = jjRandom();
x += xSpeed += (int(random &amp; 1023) - 511) / 65536.f + jjSin(jjGameTicks + speedModifier) / 128.f;
y += ySpeed += ((random &gt;&gt; 16) &amp; 1023) / 65536.f;
if (noClipCounter &gt; 0)
noClipCounter--;
else if (jjMaskedPixel(int(x), int(y)))
deathCounter = 1;
} else {
if (++deathCounter &amp; 7 == 0 &amp;&amp; frame &lt; 7)
frame++;
if (deathCounter &gt; 70)
return false;
}
for (int i = 0; i &lt; jjLocalPlayerCount; i++) {
const jjPLAYER@ player = jjLocalPlayers[i];
if (x + 32 &lt; player.cameraX || y + 32 &lt; player.cameraY || x - 32 &gt;= player.cameraX + jjSubscreenWidth || y - 32 &gt;= player.cameraY + jjSubscreenHeight)
continue;
return true;
}
return false;
}
}
array&lt;Iparticle@&gt; particles;
void addSnow() {
for (int i = 0; i &lt; jjLocalPlayerCount; i++) {
const jjPLAYER@ player = jjLocalPlayers[i];
uint random = jjRandom();
float x = player.cameraX - 32 + player.xSpeed + ((random &amp; 0xFFFF) * (jjResolutionWidth + 64) &gt;&gt; 16);
float y = player.cameraY - 32 + (((random &gt;&gt; 16) &amp; 0xFFFF) * jjResolutionHeight &gt;&gt; 16);
particles.insertLast(Tsnowflake(x, y));
}
}
void drawParticleSet(const array&lt;Iparticle@&gt; &amp;in particleSet, jjCANVAS@ canvas) {
for (uint i = 0; i &lt; particleSet.length(); i++) {
particleSet[i].draw(canvas);
}
}
void processParticleSet(array&lt;Iparticle@&gt;&amp; particleSet) {
for (uint i = 0; i &lt; particleSet.length();) {
if (particleSet[i].process())
i++;
else
particleSet.removeAt(i);
}
}
void onDrawLayer4(jjPLAYER@, jjCANVAS@ canvas) {
drawParticleSet(particles, canvas);
}
void onLevelLoad() {
jjObjects[0].determineCurAnim(ANIM::SNOW, 0, false);
}
void onMain() {
addSnow();
processParticleSet(particles);
}
The number in red should be modified to the palshift parameter value you want to use. Notice this code doesn't require a snow event in the level.

Violet CLM
Jul 17, 2014, 01:39 PM
SE makes an excellent point re: drawing snow through direct drawSprite calls.

more importantly, bullets & ammo pickups. Fastfire gives blaster ammo + fastfire, bouncers gives ammo + increased range, ice gives ammo + increased duration of freeze, and so on.
Ah. For that you want to define an <a href="http://www.jazz2online.com/jj2plus/plus-angelscript.html#onobjecthit">onObjectHit</a> hook (scroll up a little from the anchor), and additionally <code>jjObjectPresets[OBJECT::FASTFIRE].scriptedCollisions = true;</code> and again for other pickups that you also want to modify in this way.
Woah. That's sad and unexpected. Why leftwards facing sprites are any different?
Each of the different SPRITE::Mode constants refers to a distinct set of drawing functions with distinct purposes in the game. Most are used for drawing ingame objects, but RESIZED is only used for stuff like 3D spike bolls, which never need to be horizontally flipped, and PALSHIFT is only used for colored text as caused by | or # characters, and text is never flipped.


We're staying largely mum about what 5.0 will or won't be able to do, so that people will take the time to do cool stuff with 4.3 instead of waiting around patiently for another set of functions to become available, and then another after that, and then another after that... this is planned to change in August, though, as the hype machine warms up again and we look for a release date.

AvalancheMaster
Jul 17, 2014, 05:52 PM
Here's the kind of code I meant:

The number in red should be modified to the palshift parameter value you want to use. Notice this code doesn't require a snow event in the level.

Works like charm! One question left, though: is there a way to make it appear above all layers (layer 3, mainly)? Currently it reveals all secret passages in my level. If not, I'll just make it react with mask tiles immediately.

EDIT: Violet, I seem to have found a bug.

I've currently set:

jjWeapons[WEAPON::BLASTER].infinite = false;
jjWeapons[WEAPON::BLASTER].maximum = 99;
p.ammo[WEAPON::BLASTER]==99;

However, when I run out of blaster, my ammo switches to the remaining bouncers I have, and correctly shows their number, but it never goes down. Basically it seems that it makes them "infinite".

Violet CLM
Jul 17, 2014, 06:02 PM
Works like charm! One question left, though: is there a way to make it appear above all layers (layer 3, mainly)? Currently it reveals all secret passages in my level. If not, I'll just make it react with mask tiles immediately.
Replace <code>onDrawLayer4</code> with <code>onDrawLayer3</code> or <code>onDrawLayer1</code>. :P

I'll look into the other thing. What's the context here? <code>onLevelLoad</code> or what? (And note that <code>p</code> is deprecated.)

AvalancheMaster
Jul 17, 2014, 06:14 PM
Here's the whole thing:

void onLevelBegin() {
jjWeapons[WEAPON::BLASTER].infinite = false;
jjWeapons[WEAPON::BLASTER].maximum = 99;
p.ammo[WEAPON::BLASTER]=99;
}

cooba
Jul 18, 2014, 12:36 AM
I don't know about your problem, but you really need to make that intojjPlayers[0].ammo[WEAPON::BLASTER] = 99;

Violet CLM
Jul 18, 2014, 01:03 AM
Not if it's a multiplayer level, which hopefully it is or else the <code>infinite</code> line is the only one that does anything. For multiplayer you'd want <code>jjLocalPlayers[0]</code>. (Alternatively, set <code>maximum</code> in <code>onLevelLoad</code> instead of <code>onLevelBegin</code>, which should take care of setting ammo to 99 all on its own.)

AvalancheMaster
Jul 18, 2014, 01:27 AM
It's a single player level.

EDIT: Bizarrely enough, when I get rid of p.ammo[WEAPON::BLASTER]=99;, the problem disappears.

Violet CLM
Jul 18, 2014, 01:42 AM
<code>p</code> is only supposed to work for <code>onPlayer</code>, <code>onFunction#</code>, and <code>onPlayerTimerEnd</code>, and even in those cases it's only there for backwards compatibility and you should define a <code>jjPLAYER@</code> argument instead. Using <code>p</code> in <code>onLevelBegin</code> is undefined behavior.

AvalancheMaster
Jul 19, 2014, 11:43 PM
EDIT: Ok, no matter where I put jjWeapons[WEAPON::BLASTER].maximum = 35; it never works. How to fix this in singleplayer? Am I missing something?

Also, a question regarding FF. I managed to successfully turn the fastfire pickup into an ammo, but only for pre-places fastfire pickups. When an enemy drops fastfire, it acts as usual (no ammo, decreases bullets frequency).

Violet CLM
Jul 20, 2014, 12:56 AM
EDIT: Ok, no matter where I put jjWeapons[WEAPON::BLASTER].maximum = 35; it never works. How to fix this in singleplayer? Am I missing something?
void onLevelLoad() {
jjWeapons[WEAPON::BLASTER].maximum = 35;
jjWeapons[WEAPON::BLASTER].infinite = false;
} I would think?
Also, a question regarding FF. I managed to successfully turn the fastfire pickup into an ammo, but only for pre-places fastfire pickups. When an enemy drops fastfire, it acts as usual (no ammo, decreases bullets frequency).
Hmm... it looks like the code for dropping pickups like that (also used by crates) sets <code>scriptedCollisions</code> to false. (Also <code>isTarget</code> and <code>triggersTNT</code>, and <code>deactivates</code> to true.) This is conceivably a bug. You should be able to get around it by doing something like this:

void onLevelLoad() {
jjObjectPresets[OBJECT::FASTFIRE].behavior = MyFastfire;
}
void MyFastfire(jjOBJ@ obj) {
obj.scriptedCollisions = true;
obj.behavior = BEHAVIOR::PICKUP;
obj.behave();
}

AvalancheMaster
Jul 20, 2014, 06:05 PM
void onLevelLoad() {
jjWeapons[WEAPON::BLASTER].maximum = 35;
jjWeapons[WEAPON::BLASTER].infinite = false;
} I would think?


No, it didn't work. But I managed to find a workaround with several ifs doing the job.

However, I've got another problem at hand. I'm trying to tint the ball platform to blue, but when I put jjObectPresets[OBJECT::BOLLPLATFORM].behavior = IceballPlatform; in onLevelLoad, no part of the code loads up. I even tried it with the simple rat example, given in the AngelScript guide (void MyRat(jjOBJ@ rat) {rat.behave(BEHAVIOR::LABRAT);}). It didn't work as well.

Here's the relevant part of the code:

onLevelLoad(){
jjObectPresets[OBJECT::BOLLPLATFORM].behavior = IceballPlatform;
}
void IceballPlatform(jjOBJ@ plat) {
plat.behave(BEHAVIOR::PLATFORM, false);
jjDrawSpriteFromCurFrame(plat.xPos, plat.yPos, plat.curFrame, plat.direction, SPRITE::TINTED, 151);
}

Violet CLM
Jul 20, 2014, 06:24 PM
<em>jjOb<strong>j</strong>ectPresets</em>, with a <strong>j</strong>.

Blaster: how are you running the level? If you're cycling to it from another level that <em>doesn't</em> have that code, then you're going to start with 99 blaster left over from that previous level, and it won't be until you go below 35 that <code>maximum</code> is going to mean anything.

AvalancheMaster
Jul 20, 2014, 06:35 PM
<em>jjOb<strong>j</strong>ectPresets</em>, with a <strong>j</strong>.

Blaster: how are you running the level? If you're cycling to it from another level that <em>doesn't</em> have that code, then you're going to start with 99 blaster left over from that previous level, and it won't be until you go below 35 that <code>maximum</code> is going to mean anything.

Single player, first level off the pack.

Also, DID I REALLY fell for a typo mistake. x_

EDIT: And it still doesn't draw the chainlinks of the platform. Only the ball.

Seren
Jul 21, 2014, 07:42 AM
Also, DID I REALLY fell for a typo mistake.
That would suggest you don't have debug mode enabled. It's strongly suggested to have it on whenever you're doing anything with AngelScript. The readme introduction (http://www.jazz2online.com/jj2plus/plus-angelscript.html#intro) explains how to do that. You may also be interested in this download (http://www.jazz2online.com/downloads/7300/notepadplusplus-angelscript-language-support/) as, while it couldn't detect a mistake, said mistake would have never been made if the auto-completion feature were used.
And it still doesn't draw the chainlinks of the platform. Only the ball.
That's because <code>jjOBJ::behave</code>, when its second argument is set to <code>false</code>, stops all drawing operations from the behavior. You could solve that by drawing the chain manually but in your case a simpler solution may be to just call <code>behave</code> with the second argument set to <code>true</code>. This will have the effect of your tinted sprite being drawn on top of the regular one, which should be visually identical to what you're trying to achieve.

AvalancheMaster
Jul 21, 2014, 03:10 PM
That's because <code>jjOBJ::behave</code>, when its second argument is set to <code>false</code>, stops all drawing operations from the behavior. You could solve that by drawing the chain manually but in your case a simpler solution may be to just call <code>behave</code> with the second argument set to <code>true</code>. This will have the effect of your tinted sprite being drawn on top of the regular one, which should be visually identical to what you're trying to achieve.

I did it, and it worked, but the chainlinks are still drawn as usual. It seems that I will have to code them as well.

Also, palshifting the bat does this:

http://i.imgur.com/0yWQlvJ.png

I do realise it comes from the direction (capt'n obvious) yet I do not know how to solve it.

Code:

void Icebat(jjOBJ@ bat) {
bat.behave(BEHAVIOR::BAT, true);
jjDrawSpriteFromCurFrame(bat.xPos, bat.yPos, bat.curFrame, bat.direction, SPRITE::PALSHIFT, -56);
}

Violet CLM
Jul 21, 2014, 04:10 PM
I refer you to our discussion on the previous page of SPRITE::PALSHIFT not working with leftward facing sprites.

AvalancheMaster
Jul 21, 2014, 04:19 PM
I refer you to our discussion on the previous page of SPRITE::PALSHIFT not working with leftward facing sprites.

<iframe width="640" height="360" src="//www.youtube.com/embed/RXKJolS9Atg?feature=player_detailpage" frameborder="0" allowfullscreen></iframe>

Damn. What about the chain links?

Violet CLM
Jul 21, 2014, 05:15 PM
void onLevelLoad(){
jjObjectPresets[OBJECT::BOLLPLATFORM].behavior = IceballPlatform;
}
void IceballPlatform(jjOBJ@ plat) {
int angle = 0;

//get part of the angle before it moves
if (plat.state == STATE::PUSH)
angle = plat.var[4];
else if (plat.state == STATE::ACTION || plat.state == STATE::FREEZE)
if (plat.var[3] == 1) //U swing
angle = 1024 + int(jjSin(plat.var[4])*65536)/256;
else
angle = plat.var[4];

plat.behave(BEHAVIOR::PLATFORM, false);
angle += plat.var[5] * plat.var[2];

//links
int radius = 0;
jjObjects[0].curAnim = plat.killAnim;
jjObjects[0].frameID = 0;
int frame = jjObjects[0].determineCurFrame(false);
int radadd = 11; //one less than the width of the sprite, so change this if dealing with other platforms
int angleadd = -plat.var[5];
SPRITE::Mode mode = (plat.freeze != 0) ? SPRITE::FROZEN : SPRITE::TINTED;
for (int n=0; n< plat.var[2]; ++n) {
jjDrawSpriteFromCurFrame(
plat.xOrg + radius * jjSin(angle),
plat.yOrg + radius * jjCos(angle),
frame, 0,
mode, 151
);
angle+=angleadd;
radius+=radadd;
}
//ball
jjDrawSpriteFromCurFrame(plat.xPos, plat.yPos, plat.curFrame, plat.direction, SPRITE::TINTED, 151);
}

AvalancheMaster
Jul 22, 2014, 02:11 AM
void onLevelLoad(){
jjObjectPresets[OBJECT::BOLLPLATFORM].behavior = IceballPlatform;
}
void IceballPlatform(jjOBJ@ plat) {
int angle = 0;

//get part of the angle before it moves
if (plat.state == STATE::PUSH)
angle = plat.var[4];
else if (plat.state == STATE::ACTION || plat.state == STATE::FREEZE)
if (plat.var[3] == 1) //U swing
angle = 1024 + int(jjSin(plat.var[4])*65536)/256;
else
angle = plat.var[4];

plat.behave(BEHAVIOR::PLATFORM, false);
angle += plat.var[5] * plat.var[2];

//links
int radius = 0;
jjObjects[0].curAnim = plat.killAnim;
jjObjects[0].frameID = 0;
int frame = jjObjects[0].determineCurFrame(false);
int radadd = 11; //one less than the width of the sprite, so change this if dealing with other platforms
int angleadd = -plat.var[5];
SPRITE::Mode mode = (plat.freeze != 0) ? SPRITE::FROZEN : SPRITE::TINTED;
for (int n=0; n< plat.var[2]; ++n) {
jjDrawSpriteFromCurFrame(
plat.xOrg + radius * jjSin(angle),
plat.yOrg + radius * jjCos(angle),
frame, 0,
mode, 151
);
angle+=angleadd;
radius+=radadd;
}
//ball
jjDrawSpriteFromCurFrame(plat.xPos, plat.yPos, plat.curFrame, plat.direction, SPRITE::TINTED, 151);
}

That's quite helpful, thanks! While I did not end up using it, it did help me create a platform chain out of the tileset. Now I'm trying to create the platform itself using the tileset, but I'm experiencing troubles with making it solid. As far as I understand drawTile only draws a tile and disregards mask, right?

Violet CLM
Jul 22, 2014, 02:22 AM
int <b>drawTile</b>(int <i>xPixel</i>, int <i>yPixel</i>, uint16 <i>tile</i>, TILE::Quadrant <i>tileQuadrant</i> = TILE::ALLQUADRANTS)
Draws a tile of your choice at some position on the screen. This is purely a drawing operation; using it to draw masked tiles to the screen does not create masked areas for players or other objects to interact with.
<b></b>

AvalancheMaster
Jul 22, 2014, 02:50 AM
<b></b>

Ya, but I found a solution to this. A side question: can DrawTile use Resize modifier?

XxMoNsTeRXM
Aug 4, 2014, 01:05 AM
I want to verify if a player is at x-pos 53 and y-pos 79. I created a code but it doesn't work:


void onPlayer(jjPLAYER@ p) {
if ((p.xPos / 32 == 53 && p.yPos / 32 == 79) && jjGameTicks % 70 == 0)
jjAlert("Test");
}

Violet CLM
Aug 4, 2014, 02:13 AM
Instead of <code>p.xPos / 32</code>, try <code>int(p.xPos / 32)</code>. Otherwise you're comparing a float to an integer and the chances are rather lower they'll be equal.

XxMoNsTeRXM
Aug 4, 2014, 02:47 AM
Instead of <code>p.xPos / 32</code>, try <code>int(p.xPos / 32)</code>. Otherwise you're comparing a float to an integer and the chances are rather lower they'll be equal.

It worked, thanks!" also can you make a global timer? with timerStart to start it global, not player-based, or at least to verify the server game timer (server timer after pregame server timer), is it possible?

DennisKainz
Aug 19, 2014, 04:14 AM
I spent half an hour searching for a way to make the bats follow you all over the map.
All I found is that setting var[0] and var[11++] to 0 makes them chase you when you're close (and for some reason makes them shout while they're NOT awake and viceversa)
And setting these to anything else makes them NEVER chase you.
I also can't change their movement speed for chasing you.

I didn't want to bother you with more requests, but I can't do this by myself.

So, how do I give bats unlimited range? And how do I change their chasing speed?

Seren
Aug 19, 2014, 05:30 AM
Most of behavior constants for the majority of objects are hard-coded so you can't technically change only the distance bats detect you from or chase you from without rewriting the whole behavior. However, the position bats return to when they lose interest is their (xOrg, yOrg), so you could keep setting those to player's current position in order to make the bat chase them regardless of whether the range check succeeds. The variable you mention, var[0], stores ID of currently chased player, so you should use
const jjPLAYER@ player = jjPlayers[obj.var[0]];
obj.xOrg = player.xPos;
obj.yOrg = player.yPos;
or equivalent code. Speed values for bats are also more or less hard-coded but you can just adjust their position manually yourself. We established that xOrg and yOrg will always contain the position the bat is trying to reach so the code can look something like this:
obj.xPos = obj.xPos + (obj.xOrg > obj.xPos ? 2.f : -2.f);
obj.yPos = obj.yPos + (obj.yOrg > obj.yPos ? 2.f : -2.f);
Both of these pieces of code will naturally best fit in a custom behavior function that also calls the original behavior. However, at least the second one of them only makes sense to call when the bat is actually chasing somebody. You can make sure about that with a state check.
void bat(jjOBJ@ obj) {
const jjPLAYER@ player = jjPlayers[obj.var[0]];
obj.xOrg = player.xPos;
obj.yOrg = player.yPos;
obj.behave(BEHAVIOR::BAT);
if (obj.state == STATE::FLY) {
obj.xPos = obj.xPos + (obj.xOrg > obj.xPos ? 2.f : -2.f);
obj.yPos = obj.yPos + (obj.yOrg > obj.yPos ? 2.f : -2.f);
}
}

XxMoNsTeRXM
Nov 2, 2014, 01:57 AM
I got a code that does not work in multiplayer, it might be because it uses local variables, what I mean is that, if I join as a server it works, if I join as a normal player it crashes.

array<int> savedgems(3, 0);
bool access = true;

void onPlayer(jjPLAYER@ p) {

switch(p.health) {
case 0:
if (access) {
savedgems[0] = p.gems[GEM::RED];
savedgems[1] = p.gems[GEM::GREEN];
savedgems[2] = p.gems[GEM::BLUE];
jjAlert("Red gems current: " + p.gems[GEM::RED]);
jjAlert("|Red gems saved: " + savedgems[0]);
jjAlert("Green gems current: " + p.gems[GEM::GREEN]);
jjAlert("|Green gems saved: " + savedgems[1]);
jjAlert("Blue gems current: " + p.gems[GEM::BLUE]);
jjAlert("|Blue gems saved: " + savedgems[2]);
access = false;
}
break;
case 5:
p.gems[GEM::RED] = savedgems[0];
jjAlert("||Red gems loaded: " + p.gems[GEM::RED]);
p.gems[GEM::GREEN] = savedgems[1];
jjAlert("||Green gems loaded: " + p.gems[GEM::GREEN]);
p.gems[GEM::BLUE] = savedgems[2];
jjAlert("||Blue gems loaded: " + p.gems[GEM::BLUE]);
if (!access) access = true;
p.health = 4;
break;
}

}

cooba
Nov 2, 2014, 02:09 AM
"Crashes" tells me nothing. Is it an Access Violation, or an other kind of error? If it's an Access Violation, what are the two addresses listed in the message?

XxMoNsTeRXM
Nov 2, 2014, 02:28 AM
Yea it is.
"At adress 0043CC2Bh by attempting to read from adress 9F763A48h"

EDIT: Maybe I gotta put [p.localPlayerID]? I tested that with the blaster reloading script, if I remove all the p.localPlayerID it crashes, if I have them, it works fine. I'll test that.

EDIT 2: Still not working...

Also here's the new magic code:


bool access = true;

class savedGems {
savedGems() {
red = green = blue = 0;
}
int red;
int green;
int blue;
};

array<savedGems> gemsArray(4);

void onPlayer(jjPLAYER@ p) {
reloadBlaster(p);
switch(p.health) {
case 0:
if (access) {
gemsArray[p.localPlayerID].red = p.gems[GEM::RED];
gemsArray[p.localPlayerID].green = p.gems[GEM::GREEN];
gemsArray[p.localPlayerID].blue = p.gems[GEM::BLUE];
jjAlert("Red gems current: " + p.gems[GEM::RED]);
jjAlert("|Red gems saved: " + gemsArray[p.localPlayerID].red);
jjAlert("Green gems current: " + p.gems[GEM::GREEN]);
jjAlert("|Green gems saved: " + gemsArray[p.localPlayerID].green);
jjAlert("Blue gems current: " + p.gems[GEM::BLUE]);
jjAlert("|Blue gems saved: " + gemsArray[p.localPlayerID].blue);
access = false;
}
break;
case 5:
p.gems[GEM::RED] = gemsArray[p.localPlayerID].red;
jjAlert("||Red gems loaded: " + p.gems[GEM::RED]);
p.gems[GEM::GREEN] = gemsArray[p.localPlayerID].green;
jjAlert("||Green gems loaded: " + p.gems[GEM::GREEN]);
p.gems[GEM::BLUE] = gemsArray[p.localPlayerID].blue;
jjAlert("||Blue gems loaded: " + p.gems[GEM::BLUE]);
if (!access) access = true;
p.health = 4;
break;
}
}

Seren
Nov 2, 2014, 04:06 AM
The error is not caused by your script. Your script is technically correct (except for the accidental undefined reloadBlaster call in your latest post). The only problem it has is that <code>p.health = 4;</code> is a poor choice because, a) it's not obvious why this is done and b) the health change will cause a status update packet to be sent, which means unnecessary efficiency loss that could be avoided (finding a way to do so is left as an exercise for the reader).

The crash is most likely caused by the level alone but finding the cause proves troublesome. From the access violation error window, please provide the value of ESI.

XxMoNsTeRXM
Nov 2, 2014, 04:14 AM
reloadBlaster is not accidental, I didn't wrote the functionon the forum.

XxMoNsTeRXM
Nov 2, 2014, 04:52 AM
Welp... still not working, even though I am not changing health, I am just using it.
Let's try do it without even using health at all.

EDIT: There's no way I can make this without testing for health, I need a onDeath function.

Seren
Nov 2, 2014, 06:54 AM
I already said your script doesn't cause this error so your further modifications will not fix it. If I wanted you to avoid using the health variable, I would say so. What I said where I was talking about possible improvements to your script is that you should avoid writing to this variable when unnecessary because it involves additional actions, which in turn decrease efficiency, i.e. script execution speed. Most importantly, I never said avoiding its use would get rid of the error you experience, as that would be untrue. Now focus on what I wrote and notice I requested the value of the ESI register at the point of crashing that you can obtain from the error message. This is currently the only information from your side I'm interested in.

XxMoNsTeRXM
Nov 3, 2014, 03:01 AM
The ESI is 6h.

Also it would be possible to do my script on a function, instead of putting the death
pit on the level I could add a line of "Text" events in the level at the bottom of the level.

Seren
Nov 3, 2014, 11:45 AM
It appears that somewhere in your script you're trying to call <code>jjPLAYER::showText</code> on a non-local or undefined player. JJ2+ probably has a bug that makes this action potentially crash the game, thank you for the report; regardless of that though, calling it on a non-local player would have no effect and therefore also likely indicates a bug in your script. The call is likely to have a form of <code>p.showText</code> somewhere in the <code>onLevelLoad</code> hook function but that's just one of the possibilities. In case your code really contains references to the global variable <code>p</code> / <code>jjP</code> as the symptoms would suggest, you should consider completely refraining from its use, as mixing deprecated and new features may and will result in undefined behavior.

XxMoNsTeRXM
Nov 4, 2014, 03:20 AM
This is the only place I use show text:


void onLevelBegin() {
p.showText("@@@@@@#Treasure Jail", STRING::LARGE);

}
<int>

There's something wrong... I tested another level without the code that originally I thought it crashed when other client joins. About 1 month ago that map worked successfully, no crashes on multiplayer, so... it... might be... something with my server?

cooba
Nov 4, 2014, 03:39 AM
That really should bejjLocalPlayers[0].showText

XxMoNsTeRXM
Nov 4, 2014, 05:28 AM
That really should bejjLocalPlayers[0].showText
It actually is, that's the problem, I tested, I commented the p.showText and... cha-ching, works... lol... :lol:

It's interesting that people were able to join on my server 1 or 2 months ago, without any problem and it had

p.showText
<int>
then.

Everyone: Note that one line of your code could damage your entire level.

XxMoNsTeRXM
Jan 9, 2015, 11:36 PM
Ok, I obviously made a mistake, but I don't know where did I go wrong. I just tried to add the "Fall Damage" and "Wall Jumping" snippets. Argh, I don't even know how to modify two scripts.

int jumpKey = 0;
int fallTimer = 0;
const double maxFallTime = 4;

void onMain() {
jjPLAYER@ p = jjLocalPlayers[0];
p.ammo[2] = 3;
if (p.keyJump == true) {
jumpKey = jumpKey+1;
} else {
jumpKey = 0;
}

if (jjMaskedPixel(p.xPos + (p.direction * 13), p.yPos) && p.keyJump == true && jumpKey < 3) {
p.ySpeed = -10;
p.direction = p.direction * (-1);
p.xSpeed = p.direction * 5;
// && p.ySpeed < 0
}

if (jjMaskedPixel(p.xPos + 13, p.yPos) && p.ySpeed > 0 && p.keyRight == true) {
p.ySpeed = 1;
p.alreadyDoubleJumped = false;
}
if (jjMaskedPixel(p.xPos - 13, p.yPos) && p.ySpeed > 0 && p.keyLeft == true) {
p.ySpeed = 1;
p.alreadyDoubleJumped = false;
}

int fallTimer = 0;
const double maxFallTime = 4;

void onMain() {
if (!jjMaskedPixel(p.xPos, p.yPos + 32) && p.ySpeed > 0) {
fallTimer++;
} else if (jjMaskedPixel(p.xPos, p.yPos + 32)) {
int repeats = (fallTimer / 70) / maxFallTime;
if (fallTimer >= maxFallTime) {
for (int i = 0; i < (fallTimer / 70) / maxFallTime; i++) {
p.health = p.health - 1;
if (p.health < 0) p.health = 0;
}
}
fallTimer = 0;
}
if (p.health == 0) {
fallTimer = 0;
}
}

AngelScript reminds me a little bit about LUA, but LUA was slightly easier, or at least on Roblox. Don't judge the Roblox players, it takes a lot of time to do a decent game and you need to know both modeling and programming...

Well... you got 2 "void onMain()", you gotta put both snippets into one "void onMain()", that might be the problem. I remember I did that too and I was like "Why isn't it working?", the chatlogger didn't give me any errors, and I realized I've got 2 of them.
Also you declared the variables "fallTimer" & "maxFallTime" twice.

(I moved this reply from the JJ2+ Thread to this thread)

Primpy
Jan 10, 2015, 12:52 AM
Well... you got 2 "void onMain()", you gotta put both snippets into one "void onMain()", that might be the problem. I remember I did that too and I was like "Why isn't it working?", the chatlogger didn't give me any errors, and I realized I've got 2 of them.
Also you declared the variables "fallTimer" & "maxFallTime" twice.

(I moved this reply from the JJ2+ Thread to this thread)

Thanks a lot, I didn't notice I put two "void onMain()".

Primpy
Jan 10, 2015, 01:30 AM
Just wondering, but can Devan Shell be a playable character using Angel Script?

Love & Thunder
Jan 10, 2015, 06:12 AM
It should be possible as a simple sprite swap, I think.

Anyway, I'm having trouble getting an enemy surge working. The code is mostly a modified version of some code from plusEnscripted.
It turns up no errors, and the "Surge incoming" text comes up, but no enemies spawn. The coordinates of where I want to spawn stuff is between 237 and 247 widthwise, and 35 heightwise, according to JCS.
uint elapsed = 0;
bool surge = false;
int slain = 0;
const int SLAINTARGET = 10;
bool surgeover = false;

void onMain() {
if (surge == false) {
elapsed = 0;
} else {
elapsed ++;
}
if ((jjTriggers[5] == true) && (surgeover == false) == true) {
if (surge == false) {
jjLocalPlayers[0].showText("@@@@@SURGE INCOMING!", STRING::LARGE);
}
doEnemySurge();
}
}

void doEnemySurge() {
if (surge == false) {
surge = true;
}
if (slain < SLAINTARGET) {
if (elapsed % 70 == 0) { //Once per second
uint16 randomTarget = (237 + (jjRandom()&15)) * 32;
jjOBJ@ obj = jjObjects[jjAddObject(OBJECT::LIZARD, randomTarget, 1120)];
obj.state = STATE::FALL;
}
} else { //slain >= SLAINTARGET: surge is over
surgeover = true;
jjMusicLoad("carrotus.j2b");
jjLocalPlayers[0].showText("@@@@@SURGE COMPLETE!", STRING::LARGE);
for (int i = 0; i < jjLocalPlayerCount; i++) {
jjLocalPlayers[i].limitXScroll(43, 0);
}
elapsed = 0;
}
}Oh, also I'm triggering it using a trigger crate.

EDIT: Turns out that they're just invisible.
So, now my question is, why are they invisible, and how can I get them visible?
EDIT 2: I've placed other lizards in the level, but the ones coming from this script are still invisible.
EDIT 3: Wait, I fixed it.
Turns out it was the "STATE::FALL" that was the problem. Switching it to either a Float Lizard or removing that line fixes it.

I apologise for the slightly useless post. XD

EDIT 4: New problem: void onObjectHit(jjOBJ@ object, jjOBJ@ bullet, jjPLAYER@ player, int force) isn't triggering.

Violet CLM
Jan 10, 2015, 10:50 AM
<code>onObjectHit</code> is only called for objects with <code>scriptedCollisions</code> set to <code>true</code>.

The trouble with trying to make Devan a playable character in AngelScript is that you'd still see the rabbit sprites. You could do stuff with jjPLAYER::cameraFreeze, maybe offset layer 4 some number of tiles to the side and edit every behavior so it offsets its sprites accordingly, but that would be a pretty big hassle. Or you could stick Jazz in a wall somewhere and write your own platforming engine for Devan from scratch. Or you could decide it's probably not a great idea for 4.3.

Love & Thunder
Jan 10, 2015, 12:55 PM
Bullets are now going through multiple enemies, and although it does kill them, the kill counter still isn't going up.

Also, enemies are invincible in the air, and they only spawn at the two edges of the area I've specified for them to spawn in.

Violet CLM
Jan 10, 2015, 01:15 PM
Without knowing what the code looks like, it's pretty much impossible to point at what you're doing wrong.

Love & Thunder
Jan 11, 2015, 12:02 AM
uint elapsed = 0;
bool surge = false;
int slain = 0;
bool surgeover = false;

void onMain() {
if (surge == false) {
elapsed = 0;
} else {
elapsed ++;
}
if ((jjTriggers[5] == true) && (surgeover == false) == true) {
if (surge == false) {
jjLocalPlayers[0].showText("@@@@@SURGE INCOMING!", STRING::LARGE);
}
doEnemySurge();
}
}

void doEnemySurge() {
if (surge == false) {
surge = true;
}
if (slain < 10) {
if (elapsed % 70 == 0) { //Once per second
uint16 randomTarget = (237 + (jjRandom()&8)) * 32;
jjOBJ@ obj = jjObjects[jjAddObject(OBJECT::FLOATLIZARD, randomTarget, 1024)];
obj.state = STATE::FALL;
obj.var[5] = 0;
obj.scriptedCollisions = true;
}
} else { //slain >= 10: surge is over
surgeover = true;
jjMusicLoad("carrotus.j2b");
jjLocalPlayers[0].showText("@@@@@SURGE COMPLETE!", STRING::LARGE);
for (int i = 0; i < jjLocalPlayerCount; i++) {
jjLocalPlayers[i].limitXScroll(43, 0);
}
elapsed = 0;
}
}

void onLevelReload() {
slain = 0;
elapsed = 0;
}

void onObjectHit(jjOBJ@ object, jjOBJ@ bullet, jjPLAYER@ player, int force) {
if ((object.eventID == OBJECT::FLOATLIZARD || object.eventID == OBJECT::XMASFLOATLIZARD) && object.state != STATE::KILL) {
if (player !is null) {//no TNT or turtle shells in this level, so shouldn't be necessary, but can't hurt
if (force == 0) //normal collision, not using any buttstomps or whatever
player.hurt();
else {
//Here JJ2 would check to see if the object is frozen, and if so,
//unfreeze it and (possibly; some objects do this and others don't)
//alter the amount of damage it receives from the bullet. There's no
//ice ammo in this level, so that's not required.
if (force > 0) //probably a bullet
object.energy -= force;
else //special attack
object.energy -= 4;
if (object.energy <= 0) {
if (bullet !is null) {
if ((bullet.var[6] & 2) == 2) { //toaster and its ilk
object.particlePixelExplosion(1); //burny explosion
jjSample(object.xPos, object.yPos, SOUND::COMMON_BURN);
} else {
object.particlePixelExplosion(0);
}
object.grantPickup(player, (bullet.eventID == OBJECT::BLASTERBULLET) ? 5 : 10);
//JJ2 only ever calls grantPickup for enemies/crates destroyed
//by bullets, but you can branch out a bit if you like
} else {
object.particlePixelExplosion(2); //killed by physical contact
jjSample(object.xPos, object.yPos, SOUND::COMMON_SPLAT1);
}
object.state = STATE::KILL; //let the object's behavior function take care of deleting it
player.score += object.points;
jjPARTICLE@ score = jjAddParticle(PARTICLE::STRING); //JJ2 checks that jjGameMode is SP or COOP before doing this,
if (score !is null) { //and also makes sure that object.points is non-zero. We know both
score.xPos = object.xPos; //are true here, so there's no need to bother.
score.yPos = object.yPos;
score.xSpeed = -0.5 - (jjRandom() & 0x3FFF) / 65536.;
score.ySpeed = -1 - (jjRandom() & 0x7FFF) / 65536.;
score.string.text = formatInt(object.points, "1");
}
++slain; //the only reason we're going to all this effort
} else //not yet dead
object.justHit = 5; //flash white for five ticks
}
}
if (bullet !is null && (bullet.var[6] & 16) == 0) { //JJ2 also checks for var[6] & 4, aka the laser shield blast, but eh whatever
bullet.state = STATE::EXPLODE; //EXPLODE, like START, means the bullet won't be checked for collisions with other objects/players
//also, all normal bullet behaviors have code to dispose of themselves during EXPLODE, so that's nice
}
}
}

Violet CLM
Jan 11, 2015, 12:24 AM
they only spawn at the two edges of the area I've specified for them to spawn in.
You're confusing & and %

The other problems stem from your not writing <code>obj.bulletHandling = HANDLING::DETECTBULLET;</code> either while spawning the lizards or in their <code>jjObjectPresets</code> entry.

Love & Thunder
Jan 11, 2015, 01:08 AM
Ah, I thought it would be something simple like that.

Thank you very much. :)

EDIT:
Now having trouble adding a second wave to the surge.
I've added the following code:
} else if (slain < 30) {
if (elapsed % 60 == 0) { //Once every just less than a second.
uint16 randomTargetA = (237 + (jjRandom()%10)) * 32;
jjOBJ@ obj = jjObjects[jjAddObject(OBJECT::FLOATLIZARD, randomTargetA, 1024)];
obj.state = STATE::FALL;
obj.var[5] = 0;
obj.scriptedCollisions = true;
obj.bulletHandling = HANDLING::DETECTBULLET;
} else if (elapsed % 70 == 0) { //Once every second
uint16 randomTarget = (237 + (jjRandom()%10)) * 32;
jjOBJ@ obj = jjObjects[jjAddObject(OBJECT::BAT, randomTarget, 1008)];
obj.scriptedCollisions = true;
obj.bulletHandling = HANDLING::DETECTBULLET;
}
} else { //slain >= 30: surge is overBut the bats spawned don't take damage.
EDIT 2: They can be killed with special attacks, but not bullets. Either way, though, they don't trigger the onObjectHit code.
EDIT 3: By removing the bullet handling part, I've fixed them being invulnerable to bullets, but they still don't activate the onObjectHit code.
EDIT 4: For debugging purposes, I've added the following code in the onObjectHit part, which should trigger every time I hit a bat:
if (object.eventID == OBJECT::BAT) {
jjLocalPlayers[0].showText("@@@@@HIT", STRING::LARGE);
}But it doesn't. This proves that it's not triggering the onObjectHit thing.
EDIT 5: Tried swapping the bats out for ravens. Still didn't work.

Violet CLM
Jan 11, 2015, 12:22 PM
Try <code>obj.playerHandling = jjObjectPresets[OBJECT::FLOATLIZARD].playerHandling;</code>

KRSplatinum
Jan 11, 2015, 09:18 PM
Is it possible to create a level script that shows radar in-game?

Here's a good example of radar taken from Halo, the radar is in the bottom-left corner:

http://faqsmedia.ign.com/faqs/image/article/823/823401/10_halo_002.jpg

There's obviously precedent for finding other player's positions in the map, but I haven't seen what an HUD-based radar what look like in JJ2.

Foly
Jan 11, 2015, 11:14 PM
This is defininely possible. All you have to do is get some sprites, parts of tiles or whatever to draw the dots that represent players and a background. Every player has the position of all other players it's just a matter of scaling this to the dot position and making a condition for when the dots to show up. It's ofcourse also possible to put pu's, carrots and bases on it.

Toni_
Jan 12, 2015, 07:25 AM
I think you should ask Artem about that. He will explain you everything about radar and how it works.

cooba
Jan 12, 2015, 07:54 AM
I think you should ask Artem about the 5,478 lines of code he wrote for JJ2+ instead.

XxMoNsTeRXM
Jan 15, 2015, 03:35 AM
Is it possible to create a level script that shows radar in-game?

Here's a good example of radar taken from Halo, the radar is in the bottom-left corner:

http://faqsmedia.ign.com/faqs/image/article/823/823401/10_halo_002.jpg

There's obviously precedent for finding other player's positions in the map, but I haven't seen what an HUD-based radar what look like in JJ2.

Well... I am trying to make a radar script.

Primpy
Jan 15, 2015, 10:00 AM
Well... I am trying to make a radar script.

We know you can, good luck.
Apropo, majoritatea pustilor de varsta ta sunt niste pitici enervanti care se cred buricul pamantului. Ma bucur ca exista persoane inteligente ca tine in Romania!

XxMoNsTeRXM
Jan 22, 2015, 10:11 AM
I am trying to remake "somehow" the JJ1 Bonus in JJ2 (But not 3D)
http://i.imgur.com/7xOjwQp.png
Sounds interesting. I wish you luck! :)
Thanks!

Primpy
Jan 22, 2015, 11:18 PM
I am trying to remake "somehow" the JJ1 Bonus in JJ2 (But not 3D)
http://i.imgur.com/7xOjwQp.png

Sounds interesting. I wish you luck! :)

Jelly Jam
Jan 23, 2015, 03:56 AM
I am trying to remake "somehow" the JJ1 Bonus in JJ2 (But not 3D)
http://i.imgur.com/7xOjwQp.png

Does that mean the original 2d levels from JJ2 are going to be 3D, and that the 3D bonus levels will be 2D? :+
Just kidding, i wish you luck with this, cause it sounds really interesting:7

AvalancheMaster
Mar 24, 2015, 01:08 AM
It's not exactly a request but it would be if the answer is "yes".

Is it possible to combine a bridge and an Acc Belt? I'm thinking of modifying the MEZ03 serpentine belt so a custom "rolling" bridge can be made via Angelscript.

Violet CLM
Mar 24, 2015, 09:01 AM
heck, you can just put Acc Belt events in the area the bridge would take up in JCS. But more generally:
void onPlayer(jjPLAYER@ play) {
jjOBJ@ platform = jjObjects[play.platform];
if (playform.behavior == WHATEVER) {
play.xSpeed CHANGES SOMEHOW;
}
}

Love & Thunder
Mar 25, 2015, 07:49 AM
Do you think a Tails-like NPC would be hard to get working?

Violet CLM
Mar 25, 2015, 10:44 AM
The trickiest part would be writing all the logic for how to move around the level and what to react to and when to shoot and stuff. And that would be tricky. But that's because of AI, not AS.

XxMoNsTeRXM
Apr 7, 2015, 08:22 AM
Is it possible to do #include file.j2as?
EDIT: OF COURSE I CAN :) Because 5.0 IS SO AWESOME!
it's just:
#include "file.j2as";

XxMoNsTeRXM
Apr 7, 2015, 11:05 AM
ummm... it doesn't show errors in AS in 5.0
I think it's an error in the j2as I am using.
I use #include and I think maybe it can't get the error or something?

cooba
Apr 7, 2015, 11:07 AM
If you overwrote your old plus.ini with the one from the zip, you need to enable it manually again.

XxMoNsTeRXM
Apr 7, 2015, 11:20 AM
If you overwrote your old plus.ini with the one from the zip, you need to enable it manually again.
I did not do that, but AngelscriptDebug was indeed false. I set it to true and now it works. Anyway, thx!

Also I gotta learn more about the new version AS.

Ok, it says a function with the same name and parameters already exist, I know why because I use some of the JJ2+ functions in the thing that I include and in the main j2as, hmmm... I think I need help.

Violet CLM
Apr 7, 2015, 11:38 AM
Ok, it says a function with the same name and parameters already exist, I know why because I use some of the JJ2+ functions in the thing that I include and in the main j2asDon't do that.

XxMoNsTeRXM
Apr 9, 2015, 08:20 AM
Ok, I need help!
http://i.imgur.com/KtU4zHy.png

Violet CLM
Apr 9, 2015, 09:32 AM
ANIM::PLUS_AMMO is already loaded at the start of the level, so there's no need to load it again. Especially not every single render frame, which it looks like you're doing there. Naturally if you try to load 7 new jjANIMATION entries every frame, eventually you're going to go past 1500.
ANIM::AMMO and ANIM::PLUS_AMMO are different. That code would mess up every animation using any of the ANIM::AMMO animations&mdash;bullets, explosions, and so on.
Don't use <code>p</code>
Don't use <code>620, 455</code>. That won't work at other resolutions. Use <code>jjSubscreenWidth-20, jjSubscreenHeight-25</code>
I think that'll work in that case, but in general it's good to include a <code>jjIsTSF</code> check when writing Lori-specific code, since 1.23 doesn't always understand Lori-related constants.

Love & Thunder
Apr 9, 2015, 05:52 PM
Could someone explain how I can check if an object is using a specific set and animation?

I've tried searching the readme, but I haven't found anything.

Violet CLM
Apr 9, 2015, 07:18 PM
I suppose something like
bool doesObjectUseAnimation(jjOBJ@ obj, uint curAnim) {
jjANIMATION@ anim = jjAnimations[curAnim];
return obj.curFrame >= anim.firstFrame && obj.curFrame < anim.firstFrame + anim.frameCount;
}
bool doesObjectUseAnimation(jjOBJ@ obj, ANIM::Set setID, uint animID) {
return doesObjectUseAnimation(obj, jjAnimSets[setID].firstAnim + animID);
}

Zah dud4h
Apr 13, 2015, 06:48 AM
Is there something that makes the blue team lose if they didn't killed everyone from red team in tlrs after the game stopped?

Violet CLM
Apr 13, 2015, 09:36 AM
I'd try something like this (untested), if you're sure there'll be a time limit (maybe put some code in <code>onLevelBegin</code> to ensure that):

bool atLeastOneRedPlayerAlive() {
for (uint i = 0; i < 32; ++i) {
jjPLAYER@ play = jjPlayers[i];
if (play.team == TEAM::RED && play.isInGame)
return true;
}
return false;
}
void onGameStop(bool firstTime) {
if (!jjIsServer) return;
if (firstTime) return;
if (jjGameState == GAME::PAUSED) return;
if (atLeastOneRedPlayerAlive())
//somehow indicate that you think blue lost
}

Zah dud4h
Apr 14, 2015, 08:23 AM
I'd try something like this (untested), if you're sure there'll be a time limit (maybe put some code in <code>onLevelBegin</code> to ensure that):

bool atLeastOneRedPlayerAlive() {
for (uint i = 0; i < 32; ++i) {
jjPLAYER@ play = jjPlayers[i];
if (play.team == TEAM::RED && play.isInGame)
return true;
}
return false;
}
void onGameStop(bool firstTime) {
if (!jjIsServer) return;
if (firstTime) return;
if (jjGameState == GAME::PAUSED) return;
if (atLeastOneRedPlayerAlive())
//somehow indicate that you think blue lost
}

Thanks violet,now,is there something that sets the TLRS lives depending on how many people are playing?

Violet CLM
Apr 14, 2015, 10:04 AM
First you figure out how many people are playing; then you do whatever math you have in mind; then you set the number of lives.

XxMoNsTeRXM
Apr 22, 2015, 06:07 AM
I need help... I don't know much of how to use jjSTREAM, and I wanna make a custom command "!rename name" that only renames yourself, and I need to send a packet to the server to do the command "/rename clientID name".

Grytolle
Apr 23, 2015, 12:56 PM
Why don't you just make rename if jjisserver in the on Chat event?

XxMoNsTeRXM
Apr 25, 2015, 02:34 AM
Why don't you just make rename if jjisserver in the on Chat event?

Ok, I learned quite more about jjStream, and now I think I know how to use it. :)

DennisKainz
Apr 26, 2015, 06:57 AM
I wanted to insert a custom sprite in my level, replacing a food with another.
1st question: How do you change the amount of set IDs and their respective frames and animation amounts in your custom j2a file? You can't do it with Jazz Sprite Dynamite.
2nd question: What should I write in Angelscript to successfully replace a food sprite with one from my custom j2a file?

Violet CLM
Apr 26, 2015, 09:33 AM
1: Don't use Jazz Sprite Dynamite.
2: Suppose for the sake of simplicity that your food sprite is in animation 0 in anim set 0 in your custom j2a file. Then there are various approaches you could take, but these two are probably the most practical.
jjAnimSets[ANIM::CUSTOM[0]].load(0, "myCustom.j2a");
//option 1: affects only apples
jjObjectPresets[OBJECT::APPLE].determineCurAnim(ANIM::CUSTOM[0], 0);
//option 2: affects any object that might try to use the apple animation
jjAnimations[jjObjectPresets[OBJECT::APPLE].curAnim] = jjAnimations[jjAnimSets[ANIM::CUSTOM[0]]];

DennisKainz
Apr 28, 2015, 05:04 AM
Thank you for the help! I now can make those custom objects I've been trying to make for years! (see "Campaign Mysteries" and other archaic levelpacks of mine)

I'm now experimenting the tile redrawing functions of AngelScript. Is there by chance an option that allows you to not only draw a tile on a specified layer, but also repeat it along with the JCS Tile Width / Height function? (as far as it is in the screen, ofcourse, otherwise it would cause a hyperlag)

Violet CLM
Apr 28, 2015, 11:28 AM
Not built-in. You'll have to do the math yourself.

Crazy Rabbit
May 7, 2015, 07:58 AM
Greetings.
I've come up with idea to make a custom gamemode - Prop'n Hunt. The rules are simple: there's two teams in this game; red team for hunters, those who will hunt down blue and the blue team - props (morphed into pickups or level's furniture players).
Red team starts with black screen, that lasts for 15 (or more) seconds, then they get warped into the level. For that time the blue team must morph into something, that might be well disguised, then hide (the level is planned to be very big). Blue team can't shot or hurt anyhow, but a red team member also can't shot a fake furniture/pickup, because he'll get hurt then. Each player has one live per round...

Okay, now to the business - the problem is that I'm not well acknowledged with AngelScript, so I won't be able to make it alone.
I also didn't come up with HOW a blue team member is going to choose his disguise (maybe there's chat command, or a keybutton click on nearby pickup, or something?), so I'm asking you for help, if you're interested in that...

Treylina
May 7, 2015, 08:49 AM
So basically...a glorified hide and seek.

People who know the level well won't be fooled, unless the real pickups/furniture locations are randomized each round/cycle.

Okay I'm not really helping technical wise, though that's my two cents on the concept.

EDIT: Oh, so it's based off something else.

XxMoNsTeRXM
May 7, 2015, 11:19 AM
Greetings.
I've come up with idea to make a custom gamemode - Prop'n Hunt. The rules are simple: there's two teams in this game; red team for hunters, those who will hunt down blue and the blue team - props (morphed into pickups or level's furniture players).
Red team starts with black screen, that lasts for 15 (or more) seconds, then they get warped into the level. For that time the blue team must morph into something, that might be well disguised, then hide (the level is planned to be very big). Blue team can't shot or hurt anyhow, but a red team member also can't shot a fake furniture/pickup, because he'll get hurt then. Each player has one live per round...

Okay, now to the business - the problem is that I'm not well acknowledged with AngelScript, so I won't be able to make it alone.
I also didn't come up with HOW a blue team member is going to choose his disguise (maybe there's chat command, or a keybutton click on nearby pickup, or something?), so I'm asking you for help, if you're interested in that...

I think I can help you. :)

Slaz
May 23, 2015, 12:06 AM
Okay, I'm looking for a way to create an eyecandy effect for my level. I'd like tiny particles to fall gently from the top of the players screen. Imagine little stars falling down, or diamond dust falling while being illuminated by moonlight.

I still know little about AS, so I started experimenting. I've looked at jjParticle's ICETRAIL since those particles felt like they could do the trick. However, how do I make a few of them fall from the top of the screen? Do I need to make a jjCanvas relative to the players position and attach the jjParticle(s) to that?

If the jjParticle idea is all wrong for some reason, could a custom object using the icetrail anim work? Either way, I'd like some help!

Thanks in advance!

Violet CLM
May 23, 2015, 03:06 PM
void onPlayer(jjPLAYER@ play) {
jjPARTICLE@ part = jjAddParticle(PARTICLE::ICETRAIL);
if (part !is null) {
part.xPos = play.cameraX + (jjRandom() % jjSubscreenWidth);
part.yPos = play.cameraY;
}
}
You may want to use some more sophisticated approach than <code>jjRandom</code>, or a frequency different than one particle per tick (regardless of screen width), but the important thing is that <code>jjPLAYER::cameraX</code> and <code>jjPLAYER::cameraY</code> are used for translating between level coordinates and screen coordinates.

If you end up deciding against PARTICLE::ICETRAIL, though, you could also create your own tiny particle class containing position, (maybe) color and (maybe) lifetime values, make an array of that class, and draw blue pixels (or small rectangles or something) directly to a non-layer jjCANVAS based on the array's contents' positions. But ICETRAIL is simpler if you don't want to figure out classes.

SAMI
May 24, 2015, 04:11 AM
I don't know anything about Angle scripting. But I wanna know if its possible to increase screen area without changing resolution? For example this:
http://i1280.photobucket.com/albums/a486/RiasatSalminSami/Widescreen_zpsbk17zzn0.png
If yes, what should write?

Slaz
May 24, 2015, 04:13 AM
You may want to use some more sophisticated approach than <code>jjRandom</code>, or a frequency different than one particle per tick (regardless of screen width), but the important thing is that <code>jjPLAYER::cameraX</code> and <code>jjPLAYER::cameraY</code> are used for translating between level coordinates and screen coordinates.

If you end up deciding against PARTICLE::ICETRAIL, though, you could also create your own tiny particle class containing position, (maybe) color and (maybe) lifetime values, make an array of that class, and draw blue pixels (or small rectangles or something) directly to a non-layer jjCANVAS based on the array's contents' positions. But ICETRAIL is simpler if you don't want to figure out classes.

Your piece of code combined with ICETRAIL's color & delta values gave the exact result I was looking for. Many thanks! <code>jjRandom</code> makes it look fine, naturally there are more particles on the screen while standing still and less while the screen is scrolling. There's no need looking into classes or changing the frequency at all.

I will comment your name atop the script file. ;)

Seren
May 24, 2015, 04:18 AM
If yes, what should write?
Probably at least several hundred lines of code.

SAMI
May 24, 2015, 08:50 AM
Probably at least several hundred lines of code.

Can u help me with those codes?

Seren
May 24, 2015, 03:07 PM
I don't have the will to. The solution for tiles would involve hiding all layers and using the jjPIXELMAP constructor from tile ID to create sprites to be drawn with jjCANVAS::drawResizedSprite in onDrawLayer# hooks. It wouldn't work correctly for animated tiles so you'd have to handle those separately. Objects would preferably be modified within behavior functions to use jjDrawResizedSpriteFromCurFrame instead of jjDrawSpriteFromCurFrame. It wouldn't work for rotated sprites though - in fact, no as simple solutions would, so hopefully you don't need those. Players should have their jjPLAYER::invisibility property set to true and their sprites, and optionally names and other things, such as Spaz's bird, drawn manually with jjDrawResizedSpriteFromCurFrame. There's not much that can be done about particles either but luckily they're small so it's possible to get away with it. It also wouldn't have effect on textured backgrounds, water, etc. I wouldn't bet my money on stable fps after all of that is done.

XxMoNsTeRXM
Jun 30, 2015, 04:57 AM
Ok, so it seems like commands on "onChat & onLocalChat()" with Server don't work for me, what I mean is I put a if (stringReceived == "/test") and jjAlert("s") when I do that. And when I do it as a server it doesn't work, when I do it as a client it works! Did I do something wrong, or it just doesn't work with the Server?

Violet CLM
Jun 30, 2015, 09:19 PM
Commands (even invalid ones) are not supposed to be intercepted by the chat hooks at all. Any time they are is an error.

Love & Thunder
Jul 1, 2015, 01:25 PM
So, can you not make custom server commands in AS?

Seren
Jul 1, 2015, 01:45 PM
All messages starting in '/' are reserved by JJ2+ for clarity and forward compatibility. Similarly, due to collisions with whispering and admin chat I cannot recommend the use of '@' or '>' to signify custom commands. Nothing prevents script writers from using one of the other 23 non-alphanumeric ASCII characters present on every keyboard, however. Or, using my by far favorite solution, words.

szmol96
Jul 17, 2015, 12:12 PM
I guess the exclamation mark (!) is the most known symbol used by custom commands.

XxMoNsTeRXM
Jul 31, 2015, 12:40 PM
Ok, jjMaxLives doesn't work. Why, doesn't it? I just used it and it says it isn't declared, when I declare it and set a value to it, it's fine. I typed it correctly, and also tested it with a simple thing on my tests.mut, with jjAlert(jjMaxLives + ""). I also have the latest plus version. :?

Seren
Jul 31, 2015, 12:54 PM
True, that's a documentation error, the property doesn't exist.

XxMoNsTeRXM
Jul 31, 2015, 12:55 PM
True, that's a documentation error, the property doesn't exist. And why is it there in the angelscript readme? That confused me. I thought nobody noticed that.

Violet CLM
Jul 31, 2015, 04:06 PM
As SE said, it's an error. IIRC it had a temporary implementation, but that didn't end up working for clients, and it was a minor enough property that we opted for taking it out rather than fixing it. But then that particular change got missed while updating the documentation later.

Violet CLM
Aug 18, 2015, 10:59 AM
re: the Angelscript <em>Requests</em> part of this topic:

I'd like to see a mutator that automated some of the CTF codes, but I'm not enough of an expert on them to want to do it myself. At the very least, it would be nice if flag carriers could just announce their health (via teamchat) automatically--when picking up a flag, when their health changes, or when anyone asks "h" or "h?" via teamchat. Trying to type and send a number while running for my life tends not to be very pleasant. :(

XxMoNsTeRXM
Aug 18, 2015, 11:59 PM
re: the Angelscript <em>Requests</em> part of this topic:

I'd like to see a mutator that automated some of the CTF codes, but I'm not enough of an expert on them to want to do it myself. At the very least, it would be nice if flag carriers could just announce their health (via teamchat) automatically--when picking up a flag, when their health changes, or when anyone asks "h" or "h?" via teamchat. Trying to type and send a number while running for my life tends not to be very pleasant. :(

That is a great idea, it shouldn't be hard to do.

ScarXL
Aug 29, 2015, 01:01 PM
Since I cannot post new threads, I may aswell ask this here.
How can I make it so when I use a coin warp, all of the map's coins DON'T turn into gems?

cooba
Aug 29, 2015, 01:04 PM
By setting the global property <code>jjWarpsTransmuteCoins</code> to false on level load.

ScarXL
Aug 29, 2015, 08:26 PM
This is the code i've put:

void onLevelLoad() {
jjWarpsTransmuteCoins = false;
}

Did I do something wrong? Cuz it's not working.

EDIT: NEVERMIND it does. I was a stupe and ran it through JCS lol. Thank you cooba this helped a lot :D

SaVn
Sep 3, 2015, 03:30 PM
my problem is that I do not know all the codes AngelScript
I explain them?

Love & Thunder
Sep 3, 2015, 04:04 PM
Read the AngelScript manual. If you still have problems, come back.
Also, that's a pretty vague problem.

Love & Thunder
Sep 4, 2015, 03:35 AM
Read the code in question for Ozymandius, look up stuff you don't understand in the AS readme, and when in doubt, screw around with how a piece of code works until you understand it.

One thing to avoid doing in this case is copypasting code you don't understand. It will technically work most of the time, but you won't learn from it.

SaVn
Sep 4, 2015, 06:59 AM
What is "for (int i = 0; i < jjObjectCount; i++) {"
i don't known! anyone knows this code?

Seren
Sep 4, 2015, 08:02 AM
Preferably start by reading a good C/C++/C#/Java tutorial. Then read all of the following pages in full:

http://www.angelcode.com/angelscript/sdk/docs/manual/doc_global_func.html
http://www.angelcode.com/angelscript/sdk/docs/manual/doc_global_variable.html
http://www.angelcode.com/angelscript/sdk/docs/manual/doc_global_enums.html
http://www.angelcode.com/angelscript/sdk/docs/manual/doc_global_namespace.html
http://www.angelcode.com/angelscript/sdk/docs/manual/doc_script_statements.html
http://www.angelcode.com/angelscript/sdk/docs/manual/doc_expressions.html
http://www.angelcode.com/angelscript/sdk/docs/manual/doc_datatypes_primitives.html
http://www.angelcode.com/angelscript/sdk/docs/manual/doc_datatypes_obj.html
http://www.angelcode.com/angelscript/sdk/docs/manual/doc_datatypes_strings.html
http://www.angelcode.com/angelscript/sdk/docs/manual/doc_datatypes_arrays.html
http://www.angelcode.com/angelscript/sdk/docs/manual/doc_script_func_decl.html
http://www.angelcode.com/angelscript/sdk/docs/manual/doc_script_func_overload.html
http://www.angelcode.com/angelscript/sdk/docs/manual/doc_script_func_defarg.html
http://www.jazz2online.com/jj2plus/plus-angelscript.html

DennisKainz
Dec 8, 2015, 12:19 AM
I have tried literally everything to align my texts to the center, but nothing worked.
It's hard without examples.
Can I please have an example of ANY possible way to create ANY kind of centered text?

Seren
Dec 8, 2015, 01:26 AM
plusCharJump.j2as lines 90-93. Noticeably line 91 is currently obsolete and no longer required.

DennisKainz
Dec 8, 2015, 02:45 AM
Thanks for the help, and sorry for the disturb.
I now can make my custom text!

DennisKainz
Dec 11, 2015, 08:24 AM
One more thing ... How do I get an object to activate even if Jazz has never been close enough to it? Example: Jazz never walked further to the left than X tile 32, but the enemy is at X tile 224. How do I get the enemy to activate already, without Jazz actually being any nearby?

Violet CLM
Dec 11, 2015, 09:19 AM
Seems to me the simplest way would be to place the object somewhere around X tile 32, but have it reposition itself immediately upon creation. Alternatively, I haven't tested this but it looks plausible:
jjOBJ@ ActivateEventAt(int xTile, int yTile) {
if (jjParameterGet(xTile, yTile, -1, 1) == 1) //event already activated
return null;
jjParameterSet(xTile, yTile, -1, 1, 1); //bit meaning that this event is active
return jjObjects[jjAddObject(jjEventGet(xTile, yTile), xTile * 32 + 15, yTile * 32 + 15, 0, CREATOR::LEVEL)]; //or it might be + 16 for the position offsets if you want to get it exactly right... I don't remember offhand
}
Either way, you'll want to make sure its <code>jjOBJ::deactivates</code> is <code>false</code>.

DennisKainz
Dec 11, 2015, 11:14 AM
There's a tinyish problem ...
The expression does nothing. AngelScript recognizes it as valid and all, but the inactive stays inactive.
I even made sure a specific item first and then all items do not deactivate, but nothing. It doesn't affect anything.
Then I tried to replace xTile and yTile with their actual values. Still nothing.
It didn't work as a stand alone, so I tried to inject it in onMain(), but it said "Expected ; Instead found @"
Then I tried to remove the upper path, the one who returns null, and only kept the other. Guess what? Nothing!
In the end, I tried to add the "else" line between the two paths. And still nothing!

Maybe I should get back to tileset making ...
I said MAYBE

Violet CLM
Dec 11, 2015, 03:33 PM
What numbers are you passing as arguments and what event is at that location?

DennisKainz
Dec 12, 2015, 12:15 AM
At first, I tried keeping "xTile" and "yTile", supposing they'd scan the whole level.
Then, I used the event location: 28, 7 (JCS). I tried to use as arguments both 28, 7 and 27, 6 (starting from 0).
And the event is a boll platform with a custom behavior used for moving it left and right, changing direction when it collides with a slide event, that I use as a sort of "Stop Platform"

Violet CLM
Dec 12, 2015, 10:32 AM
Okay I created a 256-by-64 level with a start position in the top left corner and a piece of seeker ammo in the bottom right area, at position 252,60. Then I gave it this complete script:
void onLevelLoad() {
jjObjectPresets[OBJECT::SEEKERAMMO3].behavior = MyObject;
jjObjectPresets[OBJECT::SEEKERAMMO3].deactivates = false;
}

void onLevelBegin() {
ActivateEventAt(252, 60);
}

void MyObject(jjOBJ@ obj) {
jjAlert("I am active!");
}

jjOBJ@ ActivateEventAt(int xTile, int yTile) {
if (jjParameterGet(xTile, yTile, -1, 1) == 1)
return null;
jjParameterSet(xTile, yTile, -1, 1, 1);
return jjObjects[jjAddObject(jjEventGet(xTile, yTile), xTile * 32 + 15, yTile * 32 + 15, 0, CREATOR::LEVEL)];
}
I started seeing the "I am active!' alert constantly and it did not shut up, even when I went over to where the event was placed and then went away again. So whatever you're doing wrong is not in the function I gave you.

Are you hosting the level in MP? (Though if you were, I'm not sure why you'd be bothering with this, since the object would be activated anyway.) Boll platforms don't appear in MP servers unless they're set to MP-only....

DennisKainz
Dec 12, 2015, 12:04 PM
My bad. I did use deactivates = false, but not with jjObjectPresets. Now it works flawlessly!

DennisKainz
Dec 14, 2015, 09:04 AM
There's a new problem ... (Warn me if double posting is not authorized. I don't know all the rules)
I wrote a script. It works flawlessly on my computer, but Blaze the Movie Fan says it's extremely laggy on his computer, so I'll post it and see if you can help me.
Hopefully I'll learn something new and useful!

uint shownText = 0;
bool textShift = false;
uint textShiftTotal = 0;
uint thunderCounter = 0;
uint debugger = 0;
uint killedDemons = 0;
uint wallFall = 0;
uint wallFall1 = 0;
uint wallFall2 = 0;
uint isSugarRush = 0;
bool justMorphed = false;

void onLevelLoad()
{
jjPalette.gradient(224, 192, 255, 0, 0, 0, 16, 8, 1);
jjPalette.gradient(192, 255, 224, 0, 0, 0, 24, 8, 1);
jjPalette.gradient(255, 255, 192, 0, 0, 0, 32, 8, 1);
jjPalette.gradient(255, 192, 255, 0, 0, 0, 40, 8, 1);
jjPalette.gradient(192, 255, 192, 0, 0, 0, 48, 8, 1);
jjPalette.gradient(255, 192, 224, 0, 0, 0, 58, 6, 1);
jjPalette.gradient(224, 224, 255, 0, 0, 0, 64, 8, 1);
jjPalette.gradient(255, 192, 192, 0, 0, 0, 72, 8, 1);
jjPalette.gradient(255, 224, 224, 0, 0, 0, 80, 8, 1);
jjPalette.gradient(192, 255, 224, 0, 0, 0, 88, 8, 1);
jjPalette.gradient(224, 192, 160, 0, 0, 0, 104, 12, 1);
jjPalette.gradient(16, 0, 16, 32, 0, 0, 176, 32, 1);
jjPalette.gradient(0, 0, 0, 0, 0, 0, 10, 1, 1);
jjPalette.apply();
jjUseLayer8Speeds = true;
jjTexturedBGTexture = TEXTURE::NORMAL;
p.lives = 5;
jjObjectPresets[OBJECT::BAT].energy = 5;
jjObjectPresets[OBJECT::DEMON].energy = 25;
jjObjectPresets[OBJECT::DOGGYDOGG].energy = 15;
jjObjectPresets[OBJECT::DRAGON].energy = 10;
jjObjectPresets[OBJECT::HELMUT].energy = 15;
jjObjectPresets[OBJECT::MONKEY].energy = 20;
jjObjectPresets[OBJECT::RAPIER].energy = 25;
jjObjectPresets[OBJECT::RAVEN].energy = 10;
jjObjectPresets[OBJECT::STANDMONKEY].energy = 25;
jjObjectPresets[OBJECT::BOLLPLATFORM].behavior = myPlatform;
jjObjectPresets[OBJECT::BOLLPLATFORM].deactivates = false;
jjObjectPresets[OBJECT::SPIKEBOLL].energy = 0;
jjObjectPresets[OBJECT::SPIKEPLATFORM].behavior = bruiser;
}

void onLevelReload()
{
jjPalette.gradient(224, 192, 255, 0, 0, 0, 16, 8, 1);
jjPalette.gradient(192, 255, 224, 0, 0, 0, 24, 8, 1);
jjPalette.gradient(255, 255, 192, 0, 0, 0, 32, 8, 1);
jjPalette.gradient(255, 192, 255, 0, 0, 0, 40, 8, 1);
jjPalette.gradient(192, 255, 192, 0, 0, 0, 48, 8, 1);
jjPalette.gradient(255, 192, 224, 0, 0, 0, 58, 6, 1);
jjPalette.gradient(224, 224, 255, 0, 0, 0, 64, 8, 1);
jjPalette.gradient(255, 192, 192, 0, 0, 0, 72, 8, 1);
jjPalette.gradient(255, 224, 224, 0, 0, 0, 80, 8, 1);
jjPalette.gradient(192, 255, 224, 0, 0, 0, 88, 8, 1);
jjPalette.gradient(224, 192, 160, 0, 0, 0, 104, 12, 1);
jjPalette.gradient(16, 0, 16, 32, 0, 0, 176, 32, 1);
jjPalette.gradient(0, 0, 0, 0, 0, 0, 10, 1, 1);
jjPalette.apply();
jjUseLayer8Speeds = true;
jjTexturedBGTexture = TEXTURE::NORMAL;
wallFall = 0;
wallFall1 = 0;
wallFall2 = 0;
}

void onLevelBegin()
{
p.xPos = 5.5 * 32;
p.yPos = 0;
p.xOrg = 5.5 * 32;
p.yOrg = 0;
ActivateEventAt(27, 6);
ActivateEventAt(32, 9);
}

jjOBJ@ ActivateEventAt(int xTile, int yTile) {
if (jjParameterGet(xTile, yTile, -1, 1) == 1)
return null;
jjParameterSet(xTile, yTile, -1, 1, 1);
return jjObjects[jjAddObject(jjEventGet(xTile, yTile), xTile * 32 + 15, yTile * 32 + 15, 0, CREATOR::LEVEL)];
}

void onMain()
{
if (textShift == true && textShiftTotal < 70)
textShiftTotal = textShiftTotal + 1;
if (textShift == false && textShiftTotal > 0)
textShiftTotal = textShiftTotal - 1;
if (jjRandom() & 3500 == 0)
thunderCounter = 16;
if (thunderCounter > 0)
thunderCounter = thunderCounter - 1;
jjPalette.gradient(16 - thunderCounter + (thunderCounter * 16), 0 + (thunderCounter * 16), 16 - thunderCounter + (thunderCounter * 16), 32, 0, 0, 176, 32, 1);
jjPalette.apply();
jjSetFadeColors(16 - thunderCounter + (thunderCounter * 16), 0 + (thunderCounter * 16), 16 - thunderCounter + (thunderCounter * 16));
if (killedDemons >= 1 && jjTriggers[0] == false)
jjSwitchTrigger(0);
if (wallFall > 0 && wallFall1 < 256)
wallFall1 = wallFall1 + 8;
if (wallFall1 == 256 && jjTriggers[30] == false)
jjSwitchTrigger(30);
if (wallFall > 1 && wallFall2 < 256)
wallFall2 = wallFall2 + 8;
if (wallFall2 == 256 && jjTriggers[31] == false)
jjSwitchTrigger(31);
if (killedDemons >= 5 && jjTriggers[5] == false)
jjSwitchTrigger(5);
if (p.health < 1)
{
textShift = false;
textShiftTotal = 0;
}
if (isSugarRush > 0)
isSugarRush = isSugarRush - 1;
}

void onPlayer()
{
if (p.yPos < 32 && p.ySpeed < 0)
p.yPos = 32;
if (p.food >= 1)
{
p.startSugarRush(1400);
isSugarRush = 1400;
p.food = 0;
}
if (p.health < 1)
isSugarRush = 0;
if (p.blink != 0 && isSugarRush < 1)
{
p.blink = 0;
p.invincibility = 0;
}
p.fastfire = 6;
if (isSugarRush == 0)
p.jumpStrength = -8.5;
if (isSugarRush > 0)
p.jumpStrength = -11.5;
if (p.yPos > 16 * 32 && p.health > 0)
{
p.health = 0;
p.kill();
}
for (int i = 1; i < jjObjectCount; i++)
{
jjOBJ@ o = jjObjects[i];
if (o.eventID == OBJECT::DEMON && o.state == STATE::KILL && o.justHit == 1)
killedDemons = killedDemons + 1;
}
p.cameraFreeze(p.xPos, 272, true, true);
}

void onPlayerInput(jjPLAYER@ p)
{
if (isSugarRush == 0)
p.keyRun = false;
if (p.health < 1)
{
p.keyDown = false;
p.keyFire = false;
p.keyJump = false;
p.keyLeft = false;
p.keyRight = false;
p.keySelect = false;
p.keyUp = false;
}
if (jjKey[0x4A] == true && p.charCurr == CHAR::SPAZ)
p.morphTo(CHAR::JAZZ, true);
if (jjKey[0x53] == true && p.charCurr == CHAR::JAZZ)
p.morphTo(CHAR::SPAZ, true);
}

void onFunction0()
{
textShift = false;
}

void onFunction1()
{
textShift = true;
shownText = 1;
}

void onFunction2()
{
textShift = true;
shownText = 2;
}

void onFunction5()
{
textShift = true;
shownText = 5;
}

void onFunction20()
{
if (wallFall < 1)
wallFall = 1;
textShift = true;
shownText = 10;
}

void onFunction21()
{
if (wallFall < 2)
wallFall = 2;
}

void bruiser(jjOBJ@ bruise)
{
bruise.behave(BEHAVIOR::PLATFORM, true);
bruise.playerHandling = HANDLING::ENEMYBULLET;
bruise.animSpeed = 1;
if (bruise.xOrg % 32 == 15)
bruise.xOrg = bruise.xOrg - 16;
if (p.health < 1)
bruise.state = STATE::KILL;
if (p.yPos < bruise.yPos + 32 && wallFall > 0)
p.yPos = bruise.yPos + 32;
if (wallFall > 0 && bruise.yOrg < 14 * 32)
bruise.yOrg = bruise.yOrg + 0.5;
debugger = jjParameterGet(27, 6, -1, 1);
}

void myPlatform(jjOBJ@ myPlat)
{
myPlat.behave(BEHAVIOR::PLATFORM, true);
if (p.health < 1)
myPlat.state = STATE::KILL;
if (myPlat.yOrg % 32 == 15)
myPlat.yOrg = myPlat.yOrg - 12;
if (myPlat.var[0] == -35)
myPlat.xOrg = myPlat.xOrg + myPlat.var[1];
if (myPlat.var[0] == 35)
myPlat.xOrg = myPlat.xOrg - myPlat.var[1];
if (jjEventGet((myPlat.xOrg + 18) / 32, (myPlat.yOrg) / 32) == AREA::SLIDE && myPlat.var[0] < 35)
{
myPlat.var[0] = myPlat.var[0] + 1;
}
if (jjEventGet((myPlat.xOrg - 18) / 32, (myPlat.yOrg) / 32) == AREA::SLIDE && myPlat.var[0] > -35)
{
myPlat.var[0] = myPlat.var[0] - 1;
}
}

void onDrawLayer4(jjPLAYER@ p, jjCANVAS@ screen)
{
jjDrawTile(233 * 32, (7 * 32) + (jjSin(wallFall1 - 256) * 64), 268, TILE::ALLQUADRANTS, 4, 4, -1);
jjDrawTile(233 * 32, (8 * 32) + (jjSin(wallFall1 - 256) * 64), 216, TILE::ALLQUADRANTS, 4, 4, -1);
jjDrawTile(233 * 32, (9 * 32) + (jjSin(wallFall1 - 256) * 64), 216, TILE::ALLQUADRANTS, 4, 4, -1);
jjDrawTile(233 * 32, (10 * 32) + (jjSin(wallFall1 - 256) * 64), 216, TILE::ALLQUADRANTS, 4, 4, -1);
jjDrawTile(233 * 32, (11 * 32) + (jjSin(wallFall1 - 256) * 64), 216, TILE::ALLQUADRANTS, 4, 4, -1);
jjDrawTile(233 * 32, (12 * 32) + (jjSin(wallFall1 - 256) * 64), 216, TILE::ALLQUADRANTS, 4, 4, -1);
jjDrawTile(233 * 32, (13 * 32) + (jjSin(wallFall1 - 256) * 64), 216, TILE::ALLQUADRANTS, 4, 4, -1);
jjDrawTile(233 * 32, (14 * 32) + (jjSin(wallFall1 - 256) * 64), 268, TILE::ALLQUADRANTS, 4, 4, -1);
jjDrawTile(252 * 32, (7 * 32) + (jjSin(wallFall2 - 256) * 64), 268, TILE::ALLQUADRANTS, 4, 4, -1);
jjDrawTile(252 * 32, (8 * 32) + (jjSin(wallFall2 - 256) * 64), 216, TILE::ALLQUADRANTS, 4, 4, -1);
jjDrawTile(252 * 32, (9 * 32) + (jjSin(wallFall2 - 256) * 64), 216, TILE::ALLQUADRANTS, 4, 4, -1);
jjDrawTile(252 * 32, (10 * 32) + (jjSin(wallFall2 - 256) * 64), 216, TILE::ALLQUADRANTS, 4, 4, -1);
jjDrawTile(252 * 32, (11 * 32) + (jjSin(wallFall2 - 256) * 64), 216, TILE::ALLQUADRANTS, 4, 4, -1);
jjDrawTile(252 * 32, (12 * 32) + (jjSin(wallFall2 - 256) * 64), 216, TILE::ALLQUADRANTS, 4, 4, -1);
jjDrawTile(252 * 32, (13 * 32) + (jjSin(wallFall2 - 256) * 64), 216, TILE::ALLQUADRANTS, 4, 4, -1);
jjDrawTile(252 * 32, (14 * 32) + (jjSin(wallFall2 - 256) * 64), 268, TILE::ALLQUADRANTS, 4, 4, -1);
}

void onDrawLayer1(jjPLAYER@ p, jjCANVAS@ screen)
{
jjTEXTAPPEARANCE mytext;
mytext.at = STRING::SPECIALSIGN;
mytext.pipe = STRING::SPECIALSIGN;
mytext.align = STRING::CENTER;
if (shownText == 1)
screen.drawString(p.cameraX + 320, -20 + textShiftTotal, "'Welcome' to Hell!@If you complete the test,@you'll obtain a reward!", STRING::SMALL, mytext, 0);
if (shownText == 2)
screen.drawString(p.cameraX + 320, -20 + textShiftTotal, "Press J to turn into Jazz.@Press S to turn into Spaz.", STRING::SMALL, mytext, 0);
if (shownText == 5)
screen.drawString(p.cameraX + 320, -20 + textShiftTotal, "Kill 5 demons@to open this door.", STRING::SMALL, mytext, 0);
if (shownText == 10)
screen.drawString(p.cameraX + 320, -20 + textShiftTotal, "I lied!@No reward for you!@Just pain!", STRING::SMALL, mytext, 0);
screen.drawString(p.xPos, 64, "", STRING::SMALL, mytext, 0);
}

HERE'S THE LEVEL (https://copy.com/ZtYGe38jsuu4vWWh)

Violet CLM
Dec 14, 2015, 10:24 AM
I suspect the issue is that you're calling <code>jjPAL::apply</code> every single gametick, and it's one of the slowest operations in the game (for justifiable reasons). You should at least be able to only call it every second or third tick without much noticeable difference, and I'm fond of disabling it entirely when <code>jjLowDetail</code> is true.

Seren
Dec 14, 2015, 11:15 AM
More importantly there's no reason to call it at all when the palette doesn't change in the first place, which would be most of the time in your script. Also I don't think the bitwise AND operator & does what you think it does.

Slaz
Dec 16, 2015, 12:38 PM
I'm looking for 2 things that are probably simple and straightforward to most readers here:

1: I'd like to have snow from ANIM::SNOW appear through jjParticle, with original coloring (not loading palette entries from other tilesets).

2: I'd like to set a textured background on levelload, like TEXTURE::WTF, and keep the original textured BG color range from the tileset in use (so just swapping the texture).

This to polish up an old unreleased Xmas level I feel like releasing with proper modifications.

Violet CLM
Dec 16, 2015, 07:13 PM
In both cases you seem to want to be (permanently) recoloring images, so you'll need jjPIXELMAP. The first one is pretty much the same as the <code>RecolorRain</code> function from <strong>plusPixelMapEx</strong>, so look there, but work on ANIM::SNOW instead. For the second, I don't think they're covered in that level, but jjPIXELMAP does have both a constructor and a <code>makeTexture</code> method for working with textures specifically.

Slaz
Dec 17, 2015, 08:04 AM
Thanks! I looked there and found something for the snow. For the texture, I just loaded a default one from Plus and reset it's color range through jjPalette. I didn't even need a pixelmap there.

DennisKainz
Dec 21, 2015, 02:18 AM
I have this script:
void onLevelLoad() {
jjAnimSets[ANIM::CUSTOM[0]].load(0, "sausage.j2a");
jjObjectPresets[OBJECT::WEENIE].determineCurAnim(ANIM::CUSTOM[0], 0);
jjTileType[659] = 5;
jjTileType[669] = 5; // White hot lava.
jjPalette.gradient(128 + (jjP.cameraY / 16), 192 + (jjP.cameraY / 32), 255, 0 + (jjP.cameraY / 8), 32 + (jjP.cameraY / 12), 128, 144, 16, 1);
jjPalette.gradient(112 + (jjP.cameraY / 16), 64 + (jjP.cameraY / 24), 32 - (jjP.cameraY / 64), 0 + (jjP.cameraY / 12), 0, 0, 160, 16, 1);
jjPalette.gradient(255, 128, 0, 0 + (jjP.cameraY / 16), 0 + (jjP.cameraY / 256), 0, 208, 24, 1);
jjPalette.gradient(0 + (jjP.cameraY / 8), 192 - (jjP.cameraY / 16), 0, 0, 0, 0, 96, 8, 1);
jjPalette.gradient(0 + (jjP.cameraY / 8), 192 - (jjP.cameraY / 16), 0, 0, 0, 0, 128, 8, 1);
jjPalette.gradient(128 + (jjP.cameraY / 16), 64 + (jjP.cameraY / 32), 0, 0 + (jjP.cameraY / 16), 0, 0, 176, 32, 1);
jjPalette.gradient(192 + (jjP.cameraY / 32), 128 - (jjP.cameraY / 32), 64 - (jjP.cameraY / 32), 0 + (jjP.cameraY / 32), 0, 0, 120, 8, 1);
jjPalette.gradient(128 + (jjP.cameraY / 32), 64 - (jjP.cameraY / 32), 0, 0 + (jjP.cameraY / 32), 0, 0, 136, 8, 1);
jjPalette.gradient(192 + (jjP.cameraY / 64), 128 - (jjP.cameraY / 64), 32, 0, 0, 0, 104, 8, 1);
jjPalette.apply();
}

void onLevelReload() {
jjPalette.gradient(128 + (jjP.cameraY / 16), 192 + (jjP.cameraY / 32), 255, 0 + (jjP.cameraY / 8), 32 + (jjP.cameraY / 12), 128, 144, 16, 1);
jjPalette.gradient(112 + (jjP.cameraY / 16), 64 + (jjP.cameraY / 24), 32 - (jjP.cameraY / 64), 0 + (jjP.cameraY / 12), 0, 0, 160, 16, 1);
jjPalette.gradient(255, 128, 0, 0 + (jjP.cameraY / 16), 0 + (jjP.cameraY / 256), 0, 208, 24, 1);
jjPalette.gradient(0 + (jjP.cameraY / 8), 192 - (jjP.cameraY / 16), 0, 0, 0, 0, 96, 8, 1);
jjPalette.gradient(0 + (jjP.cameraY / 8), 192 - (jjP.cameraY / 16), 0, 0, 0, 0, 128, 8, 1);
jjPalette.gradient(128 + (jjP.cameraY / 16), 64 + (jjP.cameraY / 32), 0, 0 + (jjP.cameraY / 16), 0, 0, 176, 32, 1);
jjPalette.gradient(192 + (jjP.cameraY / 32), 128 - (jjP.cameraY / 32), 64 - (jjP.cameraY / 32), 0 + (jjP.cameraY / 32), 0, 0, 120, 8, 1);
jjPalette.gradient(128 + (jjP.cameraY / 32), 64 - (jjP.cameraY / 32), 0, 0 + (jjP.cameraY / 32), 0, 0, 136, 8, 1);
jjPalette.gradient(192 + (jjP.cameraY / 64), 128 - (jjP.cameraY / 64), 32, 0, 0, 0, 104, 8, 1);
jjPalette.apply();
}

void onMain() {
jjUseLayer8Speeds = true; // The long awaited feature that changed my gaming experience!
jjSetFadeColors(200);
jjTexturedBGTexture = TEXTURE::WTF;
}

void onPlayer(jjPLAYER@ jjP) {
if (jjGameTicks % 7 == 6)
{
jjPalette.gradient(128 + (jjP.cameraY / 16), 192 + (jjP.cameraY / 32), 255, 0 + (jjP.cameraY / 8), 32 + (jjP.cameraY / 12), 128, 144, 16, 1);
jjPalette.gradient(112 + (jjP.cameraY / 16), 64 + (jjP.cameraY / 24), 32 - (jjP.cameraY / 64), 0 + (jjP.cameraY / 12), 0, 0, 160, 16, 1);
jjPalette.gradient(255, 128, 0, 0 + (jjP.cameraY / 16), 0 + (jjP.cameraY / 256), 0, 208, 24, 1);
jjPalette.gradient(0 + (jjP.cameraY / 8), 192 - (jjP.cameraY / 16), 0, 0, 0, 0, 96, 8, 1);
jjPalette.gradient(0 + (jjP.cameraY / 8), 192 - (jjP.cameraY / 16), 0, 0, 0, 0, 128, 8, 1);
jjPalette.gradient(128 + (jjP.cameraY / 16), 64 + (jjP.cameraY / 32), 0, 0 + (jjP.cameraY / 16), 0, 0, 176, 32, 1);
jjPalette.gradient(192 + (jjP.cameraY / 32), 128 - (jjP.cameraY / 32), 64 - (jjP.cameraY / 32), 0 + (jjP.cameraY / 32), 0, 0, 120, 8, 1);
jjPalette.gradient(128 + (jjP.cameraY / 32), 64 - (jjP.cameraY / 32), 0, 0 + (jjP.cameraY / 32), 0, 0, 136, 8, 1);
jjPalette.gradient(192 + (jjP.cameraY / 64), 128 - (jjP.cameraY / 64), 32, 0, 0, 0, 104, 8, 1);
jjPalette.apply(); // The hues depend on how close to the lava the player is.
}
if (jjGameState == GAME::OVERTIME)
jjMusicLoad("hurry_up.mod"); // Music changes along with overtime.
if (jjP.yPos > (62.5 * 32) - jjLayerYOffset[2]) {
jjP.xSpeed = 0;
jjP.ySpeed = 1;
}
jjTexturedBGFadePositionY = 0.55 - (jjP.cameraY / 16384);
jjPARTICLE@ lavaspecks = jjAddParticle(PARTICLE::SMOKE); // Creates fumes from the lava.
lavaspecks.xPos = -480 + jjP.xPos + (jjRandom() % 960);
lavaspecks.yPos = 63*32 - (jjRandom() % 256);
lavaspecks.ySpeed = -1;
jjPARTICLE@ raindrops = jjAddParticle(PARTICLE::RAIN); // Water drops from the ceiling.
raindrops.xPos = -480 + jjP.xPos + (jjRandom() % 960);
raindrops.yPos = 0 + (jjRandom() % 256);
raindrops.ySpeed = 5 + (jjRandom() % 5);
}

void onDrawLayer2(jjPLAYER@ jjP, jjCANVAS@ canvas) {
jjLayerYOffset[2] = jjSin(jjGameTicks) * 16; // Lava moving up and down.
}

void onDrawLayer7(jjPLAYER@ jjP, jjCANVAS@ screen)
{
jjPIXELMAP drawBigHills(0, 0, 6 * 32, 8 * 32, 7);
jjANIMFRAME@ bigHills = jjAnimFrames[jjAnimations[jjAnimSets[ANIM::SONICPLAT].firstAnim].firstFrame];
drawBigHills.save(bigHills); // Actually giving the game additional layers!!!
screen.drawResizedSprite((-5 * 32) - ((jjP.cameraX * 0.0625) % (9 * 32)), (-1 * 32) - (jjP.cameraY * 0.015625), ANIM::SONICPLAT, 0, 0, 1.5, 3, SPRITE::NORMAL, 0);
screen.drawResizedSprite((4 * 32) - ((jjP.cameraX * 0.0625) % (9 * 32)), (-1 * 32) - (jjP.cameraY * 0.015625), ANIM::SONICPLAT, 0, 0, 1.5, 3, SPRITE::NORMAL, 0);
screen.drawResizedSprite((13 * 32) - ((jjP.cameraX * 0.0625) % (9 * 32)), (-1 * 32) - (jjP.cameraY * 0.015625), ANIM::SONICPLAT, 0, 0, 1.5, 3, SPRITE::NORMAL, 0);
screen.drawResizedSprite((22 * 32) - ((jjP.cameraX * 0.0625) % (9 * 32)), (-1 * 32) - (jjP.cameraY * 0.015625), ANIM::SONICPLAT, 0, 0, 1.5, 3, SPRITE::NORMAL, 0);
screen.drawResizedSprite((31 * 32) - ((jjP.cameraX * 0.0625) % (9 * 32)), (-1 * 32) - (jjP.cameraY * 0.015625), ANIM::SONICPLAT, 0, 0, 1.5, 3, SPRITE::NORMAL, 0);
screen.drawResizedSprite((40 * 32) - ((jjP.cameraX * 0.0625) % (9 * 32)), (-1 * 32) - (jjP.cameraY * 0.015625), ANIM::SONICPLAT, 0, 0, 1.5, 3, SPRITE::NORMAL, 0);
screen.drawResizedSprite((-5 * 32) - ((jjP.cameraX * 0.1875) % (18 * 32)), (-3.5 * 32) - (jjP.cameraY * 0.0416666666666667), ANIM::SONICPLAT, 0, 0, 3, 6, SPRITE::NORMAL, 0);
screen.drawResizedSprite((13 * 32) - ((jjP.cameraX * 0.1875) % (18 * 32)), (-3.5 * 32) - (jjP.cameraY * 0.0416666666666667), ANIM::SONICPLAT, 0, 0, 3, 6, SPRITE::NORMAL, 0);
screen.drawResizedSprite((31 * 32) - ((jjP.cameraX * 0.1875) % (18 * 32)), (-3.5 * 32) - (jjP.cameraY * 0.0416666666666667), ANIM::SONICPLAT, 0, 0, 3, 6, SPRITE::NORMAL, 0);
screen.drawResizedSprite((49 * 32) - ((jjP.cameraX * 0.1875) % (18 * 32)), (-3.5 * 32) - (jjP.cameraY * 0.0416666666666667), ANIM::SONICPLAT, 0, 0, 3, 6, SPRITE::NORMAL, 0);
}
Essentially, I'm using Layer 7 as 3 different layers of hills, each with its X Speed and Y Speed, giving the level a total of 10 layers.
And yes, it is way too pixelated, but this is NOT the problem. The actual problem is:
It works fine on Single Player mode, but on Multiplayer, the following problems occur:
- The extra layers work, but are shifted far in the upper left corner (and 2 of their color indexes are incorrect)
- I get the error message "memAlloc() Amnesia error: Out of Memory" after 4 seconds, divided by the amount of players in the game.

And yes, it is important that it works fine on Multiplayer mode, since it's a Battle game.

Violet CLM
Dec 21, 2015, 08:27 AM
Try moving the first three lines of <code>onDrawLayer7</code> into <code>onLevelLoad</code>?

DennisKainz
Dec 21, 2015, 09:23 AM
My bad. I always forget to make my expressions one-timed.

I still have the problem of the background's location.
It seems that the calculation of the player's camera position is different in Multiplayer.
And now that I put the expressions into OnLevel Load, I can't see the hills at all in Multiplayer. And yet in Single Player they're always there!

Violet CLM
Dec 21, 2015, 09:39 AM
Again just guessing, but you're using <code>ANIM::SONICPLAT</code>, but I don't see any explicit calls to <code>jjOBJ::determineCurAnim</code> or <code>jjANIMSET::load</code>, the two ways of manually loading an animset. So I suspect you're loading the animations by placing one or more Sonic Platform events in the level... but those don't work in multiplayer unless they're set to MP-Only.

Alternatively, use <code>ANIM::CUSTOM[1]</code> instead (after an appropriate <code>allocate</code> method call), since it doesn't look like you're interested in Sonic Platforms <em>as</em> Sonic Platforms?

(None of the stuff you're doing in <code>onMain</code> needs to be done every gametick either, fwiw.)