PDA

View Full Version : AngelScript Requests & Help


Pages : 1 [2]

DennisKainz
Dec 21, 2015, 10:16 AM
All I had to do was set it to MP-Only? Great!

And yes, I definitely need to learn which expressions are one-time and which ones aren't.

EDIT: I did it! No more sonic platforms needed. The level now creates the background automatically.

Slaz
Dec 31, 2015, 07:06 AM
Sorry for being so terrible at programming, but is there some way of making a certain gun your default one?

Do I need to check if BLASTER is WEAPON::CURRENT on jjPLAYER and then change it on levelbegin?

Blaze The Movie Fan
Jan 9, 2016, 09:02 AM
AngelScript didn't exist when I left back in 2004, so it is a new thing to me. And I have a couple of question.


How does it work exactly?
Is there a special program I can use to make angelscript? Because I'm not good with doing code manually that's why I use the program Microsoft Expression to edit web pages for my website server.
What's the best way to make cutscenes with that program? I played RabbitCity and noticed that has a lot of cut scenes.

Stijn
Jan 9, 2016, 09:11 AM
1. http://www.jazz2online.com/jj2plus/plus-angelscript.html
2. Any text editor. You're going to have to write scripting code, there's no way around that. If you use Notepad++ there is a syntax highlighting module (http://www.jazz2online.com/downloads/7300/notepadplusplus-angelscript-language-support/) you can use.
3. There is no part of JJ2+'s AngelScript support specifically aimed at making cutscenes. You're probably best off reading the readme, seeing how other scripts do things (e.g. take a look at the RabbitCity scripts) and then ask specific questions in this thread.

luke11685
Jan 9, 2016, 10:41 AM
did you ever make jj1 levels in jj2 style?I hope I'm not spamming.Just one very request.

Violet CLM
Jan 9, 2016, 10:44 AM
Do you mean this?

luke11685
Jan 9, 2016, 11:09 AM
Yeah sure.Something more like level extension of flashback chapter from Jazz Jackrabbit 2 with more stages.

Violet CLM
Jan 9, 2016, 11:35 AM
Oh. Well, that doesn't have much of anything to do with Angelscript requests, but <a href="http://www.jazz2online.com/downloads/index.php?filetype=7&filesort=uploadTime&filesorttype=desc&filerating=&tag=remake">here are some tilesets you might be interested in.</a>

luke11685
Jan 9, 2016, 11:55 AM
Thanks ViolentCLM.Welll it's like recreating EarthBound Zero using 16-bit style,but it's jRPG.I think Jazz Jackrabbit 1 Creation Station is created to remake Jazz 1 maps to make them looking like in jazz 2 style.I mean widescreen in jazz 1 was 4:9 in jazz 2 it's 16:9.
http://www.jazz2online.com/downloads/jj1-level/

Stijn
Jan 9, 2016, 12:02 PM
please stop talking about stuff that's not angelscript

Blaze The Movie Fan
Jan 10, 2016, 01:07 PM
1. http://www.jazz2online.com/jj2plus/plus-angelscript.html
2. Any text editor. You're going to have to write scripting code, there's no way around that. If you use Notepad++ there is a syntax highlighting module (http://www.jazz2online.com/downloads/7300/notepadplusplus-angelscript-language-support/) you can use.
3. There is no part of JJ2+'s AngelScript support specifically aimed at making cutscenes. You're probably best off reading the readme, seeing how other scripts do things (e.g. take a look at the RabbitCity scripts) and then ask specific questions in this thread.

Thanks for the help.

Jungle Jackrabbit 2 will probably me the first levelpack where I use angelscript, it's likely not gonna be easy, and if I need help I will ask here.

Blaze The Movie Fan
Jan 11, 2016, 01:05 PM
Is it possible to make it look like Spaz/Jazz is talking to the cellphone? The reason I'm asking is because I'm gonna make Spaz/Jazz do just that at several points during my next levelpack.

Violet CLM
Jan 11, 2016, 01:38 PM
Yes. I have no idea how you would want that to look, but whatever you have in mind is almost certainly possible.

EDIT:
Sorry for being so terrible at programming, but is there some way of making a certain gun your default one?

Do I need to check if BLASTER is WEAPON::CURRENT on jjPLAYER and then change it on levelbegin?
I forgot about this question, sorry. The answer is yes and no... yes, there are ways to achieve this effect, but it's not a simple one-time setting like it intuitively feels it should be. Instead you're probably going to need to check the player every tick (<code>onPlayer</code>, presumably) and compare/set <code>jjPLAYER::currWeapon</code> based on whatever you think the right criteria are.

And <code>WEAPON::CURRENT</code> <em>looks</em> like it's what you want, but unfortunately it's not. It's just some random magic number like -36 or 173 or something which certain functions understand to mean "ignore this number and look at <code>jjPLAYER::currWeapon</code> instead." In fact, I'm not sure I'd endorse using it at <em>all</em>&mdash;it works in the cases that it works, but that requires you to keep track of which cases those are, and that's a quirk of the API instead of a quirk of JJ2.

XxMoNsTeRXM
Apr 22, 2016, 06:56 AM
In the new 5.2 plus update they were added privileges, but they don't work for me and I don't know why.
Here are the admin.ini settings:

[Admin.Settings]
Enabled=True
Password=somepassword
Spammers=false

[Admin.IPs]

[Admin.AllowedCommands]
r
c
k
start
stop
bluescore
redscore
greenscore
yellowscore
gamemode
coop
battle
ctf
treasure
dom
jb

[Admin.BlockedCommands]

[Admin.Privileges]
*:admin

And here is the script with which I test it:

bool pressed;

void onPlayer(jjPLAYER@ p) {
if (jjKey[0x5A] && !pressed) {
jjAlert(p.hasPrivilege("admin", jjScriptModuleID) + "");
}
pressed = jjKey[0x5A];
}

If I am logged in the "Admin" group, and press Z, it says false (which means that I don't have the privilege), but I added the privilege in Admin.Privileges.

Seren
Apr 22, 2016, 07:32 AM
Docs for hasPrivilege (file:///C:/Programs/Cpp/Projects/JJ2-Plus/documentation/plus-angelscript.html#jjplayer::hasPrivilege):
Because privileges are only known to the host, this function will always return false if called client-side.
Correct usage of privileges assumes a setup where messages (in form of chat or custom packets) are sent to the host, who can then use the privilege list to determine whether they are valid requests.

On a side note, the privilege <code>*:admin</code> can be shortened to just <code>admin</code> for convenience.

XxMoNsTeRXM
Apr 22, 2016, 08:48 AM
ah, ok

AvalancheMaster
Jul 13, 2016, 09:13 AM
How do I address the banana of the monkey enemy? I want to make the monkey throw the regular food banana, which bounces off masked tiles, and explodes after 2 seconds, throwing off three smaller bananas (kind of like the banana bomb in Worms World Party).

Also, is it possible to use SPRITE::PLAYER in any way so that the darker fur on the animal is shifted to white? Or do I have to find a workaround this?

EDIT: never mind the last part. I got the colors correctly; still struggling to address the banana.

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

Violet CLM
Jul 13, 2016, 05:43 PM
What I would do is search for objects whose behavior is <code>BEHAVIOR::MONKEYBULLET</code> and assign them a new behavior in your script that does the things you want it to do.

AvalancheMaster
Jul 13, 2016, 06:04 PM
So I can change existing behavior, not only behavior of objects?

I thought the only thing I could do is search for existing objects, and assign a new behavior to them. I thought this would mean re-creating the monkey behavior from scratch.

EDIT: To expand upon my question, MONKEYBULLET is a behavior without an object. I think the easiest way would be to create a new object, monkeyBanana, which will, in turn, when exploding, create three instances of MONKEYBULLET. Am I able to replace behavior with object?

Violet CLM
Jul 13, 2016, 07:00 PM
Objects whose behavior is BEHAVIOR::MONKEY will create objects whose behavior is BEHAVIOR::MONKEYBULLET. You can in turn do a loop over existing objects, find the ones whose behavior is BEHAVIOR::MONKEYBULLET, and change their behaviors to something else.

It's also possible to recreate BEHAVIOR::MONKEY, either completely or just the tick in which it throws a banana, but that would be more work.

AvalancheMaster
Jul 13, 2016, 07:05 PM
So, for example, I can replace all instances of BEHAVIOR::MONKEYBULLET with BEHAVIOR:WITCHBULLET.

But if I want BEHAVIOR::MONKEYBULLET to be changed by a new behavior, which creates an instance of BEHAVIOR::MONKEYBULLET, I believe that will be problematic.

Correct?

Violet CLM
Jul 13, 2016, 07:20 PM
You could replace instances of BEHAVIOR::MONKEYBULLET with a custom behavior that creates instances of (objects using ) a <em>different</em> custom behavior that calls <code>behave(BEHAVIOR::MONKEYBULLET)</code>

AvalancheMaster
Jul 13, 2016, 08:40 PM
Maybe I don't understand what you mean.

So, I have placed various MONKEY and STANDMONKEY enemies in my level. I want to modify the behavior of their MONKEYBULLETs. The new behavior will include in itself BEHAVIOR::MONKEYBULLET.

For me to create this, I will need to recreate the MONKEY behavior, correct?

Violet CLM
Jul 13, 2016, 09:56 PM
void onMain() {
for (int i = 1; i < jjObjectCount; ++i) {
jjOBJ@ obj = jjObjects[i];
if (obj.behavior == BEHAVIOR::MONKEYBULLET)
obj.behavior = BananaMaker;
}
}
void BananaMaker(jjOBJ@ obj) {
//bounce off walls and stuff, then eventually:
jjAddObject(OBJECT::BULLET, obj.xPos, obj.yPos, obj.objectID, OBJECT::CREATOR, function(obj){ obj.behave(BEHAVIOR::MONKEYBULLET); });
}
Something like that. Yes, you could recreate the monkey behavior and skip over this stuff, but the above feels like less work for nearly the same effect.

AvalancheMaster
Jul 14, 2016, 12:24 AM
Wouldn't that cause the new object to spawn itself, since we are replacing all instances of BEHAVIOR:: MONKEYBULLET?

Violet CLM
Jul 14, 2016, 07:07 AM
No, that is and continues to be the point of <code>jjOBJ::behave</code>

Exploder
Jul 21, 2016, 05:56 AM
Sorry if this is a stupid question, is it possible to set an enemy monster's team?

Example of what I mean: Making a turtle on the blue team (Cannot be attacked by blue players and doesn't hurt them).

Violet CLM
Jul 21, 2016, 06:58 AM
Yeah, you'd want to write an <code>onObjectHit</code> that compared the <code>jjPLAYER::team</code> to a team variable specific to the enemy.

AvalancheMaster
Jul 21, 2016, 07:00 AM
Sorry if this is a stupid question, is it possible to set an enemy monster's team?

Example of what I mean: Making a turtle on the blue team (Cannot be attacked by blue players and doesn't hurt them).

A little off-topic, but that is one of the more original uses of AngelScript I've heard here. I think it would be possible to make the smoke rings of the Caterpillar affect only one team.

AvalancheMaster
Jul 23, 2016, 08:51 AM
Is there a way I can achieve this effect? I know for sure I'll have to use Pixelmapping, but I am stuck on the part where I need to define the player/object entering/leaving the area.

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

Violet CLM
Jul 23, 2016, 10:23 PM
I'm having trouble thinking of a sprite mode combination that would manage to draw all sprites in a single color but leave the background a different (translucent!) color, but I guess you could just do what PlusOJ does and grayscale the whole area:
jjDrawRectangle(TopLeft, TopRight, Width, Height, 0, SPRITE::BLEND_SATURATION, 255, 2);

AvalancheMaster
Jul 24, 2016, 12:27 AM
I know this is not an AngelScript functionality request thread, neither is this idea on the top of your priorities list, but would something like this be possible to implement:

SPRITE::TWOTONE, uint8, uint8

Where the first integer selects a color from the palette for the background (e.g. white), and the second integer selects a color from the palette for all the sprites and masked areas?

Violet CLM
Jul 24, 2016, 08:45 AM
Not really within the current framework, no.

MilloCz
Aug 21, 2016, 12:21 AM
Hi, I hope this is still running, I've got 2 questions;

1) I assume it's not possible to trick drawString into drawing text with multiple lines? (unless I make more drawString's each one for each line)

2) What's some fancy way to prevent player from moving? I know every frame I can set his xPos and yPos, but it doesn't look too good - how do I make him standing still (even when he's pressing arrows)?

MilloCz
Aug 21, 2016, 12:34 AM
3) I haven't yet quite figured out jjParameterGet, this code should tell me, how many of each gem is in the crate:

jjAlert("----------------------------------");
jjAlert(formatInt(jjParameterGet(26,19,4,0),"1"));
jjAlert(formatInt(jjParameterGet(26,19,4,4),"1"));
jjAlert(formatInt(jjParameterGet(26,19,4,8),"1"));
jjAlert(formatInt(jjParameterGet(26,19,4,12),"1"));
jjAlert("----------------------------------");

But it shows correct number only for the green, why?

It also doesn't seem to work properly on "Area ID", not giving area's ID.

EDIT: Meh, question 3 solved. sorry for spam

Seren
Aug 21, 2016, 05:41 AM
1) I assume it's not possible to trick drawString into drawing text with multiple lines? (unless I make more drawString's each one for each line)
Read up on <code>jjTEXTAPPEARANCE</code> (http://www.jazz2online.com/jj2plus/plus-angelscript.html#jjtextappearance). Properties of your interest are <code>at</code> (http://www.jazz2online.com/jj2plus/plus-angelscript.html#jjtextappearance::at) and <code>newline</code> (http://www.jazz2online.com/jj2plus/plus-angelscript.html#jjtextappearance::newline). See also the table in the constructor (http://www.jazz2online.com/jj2plus/plus-angelscript.html#jjtextappearance::jjTEXTAPPEARANC E), showing that you can in fact avoid <code>jjTEXTAPPEARANCE</code> usage altogether if your case allows using <code>STRING::SPIN</code>. There is currently no way to customize vertical spacing of text.
2) What's some fancy way to prevent player from moving? I know every frame I can set his xPos and yPos, but it doesn't look too good - how do I make him standing still (even when he's pressing arrows)?
Setting key input properties (http://www.jazz2online.com/jj2plus/plus-angelscript.html#jjplayer::keyDown) to false achieves this most easily. It may require to be done in <code>onPlayerInput</code>.

MilloCz
Aug 25, 2016, 07:44 AM
Thanks for reply, I will check that out.


Also, could you help me with cameraFreeze? when you are near x position 0, camera freezes and doesn't move out of level border - can I do this with cameraFreeze on other positions too?

My code:
if(p.xPos>260*32){

if(did_he_set_it == 0){

playerx = p.xPos;
did_he_set_it = 1;
}
p.cameraFreeze(playerx ,p.yPos, true, true);
}
else{

p.cameraUnfreeze(true);
did_he_set_it = 0;
}

The issue I'm having - it's laggy, the camera shakes a little when it's frozen, making it look pretty weird.. Any idea how do I overcome this? If I set isntant to false, then camera is kind of lazy and slow.

MilloCz
Aug 28, 2016, 01:15 PM
Also, please, mind helping me with classes? I am not programmer and I have actually very poor knowledge at programming. I have trouble making classes work. Why is this not working?

class Character
{
string name = "default";

Character(){}

}

Character Guy;

Guy.name = "Peter";

Violet CLM
Aug 28, 2016, 01:43 PM
That's not a class problem so much as the fact you can't run non-initialization code outside of functions like that. Either of these would work:
class Character {
string name = "default";
Character(){}
}

Character Guy;
void onLevelLoad() {
Guy.name = "Peter";
}
or
class Character {
string name = "default";
Character(){}
Character(string newName) {
name = newName;
}
}
Character Guy("Peter");

Tonycake
Feb 2, 2017, 06:05 AM
Hi everyone, I already know some simple code to adjust things in single player such as fur color and adding hearts etc, but one thing I have been thinking about is the example I found where one could play as Mario. Is there any code out there (a simple would be awesome since Im not pro on programming haha xD) that I can use to for example play as Mario instead of jazz in any single player level? Actually I just want to be able to play as any other character from a spritesheet rather than the one's already exist. Thanks alot for reading my question and if you in any way don't like anything about my question, maybe it's not written correctly or I go against any rule, I will learn from this and never do such thing again. Thanks alot !

Violet CLM
Feb 2, 2017, 09:44 AM
You're talking about Play as Mario. That's a mutator, which means it can run in any level, including single player levels, though unfortunately there's not a good built-in interface for making that happen right now. What you can do though is create a dummy level, let's say marioifier.j2l, and then write the following marioifier.j2as script:

void onLevelBegin() {
jjChat("/mutators mario on");
jjNxt("diam1.j2l", true, true);
}
(but replacing "diam1.j2l" with whatever other level filename you want to play.)

That's not a great solution, but until we make some more code changes it's probably the best you'll get. :# As for other characters from other spritesheets, pretty much the exact same code would be involved, based on <a href="https://www.jazz2online.com/snippets/136/replace-jazzs-animations/">my snippet</a>--the hard part is assembling the custom .j2a with the full roster of player sprites.

Tonycake
Feb 2, 2017, 02:58 PM
Thanks alot for your reply Violet! I will attempt to do that! Yes that's the one I ment, though I forgot it wasn't among the snippets section but in the level section, I should have linked it to my post ofcourse sorry for this haha xD thanks!

Tonycake
Feb 3, 2017, 03:21 AM
Wow! It did work out to play as mario on that level by activating the .mut to on :D It's really cool! Do you mind me asking one thing though, when you say "the hard part is assembling the custom -j2a with the full roaster of player sprites" do you mean that it's a bit difficult to put a sprite sheet together to make it work properly so that every picture works as one animation and having the exact required length between two pictures? By length I mean that if one animation is when the right leg is forward, and one animation is the left leg forward and that those two animation pictures doesn't "merge" into one so that you see both pictures at once? If this is the case, would it be possible to find a spritesheet that does work properly and kind of remake each picture with my own picture? Sorry if this is bad written I can rewrite it better if you want :) Thanks, btw I also saw this one - https://www.jazz2online.com/downloads/6648/sonic-jj2/ but the file extension .j2a is where the code for sonic animation is right?

Tonycake
Feb 3, 2017, 03:25 AM
By the way I forgot to say, I saw your example of .j2a, do you possibly have a spritesheet that fits into that example so that I could understand this part? Thanks again

EDIT: I will edit my post a bit because I found this thread: https://www.jazz2online.com/jcf/showthread.php?t=19856 Should I follow this in order to complete my question?

Violet CLM
Feb 3, 2017, 08:58 AM
So, we don't have a tool that either imports .j2a files <em>from</em> sprite sheets or exports .j2a files <em>to</em> sprite sheets. That's one of the logical options, along with using animated gifs, but the only tool we have&mdash;which you found and linked to&mdash;works with a bunch of single .png images spread across various folders. Here, for example, is how one of Spaz's animations is represented (as viewed in Windows Explorer):

<img src="http://i.imgur.com/uaLXKeR.png" />

It's absolutely possible to use that tool to create a new set of sprites&mdash;the Mario mutator did exactly that. I'm just saying it takes a while to do, particularly because player characters have over 75 distinct animations. Not only do you have to find all the sprites, you have to spend time getting them into the right format so JJ2 can understand which ones to draw at what times and where. If you are interested, I'd suggest starting with something simpler like replacing the sprites for a single enemy first, so you can be sure you know how the process works before you start doing it over and over.

(The Sonic one is a similar concept but replaces your <em>entire</em> default anims.j2a file, because that was the only option available at the time it was made, rather than replacing only individual animations or animation sets like is allowed by JJ2+.)

Tonycake
Feb 3, 2017, 10:21 AM
Thanks alot Violet! Good idea with starting with enemies im very interested in this and I will absolutely try it out! Thanks!

Darkhog
Feb 5, 2017, 05:18 AM
I'd really prefer if AngelScript would be deprecated in favor of Lua. Lua is much more mainstream scripting language, has easier to learn syntax and is faster (as in execution speed). Which means more people would be able to code their own stuff as Lua is used across the gaming/modding industry as the go-to scripting backend.

Lua is used in games such as:
- SMBX
- Gmod
- Prison Architect
- And many, many more (https://en.wikipedia.org/wiki/Category:Lua-scripted_video_games) (few are surprises on that list)

Of course AngelScript backend should remain in place, but only for the sake of compatibility with the older levels.

If news would go into the wild about JJ2 now supporting Lua, I'm sure this will bring more modders into it and maybe revitalize dying JJ2 level scene (yes, I call levels released by the same people over and over again, with no "new blood" dying).

Seren
Feb 5, 2017, 06:35 AM
That is not an AngelScript request.

Tonycake
Feb 5, 2017, 07:27 AM
Hi once again!

It works very good with the python file I downloaded to extract images and import them, I tried remake some of the mario.j2a and it worked which made me very happy! Since alot of images have a background 0,0,0 the "colorkey" must be set to make that transparent or something I guess because of all zeros at the pictures (don't take this serious because it's just a guess im actually a begginner xD) anyway, I might have missed something obvious and I read about the Anims.j2a including sound files and that you should not try this method with that one. But if I want to replace the heart symbol (lives), and would change this picture to something else, how would I import the Anims.j2a folder when im done? I mean I read this snippet https://www.jazz2online.com/snippets/136/replace-jazzs-animations/ is this the way to go? It says animation and im not sure if it means ONLY character animations or pictures aswell, if I missed something obvious im sorry for this, I will try to find the answer on internet or here meanwhile waiting for someone to tell me, thanks alot for every help I have recieved im glad!

EDIT: forget the 0,0,0 theory the numbers were explained in the first post how can I miss this

2nd EDIT: I forgot to mention, I understand the difference between the sonic.j2a and mario.j2a, I opened both of them so now I understand this clearer

3rd EDIT: I also thought that since you don't write "ANIM::LIVES" or something similar like you do "ANIM::JAZZ", my guess is the sonic way is the way to go since it alter the whole folder like Violet told me earlier, because the snippet Violet made "Replace Jazz's Animation" alter the main character that you play as right? Thanks, when I understood this I will stop asking so much haha xD thanks

4th EDIT: https://www.jazz2online.com/downloads/info.php?levelID=4041 :O :D must be it right

ABSOLUTELY LAST EDIT: I can edit Anims.j2a now with that program ! Im very happy for this thanks alot for every help and if someone else wants help with editing stuff in jazz jackrabbit 2 + send me a message and I help you! Thanks alot

Violet CLM
Feb 5, 2017, 12:36 PM
It looks like you made a lot of progress! :) Two clarificatory notes:

* When building a tileset, it's important that the first color in the palette be 0,0,0, but .j2a files do not care about that. You can use whatever palette you like.
* Jazz Sprite Dynamite can be used to edit anims.j2a, yes, but I wouldn't suggest doing that unless maybe if you truly intend to change a significant percent of the sprites in the game. Anims.j2a is an enormous file, in part because it includes almost all the game's sound effects, and it was not made to be distributed. Smaller, specific case .j2a files are to be preferred.

The reason there's no ANIM::LIVES is because unlike Jazz or Spaz, there's only a single animation for the 1up pickup, so it doesn't need its own animset. It's in the ANIM::PICKUPS set instead. In fact, the 1up pickup is literally the subject of the examples provided in the jjANIMSET documentation (https://www.jazz2online.com/jj2plus/plus-angelscript.html#jjanimset).

So, assuming you've loaded an animation that you want to use for 1up pickups from a custom .j2a set, you'll want to write something like

jjObjectPresets[OBJECT::EXTRALIFE].curAnim = myAnimationID;

or

jjAnimations[jjObjectPresets[OBJECT::EXTRALIFE].curAnim] = jjAnimations[myAnimationID];

or

jjAnimations[jjAnimSets[ANIM::PICKUPS].firstAnim] = jjAnimations[myAnimationID];

Tonycake
Feb 5, 2017, 01:43 PM
Thanks alot for clarifying those two things I will definitely keep this information in mind! :D

Jelly Jam
May 22, 2017, 12:28 PM
Quite new to scripting and sorry if I miss something completely obvious, but take a look: http://imgur.com/a/ohkoE

How do i make this look like the far right side of the level without changing the width of my level in JCS? And since I'm planning to make something on the other side of the wall as well, how do i make it look like the far LEFT side of the level? Can i make it happen ingame by touching a text area?

(not entirely to the left or right though, 2 or 3 vertical rows of tiles could be visible)

EDIT: oh and i meant to say that i want to make it look like the far left just a bit later, that's why i mentioned the text area.

Violet CLM
May 22, 2017, 06:18 PM
If I understand you right, you're looking for <code>jjPLAYER::limitXScroll</code>. Or depending on circumstances you might not even need angelscript, just the Limit X Scroll event.

Jelly Jam
May 24, 2017, 07:46 AM
Well that worked!

Is there a way to change the player name color? Especialy without messing it all up if the player already has his/her name colored, thus changing into some other color. Can it be done even in CTF and its custom gamemodes? Without swapping teams, of course.

DoubleGJ
Aug 15, 2017, 01:16 PM
Thread revival!

I'm trying to make an enemy that periodically surrounds itself with a ring of hourglasses. The solution I came up with was to edit the Pizza event so that it's a gem ring with the event ID set to 90. The enemy would then spawn a pizza and constantly set its xPos and yPos to its own. However, I'm having trouble figuring out how to access the Gem Ring event value in the script. Here's what I have so far:

void onLevelLoad() {
jjObjectPresets[OBJECT::PIZZA].behavior = freezeRing;
}

void freezeRing(jjOBJ@ obj) {
obj.behavior = BEHAVIOR::GEMRING;
obj.eventID = 90;
obj.var[2] = 90;
obj.var[0] = 4;
obj.var[1] = 4;
}

Violet CLM
Aug 15, 2017, 08:55 PM
My instinct would be to create an OBJECT::GEMRING on top of an event that you know has the right parameters to produce a gem ring with hourglasses, rather than using a pizza.

DoubleGJ
Aug 16, 2017, 04:07 AM
Okay, that does indeed work when I spawn the event at onLevelLoad. I can't make the enemy spawn it, however, though on paper this looks like it should work:

void onLevelLoad() {

jjObjectPresets[OBJECT::BEE].behavior = testBee;
}

void testBee(jjOBJ@ bee) {
int freeze;

bee.behave(BEHAVIOR::BEE);

if (bee.state == STATE::START) {
freeze = jjAddObject(192, 50, 50, 0, CREATOR::OBJECT);

}

if (bee.state == STATE::FLY) {
jjObjects[freeze].xPos = bee.xPos;
jjObjects[freeze].yPos = bee.yPos;
}

if (bee.state == STATE::KILL) {
jjObjects[freeze].state = STATE::KILL;
}
}

Violet CLM
Aug 16, 2017, 08:01 AM
Three thoughts...
The very first time you call <code>bee.behave(BEHAVIOR::BEE);</code>, the state will stop being <code>STATE::START</code>, so <code>jjAddObject</code> won't get called. Move the <code>behave</code> line farther down.
<code>int freeze;</code> is a variable local to (and therefore reinitialized) each time the function is called, not a member property of an object that would persist over time. Replace <code>freeze</code> with <code>bee.special</code> or something like that.
While creating the gem ring, you might need to set its <code>jjOBJ::deactivates</code> to <code>false</code> so it doesn't go missing in the time between its being created and its starting to follow the bee around. (And then <code>bee.state == STATE::KILL</code> should be expanded to check for <code>STATE::DEACTIVATE</code> too.)

DoubleGJ
Aug 16, 2017, 09:27 AM
Great, it works! I don't really need #3 since this is going to be a boss fight, so the gem ring spawn point will always be nearby. Right now the last thing I'm trying to figure out is creating a new hourglass shield a while after the current one is destroyed by touching it. I can't really find what's wrong in the code, but for some reason it makes the bee create new rings regardless if it already has one or not:

void testBee(jjOBJ@ bee) {


if (bee.state == STATE::START || bee.counter == 255) {
bee.counter = 0;
bee.special = jjAddObject(192, 50, 50, 0, CREATOR::OBJECT);

}

bee.behave(BEHAVIOR::BEE);

if (bee.state == STATE::ATTACK || bee.state == STATE::FLY || bee.state == STATE::IDLE) {
jjObjects[bee.special].xPos = bee.xPos;
jjObjects[bee.special].yPos = bee.yPos;
if (jjObjects[bee.special].state == STATE::KILL) {
bee.counter++;
}
}

if (bee.state == STATE::KILL) {
jjObjects[bee.special].behavior = BEHAVIOR::EXPLOSION2;
}
}

Violet CLM
Aug 16, 2017, 10:54 AM
Well, there are a couple issues, but the one you're facing at the moment is that <code>BEHAVIOR::BEE</code> <em>also</em> increments <code>jjOBJ::counter</code>.

Jelly Jam
Sep 30, 2017, 11:08 AM
Can I somehow remove the lightning that appears behind the rabbit when it's moving and the one around bullets? I want to use it in a level.

Darkhog
Dec 1, 2017, 11:25 AM
Is there a way to keep custom data between levels? I'm thinking about making a central hub level where you can unlock paths and stuff by doing certain stuff in other levels and for that I need a way to keep some information when player moves between levels.

If that's not possible, treat it as a request.

Violet CLM
Dec 1, 2017, 04:36 PM
The most intuitive way is to save the data to disk using jjSTREAM, which is effectively what JJ2 does when you enter a secret level like Gargoyle's Lair. Alternatively you can abuse JJ2 a little by storing values in the properties of higher-numbered players that never get erased, like <code>jjPlayers[31].score</code> or whatever.

PurpleJazz
Dec 1, 2017, 04:57 PM
Can I somehow remove the lightning that appears behind the rabbit when it's moving and the one around bullets? I want to use it in a level.

OK so this doesn't remove the light trail created by running players (although non-local players don't see this anyway), but does remove the light the player emits normally and removes bullet lighting (except for the light produced by weapon explosions).


void onLevelLoad() {
for (int eventID = OBJECT::BLASTERBULLET; eventID <= OBJECT::ELECTROBULLETPU; ++eventID) {
jjObjectPresets[eventID].lightType = LIGHT::NONE;
}
}

void onPlayer(jjPLAYER@ play) {
play.lightType = LIGHT::NONE;
}

DoubleGJ
Dec 1, 2017, 07:47 PM
The most intuitive way is to save the data to disk using jjSTREAM, which is effectively what JJ2 does when you enter a secret level like Gargoyle's Lair. Alternatively you can abuse JJ2 a little by storing values in the properties of higher-numbered players that never get erased, like <code>jjPlayers[31].score</code> or whatever.
Keep in mind this will all work only in a single play-through, as there is currently no means to store AngelScript data in a save file. A workaround for your needs might be to provide necessary data values as soon as you load a non-hub level.

Darkhog
Dec 2, 2017, 07:25 AM
Keep in mind this will all work only in a single play-through, as there is currently no means to store AngelScript data in a save file. A workaround for your needs might be to provide necessary data values as soon as you load a non-hub level.

I see. Though I think ability to use disk I/O in AngelScript would solve the issue. And I want it to be a single playthrough deal anyway.

Slaz
Dec 8, 2017, 12:48 AM
Hey there,

I've imported some tiles to my level through jjTilesFromTileset to use in background layers. They generally look good with the native palette, but noticed there's 1 crucial color that looks ugly and corresponds to the darkest color used in the native ground tiles. So either the background will look partly ugly or the darkest color of the layer4 ground will.

You know I suck at scripting so the answer may be obvious, but is there some way to recolor or swap palette entries to one or more specific tiles by their ID? None of my jjPal fiddling seemed to work.

Any example or tip will be highly appreciated!

Seren
Dec 8, 2017, 01:30 AM
<code>jjTilesFromTileset</code> (https://www.jazz2online.com/jj2plus/plus-angelscript.html#jjTilesFromTileset) accepts an extra parameter for that very purpose, named <code>paletteColorMapping</code>. You want most colors to be mapped to their current color (<code>paletteColorMapping[i] == i</code>), and those that look wrong to be mapped to something else.

If you find that it's more complicated than that, and some colors should be replaced with one color in one context and another in another context, <code>jjPIXELMAP</code> (https://www.jazz2online.com/jj2plus/plus-angelscript.html#jjpixelmap) is there to give you a helping hand. The documentation offers an example that already does something quite similar.

Slaz
Dec 10, 2017, 03:39 PM
You want most colors to be mapped to their current color (<code>paletteColorMapping[i] == i</code>), and those that look wrong to be mapped to something else.

I somehow overlooked that parameter and had it set to null without questioning myself.. Thanks! (y)

AvalancheMaster
Jan 6, 2018, 07:13 AM
Question time!

I want to combine the Slide event in my level with Steady Light. I'm using Mez03, and I want the neon-tube-like animated platforms to light up in the dark. So far I have no idea how to accomplish that.

Also, while on the same topic, is there a way to change the "Illuminate Surroundings" parameter to act as a steady light, rather than Flickering?

PurpleJazz
Jan 6, 2018, 08:23 AM
Question time!

I want to combine the Slide event in my level with Steady Light. I'm using Mez03, and I want the neon-tube-like animated platforms to light up in the dark. So far I have no idea how to accomplish that.

Also, while on the same topic, is there a way to change the "Illuminate Surroundings" parameter to act as a steady light, rather than Flickering?

I assume this is the only time you're using the Slide event? If that's the case, try the following script:

void onLevelBegin() {
for (int x = 0; x < jjLayerWidth[4]; x++) {
for (int y = 0; y < jjLayerHeight[4]; y++) {
if (jjEventGet(x,y) == AREA::SLIDE) {
jjOBJ@ o = jjObjects[jjAddObject(OBJECT::STEADYLIGHT, (x*32)+16, (y*32)+16)]; //lights go in the middle of tiles
o.light = 20;
o.lightType = 3;
}
}
}
}

Again, assuming there's consistency in the objects you're using illuminate surroundings on, you can set their light parameter to 20 and lightType to 3 to achieve the same result as above.

AvalancheMaster
Jan 6, 2018, 09:12 AM
That doesn't seem to do the job. Also, doesn't lightType use names?

Violet CLM
Jan 6, 2018, 09:33 AM
I'm guessing yours is a single player level and PJ is writing code for a multiplayer level (or at least testing it in a single screen). Try <code>o.deactivates = false;</code>?

AvalancheMaster
Jan 6, 2018, 09:41 AM
Single Player indeed. I included that line, but it still doesn't seem to work.

PurpleJazz
Jan 6, 2018, 10:38 AM
Single Player indeed. I included that line, but it still doesn't seem to work.

My bad; I overlooked the fact that your code was probably intended for SP and forgot to accommodate it accordingly.

The following script has been tested and works perfectly for me, so if this still doesn't work it means that there may be an error elsewhere in your script.

void onLevelBegin() {
for (int x = 0; x < jjLayerWidth[4]; x++) {
for (int y = 0; y < jjLayerHeight[4]; y++) {
if (jjEventGet(x,y) == AREA::SLIDE) {
jjOBJ@ o = jjObjects[jjAddObject(OBJECT::STEADYLIGHT, (x*32)+16, (y*32)+16)]; //add in middle of tiles
o.light = 20;
o.lightType = 3;
o.deactivates = false;
}
}
}
}

void onLevelReload() {
onLevelBegin(); //add lights again after death
}

AvalancheMaster
Jan 7, 2018, 12:46 PM
Thanks, that worked!

I'm also trying to make those areas one-way, as well as slide. Is there any way to do this?

So far any attempt to achieve this has resulted either in Slide-only, or One-way-only tiles, depending on the ordering of the code.
void onLevelBegin() {
for (int x = 0; x < jjLayerWidth[4]; x++) {
for (int y = 0; y < jjLayerHeight[4]; y++) {
if (jjEventGet(x,y) == AREA::SLIDE) {
jjOBJ@ xenonlight = jjObjects[jjAddObject(OBJECT::STEADYLIGHT, (x*32)+16, (y*32)+16)]; //add in middle of tiles
xenonlight.light = 20;
xenonlight.lightType = 3;
xenonlight.deactivates = false;
jjEventSet(x, y, AREA::ONEWAY);
jjEventSet(x, y, AREA::SLIDE);
}
}
}

Also, I am wondering if there is a way to force an animation on a specific frame, depending on player's location. Because my idea is somewhat complicated, let me try to provide an example:

If you have a 10-frame animation, with frames a[1], a[2], a[3], a[4], a[5] ... a[9], a[10], instead of using speed to control the animation, you are using player's position. As the player moves in a positive direction (x and y get bigger), the frames move in chronological order. As the player moves in a negative direction (x and y get smaller), the animation runs in reverse.

When the player stops moving, the animation also stops.

This should apply to all layers, so an animation is the only feasible way I can imagine implementing this.

I want to try to implement faux reflections in a tileset, that's the whole idea behind my question.

happygreenfrog
Jan 22, 2018, 07:11 AM
So, I'm trying to code a custom boss that summons a bunch of enemies, including summoning low HP bosses as enemies, but I've run into an issue: I'm having a hard time making things immune to (or at least not 1HKO'd by) Spaz's kick and Jazz's uppercut. Setting things to use playerHandling mode HANDLING::SPECIAL "works"... but also removes non-bullet collision detection for most enemies and the main boss (the latter would actually be a good thing if it was consistent, since I don't want it to be hurt by anything other than time passing anyways, but it's too inconsistent to be useful). It also has an issue where setting the bosses to have that collision mode means they beat the level when killed, when you're only supposed to win the level by letting the main boss run out of HP. Basically, it's supposed to be a survival challenge.

Here's the full script for the level as of now, including an attempt at a work-around for the issue where killing bosses clears the level (the work-around works, but only about half the time for some reason):
#include "MLLE-Include-1.4.asc"
const bool MLLESetupSuccessful = MLLE::Setup();
#pragma require "Tube.j2t"
#pragma require "Medivo.j2t"
#pragma require "hgfCow-MLLE-Data-1.j2l"
#pragma require "Carrot1.j2t"
#pragma require "hgfCow.j2l"

//a special thanks to Sir Ementaler and Violet CLM for their assistance with writing the script!

void onLevelLoad() {
jjObjectPresets[OBJECT::DEVILDEVAN].behavior = cowBoss;
jjObjectPresets[OBJECT::DEVILDEVAN].isFreezable = false;
jjObjectPresets[OBJECT::DEVILDEVAN].playerHandling = HANDLING::SPECIAL;
jjObjectPresets[OBJECT::DEVILDEVAN].scriptedCollisions = true;
jjObjectPresets[OBJECT::DEVILDEVAN].energy = 50;
jjObjectPresets[OBJECT::DEVILDEVAN].bulletHandling = HANDLING::DESTROYBULLET;

jjObjectPresets[OBJECT::BILSY].bulletHandling = HANDLING::HURTBYBULLET;
jjObjectPresets[OBJECT::BILSY].playerHandling = HANDLING::ENEMY;
jjObjectPresets[OBJECT::BILSY].energy = 14;
jjObjectPresets[OBJECT::BUBBA].bulletHandling = HANDLING::HURTBYBULLET;
jjObjectPresets[OBJECT::BUBBA].playerHandling = HANDLING::ENEMY;
jjObjectPresets[OBJECT::BUBBA].energy = 5+(jjDifficulty*4);
jjObjectPresets[OBJECT::TUFBOSS].bulletHandling = HANDLING::HURTBYBULLET;
jjObjectPresets[OBJECT::TUFBOSS].playerHandling = HANDLING::ENEMY;
jjObjectPresets[OBJECT::TUFBOSS].energy = 7+(jjDifficulty*4);
jjObjectPresets[OBJECT::BOLLY].bulletHandling = HANDLING::HURTBYBULLET;
jjObjectPresets[OBJECT::BOLLY].playerHandling = HANDLING::SPECIAL;
jjObjectPresets[OBJECT::BOLLY].energy = 10;
jjObjectPresets[OBJECT::UTERUS].bulletHandling = HANDLING::HURTBYBULLET;
jjObjectPresets[OBJECT::UTERUS].playerHandling = HANDLING::ENEMY;
jjObjectPresets[OBJECT::UTERUS].energy = 10;
jjObjectPresets[OBJECT::ROBOT].bulletHandling = HANDLING::HURTBYBULLET;
jjObjectPresets[OBJECT::ROBOT].playerHandling = HANDLING::ENEMY;
jjObjectPresets[OBJECT::ROBOT].energy = 30;

//just a thing I borrowed from plusPixelMapEx
jjANIMATION@ anim = jjAnimations[jjObjectPresets[OBJECT::DEVILDEVAN].curAnim];
anim.frameCount = 1;
jjANIMFRAME@ frame = jjAnimFrames[anim.firstFrame];
jjPIXELMAP kingCow(459*32, 3*32, 6*32, 7*32, 4);
kingCow.save(frame);
frame.hotSpotX = -frame.width / 2;
frame.hotSpotY = -frame.height / 2;
}

void onLevelBegin(){
//make sure the main song reloads after encountering the boss
jjMusicLoad("Meatball Parade.ogg");
}

//int rPart(float x,float y) { // render a part of Devan Force
// jjDrawSprite(x, y, ANIM::BIGROCK, 0, 0, 0);
//void jjDrawSprite(x, y, uint8 (ANIM::BIGROCK), uint8 (0), uint8 (0), int direction = 0, SPRITE::Mode mode = SPRITE::NORMAL, int param = 0, int8 layerZ = 4, uint8 layerXY = 4, int8 playerID = -1)
// return 0;
//}

void cowBoss(jjOBJ@ obj) {
switch (obj.state) {
case STATE::START:
//don't start boss until player has reached boss activation point
obj.state = STATE::DELAYEDSTART;
case STATE::DELAYEDSTART:
//loop players
for (int i = 0; i < jjLocalPlayerCount; ++i) {
jjPLAYER@ localPlayer = jjLocalPlayers[i];
if (localPlayer.bossActivated) {
localPlayer.boss = obj.objectID;
obj.state = STATE::START;
}
}
if (obj.state == STATE::START) {
//set object to be handled in a more normal way, since we're using Devil Devan as the "base"
obj.playerHandling = HANDLING::SPECIAL;
//load song
jjMusicLoad("dang.j2b");
//start boss
obj.state = STATE::ATTACK;
//initialize some important variables
obj.age = 60; //boss attack cooldown
obj.special = 0; //next attack the boss is going to use
obj.var[0] = 0; //move direction
obj.var[1] = 0; //reticle height
obj.var[2] = 10; //carrot delay
break;
}
return;
case STATE::KILL:
//start next stage
jjNxt(true, false);
case STATE::DEACTIVATE:
//reset boss
jjMusicLoad("Meatball Parade.ogg");
obj.deactivate();
break;
case STATE::ATTACK:
//draw boss
jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::NORMAL, 24);
//set cow as boss
for (int i = 0; i < jjLocalPlayerCount; ++i) {
jjPLAYER@ localPlayer = jjLocalPlayers[i];
if (localPlayer.bossActivated) {
localPlayer.boss = obj.objectID;
}
}

//just some old code I didn't completely remove
//for (int i = 1; i < jjObjectCount; i++){
// jjOBJ@ o = jjObjects[i];
// if (o.eventID == OBJECT::BOLLY){obj.var[0] == 1;}
// if (o.eventID == OBJECT::BUBBA){obj.var[0] == 1;}
// if (o.eventID == OBJECT::BILSY){obj.var[0] == 1;}
// if (o.eventID == OBJECT::TUFBOSS){obj.var[0] == 1;}
//}
//if (obj.var[0] == 0){}

//constantly cool down attack
obj.age -= 1;
//prepare summon
if (obj.age <= 0) {
//just some more old code I didn't completely remove
//if (obj.special == 1){jjAddObject(OBJECT::TUFBOSS, obj.xPos, obj.yPos+96);}
//if (obj.special == 2){jjAddObject(OBJECT::BUBBA, obj.xPos, obj.yPos);}
//if (obj.special == 2){jjAddObject(OBJECT::BOLLY, obj.xPos, obj.yPos);}
//if (obj.special == 2){jjAddObject(OBJECT::UTERUS, obj.xPos, obj.yPos);}
//if (obj.special == 3){jjAddObject(OBJECT::BILSY, obj.xPos, obj.yPos);}

//summon an enemy based on next attack chosen
if (obj.special == 0){jjObjects[jjAddObject(OBJECT::LIZARD, obj.xPos, obj.yPos)].playerHandling = HANDLING::SPECIAL;}
if (obj.special == 1){jjObjects[jjAddObject(OBJECT::BAT, obj.xPos, obj.yPos+120)].playerHandling = HANDLING::SPECIAL;}
if (obj.special == 2){jjObjects[jjAddObject(OBJECT::RAVEN, obj.xPos, obj.yPos+120)].playerHandling = HANDLING::SPECIAL;}
if (obj.special == 3){jjObjects[jjAddObject(OBJECT::FENCER, obj.xPos, obj.yPos)].playerHandling = HANDLING::SPECIAL;}
if (obj.special == 4){jjObjects[jjAddObject(OBJECT::BEE, obj.xPos, obj.yPos+120)].playerHandling = HANDLING::SPECIAL;}
if (obj.special == 5){jjObjects[jjAddObject(OBJECT::TUFBOSS, obj.xPos, obj.yPos+120)].playerHandling = HANDLING::SPECIAL;}
//if (obj.special == 6){jjObjects[jjAddObject(OBJECT::BEE, obj.xPos, obj.yPos+120)].playerHandling = HANDLING::SPECIAL;
// if(jjDifficulty >= 2){jjObjects[jjAddObject(OBJECT::BEE, obj.xPos+10, obj.yPos+120)].playerHandling = HANDLING::SPECIAL;
// jjObjects[jjAddObject(OBJECT::BEE, obj.xPos-10, obj.yPos+120)].playerHandling = HANDLING::SPECIAL;}}
if (obj.special == 6){jjObjects[jjAddObject(OBJECT::BEE, obj.xPos, obj.yPos+120)].playerHandling = HANDLING::SPECIAL;
if(jjDifficulty >= 2){jjObjects[jjAddObject(OBJECT::BEE, obj.xPos+10, obj.yPos+120)].playerHandling = HANDLING::SPECIAL;}}
if (obj.special == 7){jjObjects[jjAddObject(OBJECT::BUBBA, obj.xPos, obj.yPos)].playerHandling = HANDLING::SPECIAL;}
if (obj.special == 8){jjObjects[jjAddObject(OBJECT::LIZARD, obj.xPos, obj.yPos)].playerHandling = HANDLING::SPECIAL;
if(jjDifficulty >= 2){jjObjects[jjAddObject(OBJECT::LIZARD, obj.xPos+10, obj.yPos)].playerHandling = HANDLING::SPECIAL;
jjObjects[jjAddObject(OBJECT::LIZARD, obj.xPos-10, obj.yPos)].playerHandling = HANDLING::SPECIAL;}}
if (obj.special == 9 && jjDifficulty >= 2){jjObjects[jjAddObject(OBJECT::BILSY, obj.xPos, obj.yPos)].playerHandling = HANDLING::SPECIAL;}
if (obj.special == 9 && jjDifficulty == 1){jjObjects[jjAddObject(OBJECT::BAT, obj.xPos, obj.yPos+120)].playerHandling = HANDLING::SPECIAL;}
if (obj.special == 9 && jjDifficulty == 0){jjAddObject(OBJECT::CARROT, obj.xPos, obj.yPos+140);}
//if (obj.special == 10){jjObjects[jjAddObject(OBJECT::FENCER, obj.xPos, obj.yPos)]; if(jjDifficulty >= 2){jjObjects[jjAddObject(OBJECT::FENCER, obj.xPos+10, obj.yPos)]; jjObjects[jjAddObject(OBJECT::FENCER, obj.xPos-10, obj.yPos)];}}
if (obj.special == 10){jjObjects[jjAddObject(OBJECT::FENCER, obj.xPos, obj.yPos)].playerHandling = HANDLING::SPECIAL;
if(jjDifficulty >= 2){jjObjects[jjAddObject(OBJECT::FENCER, obj.xPos+10, obj.yPos)].playerHandling = HANDLING::SPECIAL;}}
//reset cooldown
obj.age = 180;
if (jjDifficulty == 2){obj.age = 150;}
if (jjDifficulty >= 3){obj.age = 120;}
//select next move
obj.special += 1;
//progress towards next carrot
obj.var[2] = obj.var[2]-1;
//hurt boss
obj.energy -= 1;
}
//loop attack pattern
if (obj.special >= 11){
obj.special = 5;
}
if (obj.var[2] <= 0){
if (jjDifficulty <= 2){jjAddObject(OBJECT::CARROT, obj.xPos, obj.yPos+140);}
if (jjDifficulty >= 3){jjAddObject(OBJECT::SEEKERAMMO3, obj.xPos, obj.yPos+140);}
obj.var[2] = 10;
}
//end boss
if (obj.energy <= 0){obj.bulletHandling = HANDLING::DESTROYBULLET; obj.state = STATE::KILL;}
//turn around
if (obj.xPos <= 495*32){obj.var[0]=1;}
if (obj.xPos >= 506*32){obj.var[0]=0;}
//move
if (obj.var[0] == 0){obj.xPos -=1;}
if (obj.var[0] == 1){obj.xPos +=1;}

//set reticle height
if (obj.special == 0 || obj.special == 3 || obj.special == 5 || obj.special == 7 || obj.special == 8 && obj.special != 9){obj.var[1]=230;}
if (obj.special == 1 || obj.special == 2 || obj.special == 4 || obj.special == 6){obj.var[1]=120;}
if (obj.special == 9 && jjDifficulty >= 2){obj.var[1]=230;}
if (obj.special == 9 && jjDifficulty == 1){obj.var[1]=120;}
if (obj.special == 9 && jjDifficulty == 0){obj.var[1]=9001;}
//display reticle
if (obj.age < 45 && obj.age % 6 <= 2){jjDrawSprite(obj.xPos, obj.yPos+obj.var[1], ANIM::PLUS_RETICLES, 2, 0, 0);}
//attempted work-around for killing bosses, this works about half the time
for (int i = 1; i < jjObjectCount; i++){
jjOBJ@ o = jjObjects[i];
if (o.state == STATE::DONE){jjDeleteObject(o.objectID);}
}
default:
//empty
}
}

Anybody have any ideas on how to fix the problems I've run into?

EDIT: Upon thinking about it further, I'm starting to think the easiest solution would be to disable Jazz's uppercut and Spaz's kick during the boss battle. Any easy way to go about doing that?

EDIT 2: I managed to figure it out on my own, never mind.

DennisKainz
Jan 31, 2019, 12:24 PM
I was going to upload a small mutator that allows players to grab ledges and lift themselves on them (as in Earthworm Jim and Commander Keen). However, there are a few problems...
Here's the script:
array<uint8> hang = {0, 0, 0, 0};
array<bool> hangLeft = {false, false, false, false};
array<bool> hangRight = {false, false, false, false};

void onMain() {
for (uint i = 0; i < 3; i++) {
jjPLAYER@ player = jjLocalPlayers[i];
if (player.isLocal) {
if (player.ySpeed > 0 && hangLeft[i] == false && hangRight[i] == false)
{
if (!jjMaskedPixel(player.xPos - 16, player.yPos - 16) && jjMaskedVLine(player.xPos - 16, player.yPos - 14, 8) && player.direction < 0)
{
hang[i] = 1;
hangLeft[i] = true;
}
if (!jjMaskedPixel(player.xPos + 16, player.yPos - 16) && jjMaskedVLine(player.xPos + 16, player.yPos - 14, 8) && player.direction > 0)
{
hang[i] = 1;
hangRight[i] = true;
}
}
if (hang[i] > 0)
{
player.invisibility = true;
hang[i] = hang[i] + 1;
if (hangLeft[i] == true)
{
player.xPos = player.xPos - 0.875;
jjDrawSprite(player.xPos, player.yPos, ANIM::JAZZ, 20, 0 + (hang[i] / 3), -1, SPRITE::NORMAL, 0);
}
if (hangRight[i] == true)
{
player.xPos = player.xPos + 0.875;
jjDrawSprite(player.xPos, player.yPos, ANIM::JAZZ, 20, 0 + (hang[i] / 3), 1, SPRITE::NORMAL, 0);
}
player.yPos = player.yPos - 1;
player.xSpeed = 0;
player.ySpeed = 0;
}
if (hang[i] > 30 && !jjMaskedPixel(player.xPos, player.yPos + 22))
{
player.invisibility = false;
hang[i] = 0;
hangLeft[i] = false;
hangRight[i] = false;
}
}
}
}
For now, I only made it for Jazz.
I can't find a way to determine the animation of the player itself, so I had to make the player invisible and draw the sprite in front of him instead. This gives the player the default skin color while he's hanging, which is wrong. I need a way to determine the player's current animation, rather than drawing upon him.
Oh, right! There also is this problem with the RABBIT::Anim where I simply can't find the one corresponding to Jazz grabbing the ledge. I had to use the numeral value, which probably differs between 1.23 and 1.24.

Violet CLM
Jan 31, 2019, 08:20 PM
That's a neat idea for a mutator!
I need a way to determine the player's current animation, rather than drawing upon him.
You can't do this yet, because the rabbit animation code is sufficiently complicated that we haven't come up with a good API for messing with it. But you should be able to solve your problem in the short-term by using SPRITE::PLAYER, player.playerID instead of SPRITE::NORMAL, 0.
Oh, right! There also is this problem with the RABBIT::Anim where I simply can't find the one corresponding to Jazz grabbing the ledge. I had to use the numeral value, which probably differs between 1.23 and 1.24.
The ledge-climbing animations were removed in 1.24, which is why they don't have a RABBIT::Anim entry (and why Lori doesn't have those animations at all).

headshot2018
Feb 7, 2019, 12:10 PM
hey, quick question.

is it possible to draw a custom scoreboard HUD in non-coop gametypes like CTF or battle?
i've been trying to define "bool onDrawScore()", but that seems to only alter the co-op score. is it possible?

thank you in advance.

Seren
Feb 7, 2019, 02:30 PM
At present, the score display in game modes other than SP and coop may not be altered, aside from drastic measures such as overwriting font sprites, which certainly wouldn't be limited in scope to said display and would probably quite negatively affect the game. Remaining HUD functions such as <code>onDrawAmmo</code> may still be used to display other information beside the usual.

headshot2018
Feb 7, 2019, 04:01 PM
oh... that's a bummer.

oh well, i'm gonna hold off on my project until it's possible to draw over CTF score, i guess.
thank you again.

chandie
Jan 28, 2020, 12:47 AM
I'd like to use a regular enemy as a boss. I don't intend to change his behavior. I only change his sprites with tiles or replace them with JJ1Enemies sometimes.

I tried creating a behavior for the enemy and implement the if code below but it doesn't work.

if ( boss.energy==0&&++boss.counter>2300)
jjEventSet(play.xPos / 32, play.yPos / 32, AREA::EOL);

Is there a practical way of putting a health bar and an automatic EOL event when his energy is 0?

I am pretty new at scripting btw. Treat me as a noobie :)

Seren
Jan 28, 2020, 06:25 AM
Is there a practical way of putting a health bar and an automatic EOL event when his energy is 0?
Hi! Awesome that you're learning JJ2+ scripting. The scripting documentation describes several entities that should help you.

A boss health bar is drawn for players if their bossActivated (https://docs.jj2.plus/plus-angelscript.html#jjplayer::bossActivated) is true and boss (https://docs.jj2.plus/plus-angelscript.html#jjplayer::boss) refers to an object by its ID (https://docs.jj2.plus/plus-angelscript.html#jjobj::objectID). There's also an accompanying activateBoss (https://docs.jj2.plus/plus-angelscript.html#jjplayer::activateBoss) method, or you could use the traditional Activate Boss event. See especially the documentation for boss (https://docs.jj2.plus/plus-angelscript.html#jjplayer::boss), as it describes how the health bar's size is determined.

Most JJ2 boss behaviors work the following way: the boss starts out inactive and its behavior has a loop over all players that checks if any active (https://docs.jj2.plus/plus-angelscript.html#jjplayer::isActive) player's bossActivated (https://docs.jj2.plus/plus-angelscript.html#jjplayer::bossActivated) is true. If it is, the boss changes its state (https://docs.jj2.plus/plus-angelscript.html#jjobj::state) to something else, indicating that it's now active. Then, whenever the boss is active, it runs a loop that sets all players' boss (https://docs.jj2.plus/plus-angelscript.html#jjplayer::boss) to itself. This results in the health bar being drawn.

When the boss is defeated and its energy (https://docs.jj2.plus/plus-angelscript.html#jjobj::energy) is 0, the game doesn't despawn it, and instead (much like you, it seems) uses its behavior as a countdown to end the level. First, when the counter (https://docs.jj2.plus/plus-angelscript.html#jjobj::counter) is 0, it might display some message much like showText (https://docs.jj2.plus/plus-angelscript.html#jjplayer::showText). Then it waits between 4 and 6.5 seconds before it proceeds to the next level, depending on whether the player is firing bullets, for some weird reason (maybe under the assumption that if they're firing, they're getting impatient? Either way it's currently a speedrun strat to keep shooting after defeating a boss). Your magic number of 2300 seems pretty big as, at 70 ticks per second, that corresponds to over half a minute. Your strategy of spawning an EOL event seems valid, but it's generally a better idea to call jjNxt (https://docs.jj2.plus/plus-angelscript.html#jjNxt) with default parameters.

To sum up the order of events in a typical boss fight:

The boss is inactive.
The player touches an Activate Boss event. This sets their bossActivated (https://docs.jj2.plus/plus-angelscript.html#jjplayer::bossActivated) to true.
The dormant boss detects that there's a player with an active boss fight so it wakes up.
The boss sets all players' boss (https://docs.jj2.plus/plus-angelscript.html#jjplayer::boss) property to itself. This lets the health bar know what size it should have.
Players defeat the boss. The boss behavior may display a text message.
After a few seconds, the boss behavior ends the current level.

Violet CLM
Jan 28, 2020, 07:57 AM
One possible additional consideration is your <code>boss.energy==0</code> condition. Several weapons do more than 1 damage, so it's easy for an enemy to end up with a negative energy number instead of exactly 0. (Some standard enemies/bosses check for this and immediately set energy to 0, others set it to -1, and probably others don't do anything at all.)

chandie
Jan 29, 2020, 03:41 AM
A boss health bar is drawn for players if their bossActivated is true and boss refers to an object by its ID. There's also an accompanying activateBoss method, or you could use the traditional Activate Boss event. See especially the documentation for boss, as it describes how the health bar's size is determined.
One possible additional consideration is your <code>boss.energy==0</code> condition. Several weapons do more than 1 damage, so it's easy for an enemy to end up with a negative energy number instead of exactly 0. (Some standard enemies/bosses check for this and immediately set energy to 0, others set it to -1, and probably others don't do anything at all.)

Thank you for the advices. :) I've managed to make the boss work. However the script stops working when I try to end the level automatically. I think what I've been doing wrong is not to figure where to implement the jjNXT. Here's my code. I've tried to create a JJ1 Turtle Goon Boss, like the one in Diamondus Secret.

#include "Jazz1Enemies v05.asc"
#include "Resize v11.asc"
#include "TrueColor v13.asc"
bool Boss=false;

void onLevelLoad() {
Jazz1::MakeEnemy(OBJECT::NORMTURTLE, Jazz1::Enemies::Diamondus_TurtleGoon, true);
jjObjectPresets[OBJECT::NORMTURTLE].behavior = NORMTURTBOSS;
jjObjectPresets[OBJECT::NORMTURTLE].energy = 100;
jjObjectPresets[OBJECT::NORMTURTLE].points = 200;
}

void onFunction0(jjPLAYER@ play) {
Boss=true;
play.boss=jjAddObject(OBJECT::NORMTURTLE, 37*32, 54*32);
}

void NORMTURTBOSS(jjOBJ@ boss) {
jjPLAYER@ play = jjLocalPlayers[0];
if (boss.energy==0&&++boss.counter>2300)
jjNxt(bool warp = false, bool fast = false);
}

Violet CLM
Jan 29, 2020, 04:42 PM
The main problem you're experiencing is this line: <code>jjNxt(bool warp = false, bool fast = false);</code> Those bits inside the parentheses are supposed to indicate the <em>default values</em> for those arguments, meaning that if you just type <code>jjNxt();</code> it'll be interpreted the same as if you had typed <code>jjNxt(false, false);</code>. Typing out the parameter names (and types) doesn't help.

The next thing that's going to bite you is when you write <code>jjObjectPresets[OBJECT::NORMTURTLE].behavior = NORMTURTBOSS;</code> you are getting rid of the previous behavior, which included code for moving the object, drawing the object, and handling player collision and bullet collision.

chandie
Jan 30, 2020, 04:21 AM
OK. Solved the problem. But sadly it doesn't work with JJ1 Enemies function. Because when I remove the JJ1Enemies function it works fine. It's main code probably considers it as a normal enemy and the counter does not start. So the level does not end. I tried removing the counter problem by trying to end the level when his energy=1 but it didn't work either. :(

Violet CLM
Feb 10, 2020, 11:18 PM
Very delayed response, but I don't think I can tell exactly what you're doing from your description. Troubleshooting is generally easiest in response to actual code, like in your previous post, preferably the minimum amount of code that demonstrates the problem in question. What does "works fine" look like in code? What does not removing the JJ1Enemies function look like in code?

chandie
Mar 6, 2020, 06:33 AM
And another delayed response from me :D
It's been a while and I didn't keep the code. However I've tried using Normal Turtle animations and a new behavior in order to make it work and it helped. Here's the thing:


bool boss=false;


void onLevelLoad() {

jjObjectPresets[OBJECT::PURPLEGEM].points = 2000;
jjObjectPresets[OBJECT::NORMTURTLE].behavior = TURTBOSS;
jjObjectPresets[OBJECT::NORMTURTLE].points = 5000;
jjObjectPresets[OBJECT::NORMTURTLE].energy = 50;
jjObjectPresets[OBJECT::NORMTURTLE].bulletHandling = HANDLING::HURTBYBULLET;
jjObjectPresets[OBJECT::NORMTURTLE].state = STATE::WALK;

}



void onFunction0(jjPLAYER@ play) {
play.activateBoss();
boss=true;
{play.boss=jjAddObject(OBJECT::NORMTURTLE, 38*32, 55*32);}
jjMusicLoad("boss.s3m");
play.activateBoss(true);

}


void TURTBOSS(jjOBJ@ boss) {

jjPLAYER@ play = jjLocalPlayers[0];


if ( boss.energy==0)
{
boss.counter==0;
boss.counter += 0;
boss.determineCurAnim(ANIM::TURTLE, 7);
boss.determineCurFrame();
boss.frameID = boss.counter/56;
jjDrawSpriteFromCurFrame(boss.xPos, boss.yPos, boss.curFrame, boss.direction, SPRITE::NORMAL);
++boss.counter;

if ( boss.energy==0&&++boss.counter>20)
jjEventSet(play.xPos / 32, play.yPos / 32, AREA::EOL);
}

if ((boss.xPos > play.xPos+3 || boss.xPos < play.xPos-3)&& boss.state != STATE::KILL)
{boss.direction = (play.xPos < boss.xPos) ? +1 : +1;}
else
{
boss.direction==1;}
if (boss.yPos < 54*32)
{boss.yPos = boss.yPos;}
if (boss.xPos > 24*32)
{boss.xPos = boss.xPos;}
switch (boss.state) {

case STATE::WALK:
boss.behave(BEHAVIOR::WALKINGENEMY);
{
if (boss.counter >= 180)
{boss.counter = 0; }

boss.counter++;
if (u==0||u==1)
{if (++boss.counter < 180){
boss.xSpeed= (1+1)*boss.direction;
boss.determineCurAnim(ANIM::TURTLE, 7);
if (boss.counter == 10){
jjSample(boss.xPos, boss.yPos, SOUND::INTRO_GREN3);}
if (boss.justHit == 0)
{jjDrawSpriteFromCurFrame(boss.xPos, boss.yPos, boss.curFrame, boss.direction, SPRITE::NORMAL);}
boss.determineCurFrame();
//boss.frameID = boss.counter/10;
}

break;



} }
case STATE::FREEZE:
if (boss.freeze > 0) {
boss.draw();
boss.freeze -= 4;
}
if (boss.freeze < 4) {
boss.unfreeze(0);
boss.state = boss.oldState;
}

break;
case STATE::KILL:
case STATE::DEACTIVATE:
boss.deactivate();
break;



}
//if (boss.justHit == 0)
//jjDrawSpriteFromCurFrame(boss.xPos, boss.yPos, boss.curFrame, boss.direction, SPRITE::NORMAL);
//else jjDrawSpriteFromCurFrame(boss.xPos, boss.yPos, boss.curFrame, boss.direction, SPRITE::SINGLECOLOR,15);
}

chandie
Mar 7, 2020, 10:40 PM
Have another question though. Is there a way to combine water level event with destruct scenery? I mean a shootable water level event like the ones in dreempipes.

Violet CLM
Mar 9, 2020, 10:55 PM
However I've tried using Normal Turtle animations and a new behavior in order to make it work and it helped.
Broadly speaking, it seems to be working, at least once I get rid of the <code>if (u==0||u==1)</code> line which I assume refers to a variable you didn't include in that snippet. You are running into an issue where killing it using a physical attack fails to cause the level to end, but <code>jObjectPresets[OBJECT::NORMTURTLE].playerHandling = HANDLING::ENEMY;</code> should fix that. Also you probably don't want <code>STATE::KILL</code> to call <code>boss.deactivate()</code>.
I mean a shootable water level event like the ones in dreempipes.
Sure... <a href="https://docs.jj2.plus/plus-angelscript.html#jjSetWaterLevel">jjSetWaterLevel</a> exists. You may need to figure out <a href="https://docs.jj2.plus/plus-angelscript.html#jjbehaviorinterface::onObjectHit">jjBEHAVIORINTERFACE and its onObjectHit method</a>, though, since I'm guessing you want the object to react only to being shot by bullets, not to being buttstomped.

chandie
Mar 10, 2020, 07:09 AM
You are running into an issue where killing it using a physical attack fails to cause the level to end, but <code>jObjectPresets[OBJECT::NORMTURTLE].playerHandling = HANDLING::ENEMY;</code> should fix that. Also you probably don't want <code>STATE::KILL</code> to call <code>boss.deactivate()</code>.

Thanks for the tips Violet. Yeah with playerHandling command EOL works with physical attack.


Sure... <a href="https://docs.jj2.plus/plus-angelscript.html#jjSetWaterLevel">jjSetWaterLevel</a> exists. You may need to figure out <a href="https://docs.jj2.plus/plus-angelscript.html#jjbehaviorinterface::onObjectHit">jjBEHAVIORINTERFACE and its onObjectHit method</a>, though, since I'm guessing you want the object to react only to being shot by bullets, not to being buttstomped.

I solved jjSetWaterLevel with switchtrigger. so it works fine with a trigger zone. but objecthit with bullet seems a little more complicated but I'll keep working on it. Yeah it shouldn't work by buttstomping.


And I have a one last question. I am trying to create a walking enemy from Frog animations. It works but the animation plays under the ground sprite. Here's the code:



void onLevelLoad() {

jjObjectPresets[OBJECT::LIZARD].behavior = Frog;
jjObjectPresets[OBJECT::LIZARD].bulletHandling = HANDLING::HURTBYBULLET;
jjObjectPresets[OBJECT::LIZARD].playerHandling = HANDLING::ENEMY;

}




void Frog(jjOBJ@ obj) {
obj.behave(BEHAVIOR::WALKINGENEMY, false);
obj.determineCurAnim(ANIM::FROG, 12);
obj.determineCurFrame();
obj.putOnGround(true);


jjDrawSpriteFromCurFrame(obj.xPos, obj.yPos, obj.curFrame, obj.direction, SPRITE::NORMAL, 0);


}



I've tried some other things like setting WALKINENEMY value to true but it didn't change anything. I've also try adding some negative values to obj.yPos in jjDrawSpriteFromCurFrame. It helps visually. But functionally the enemy is still under the ground. Any suggestions ar highly appreciated. Thank you.

Violet CLM
Mar 12, 2020, 04:55 PM
First off, you could simplify all that like this:
void onLevelLoad() {
jjObjectPresets[OBJECT::LIZARD].determineCurAnim(ANIM::FROG, jjIsTSF ? 12 : 11);
}

You're running into the problem that <code>BEHAVIOR::WALKINGENEMY</code> is one of the only parts of the game that cares about <a href="https://docs.jj2.plus/plus-angelscript.html#jjanimframe::coldSpotY">jjANIMFRAME::coldSpotY</a>, but the frog sprites are one of the only land-based animations that don't have that property defined. Walking enemies try to align their <code>hotSpotY</code> point to the surface of the ground they're on, but that number defaults to 0, which is the top of the sprite. Just move it upwards until it looks better:
jjANIMATION@ frogWalkAnim = jjAnimations[jjObjectPresets[OBJECT::LIZARD].curAnim];
for (uint i = 0; i < frogWalkAnim.frameCount; ++i)
jjAnimFrames[frogWalkAnim.firstFrame + i].coldSpotY = -25;

chandie
Mar 12, 2020, 11:04 PM
First off, you could simplify all that like this:
void onLevelLoad() {
jjObjectPresets[OBJECT::LIZARD].determineCurAnim(ANIM::FROG, jjIsTSF ? 12 : 11);
}

You're running into the problem that <code>BEHAVIOR::WALKINGENEMY</code> is one of the only parts of the game that cares about <a href="https://docs.jj2.plus/plus-angelscript.html#jjanimframe::coldSpotY">jjANIMFRAME::coldSpotY</a>, but the frog sprites are one of the only land-based animations that don't have that property defined. Walking enemies try to align their <code>hotSpotY</code> point to the surface of the ground they're on, but that number defaults to 0, which is the top of the sprite. Just move it upwards until it looks better:
jjANIMATION@ frogWalkAnim = jjAnimations[jjObjectPresets[OBJECT::LIZARD].curAnim];
for (uint i = 0; i < frogWalkAnim.frameCount; ++i)
jjAnimFrames[frogWalkAnim.firstFrame + i].coldSpotY = -25;

Solved. thanks a lot :)

chandie
Mar 19, 2020, 02:00 AM
I am trying to increase/decrease the player's x speed like this:
if(p.keyRight)
p.xSpeed = 20;

It works with void onPlayer but not in bool onObjectHit or void onFunction Any suggestions?

Violet CLM
Mar 21, 2020, 08:40 AM
There are a couple things you might be running into. One is that JJ2 is of course always changing the player's <code>xSpeed</code> on its own, so if you make a single short-term change, in response to something like one of the <code>onFunction#</code> hooks, then that change is not going to last very long before JJ2's normal speed handling takes over. But <code>onPlayer</code> works <em>constantly</em> instead of as a one-time thing, so naturally it's going to have more visible impact. The other is that <a href="https://docs.jj2.plus/plus-angelscript.html#p"><code>p</code> is deprecated</a> and may not (should not) work in all situations, and you should use the actual <code>jjPLAYER@</code> argument available to <code>onObjectHit</code> and <code>onFunction#</code> instead.

chandie
Mar 22, 2020, 10:11 PM
So even if I try with jjPLAYER I can’t make a constant speed change.

I could change the speed like this though, again with onPlayer.

if(play.xPos>27 && play.yPos>43)
if(play.keyRight) {
play.xSpeed = 10;
}
if(play.keyLeft) {
play.xSpeed = -10;
}
play.keyRun = true;
}

But that’s not the exact effect I want. I’d like to make a constant speed up (at least for ten seconds or so) regardless of the player pos

Violet CLM
Mar 23, 2020, 06:41 AM
Ah, okay, I see what you mean. Try something like this:
int SpeedUpUntil = 0;
void onPlayer(jjPLAYER@ play) {
if (SpeedUpUntil > jjGameTicks) {
//adjust player's xspeed and such in here
}
}
Then whenever you want to turn on the speed up effect, in an onObjectHit or whatever, set <code>SpeedUpUntil = jjGameTicks + 10 * 70;</code> where 10 is the number of seconds you want the effect to last.

(if you want to support cooperative, <code>SpeedUpUntil</code> should be an <code>array&lt;int&gt;</code> instead of a <code>int</code>.)

chandie
Mar 24, 2020, 03:20 AM
Worked like a charm. Thank you :)