[SP] Sendificate
Quote from FourthReaper on April 13, 2012, 1:09 pmHMW wrote:Deploying Aperture Science Propeller-operated head cooling decive in 3... 2... 1...
[spoiler]- Make an array of env_lasers and get a pointer to each laser's endpoint sprite at map load. (I know this works because it's what the laser system in Try Anything Twice uses.)- Put the first env_laser at the 'real' laser emitter, wait for the game to update the end point and see what it hits. (I'm afraid that this is going to involve math...)
- If it's a lens cube: put the next position at the emission point of that cube.
- If it's a portal, transform the hit location and angle to the other portal. (logic_measure_movement or more math)
- Deal with all the weird edge cases. (Cube inside portal etc.)
- Put the next env_laser at the calculated position and repeat.
- When we finally hit something that is not a cube or a portal, move the endpoint back 32 units and teleport the cargo there.
- Finally: make all of the env_lasers flash in a nice colour. Yay!
I'm absolutely sure that all of this is going to work without any unforseen problems whatsoever.
[/spoiler]
Wow, that... doesn't look difficult at all... *cough*
Love to hear how this works out. Hope all will go well.HMW wrote:Unfortunately I can't read what you're typing in the console. Did you parent the player to the cube or what?Yes he did, said so in the description. Though I never thought I'd see the day... O_o
- Put the first env_laser at the 'real' laser emitter, wait for the game to update the end point and see what it hits. (I'm afraid that this is going to involve math...)
- If it's a lens cube: put the next position at the emission point of that cube.
- If it's a portal, transform the hit location and angle to the other portal. (logic_measure_movement or more math)
- Deal with all the weird edge cases. (Cube inside portal etc.)
- Put the next env_laser at the calculated position and repeat.
- When we finally hit something that is not a cube or a portal, move the endpoint back 32 units and teleport the cargo there.
- Finally: make all of the env_lasers flash in a nice colour. Yay!
I'm absolutely sure that all of this is going to work without any unforseen problems whatsoever.
Wow, that... doesn't look difficult at all... *cough*
Love to hear how this works out. Hope all will go well.
Yes he did, said so in the description. Though I never thought I'd see the day... O_o
Quote from sicklebrick on April 13, 2012, 2:18 pmGood news everybody! (HMW mainly...)
Thread derailment preventative...
[spoiler]So I was thinking about what you said about the placement helpers, and wrote a quick script to debug them..So we know that info_placement_helpers belonging to env_portal_lasers are just disabled when the laser is off, and stick around for the life of the laser... But it turns out that when you interrupt the beam with a reflecto cube, it just disables it too.. but creates a new temporary one that is killed when the cube loses its laser source.
I also noticed that an info_target is placed at the mouth of every laser, and another at the start of the cube's laser. There's some weird issues whereby these move as the player does.. but from what I can see, the instant they're created, they're in the right place.
It's still not perfect, and it's not a *huge* help when tracing the path of the laser, but hopefully having targethelper pairs saves you a bunch of time
(Can't nest [bigspoiler]s, so the code's at the end...
Love the outline btw (so optimistic!)- never thought of using a logic_measure_movement like that! May there be no unforseen circumstances
Super curious as to how you grabbed a handle to the sprites at map spawn though... mind sending me a rough outline?
Oh yeah, the tiny writing.. something like this.
- Code: Select all
**point at george
ent_fire !picker addoutput "targetname george"
ent_fire george disablemotion
ent_fire george addoutput "angles 0 0 0"**point at emitter
ent_fire !picker setparent georgeent_fire george addoutput "angles 0 0 0"
**point at harry
ent_fire !picker addoutput "targetname harry"**point at barbra (button)
ent_fire !picker addoutput "targetname barbra"**stood next to cube
ent_fire !player setparent harryent_fire barbra press
And the nut script
- Code: Select all
//Remember to place a copy of the entity in the map before running to avoid precache error (crash) .
function setup(){ent <- null
while((ent = Entities.FindByClassname(ent,"info_placement_helper")) != null){
newName <- UniqueString();
EntFireByHandle( ent, "addoutput" "targetname " + newName, 0, null, null );
tempCube <- CreateProp("prop_physics", Vector(50,50,0), "models/props/lab_chair/lab_chair.mdl", 1 );
EntFireByHandle( tempCube, "addoutput" "targetname " + newName + "_cube", 0, null, null );
tempCube.SetOrigin( ent.GetOrigin() + Vector( 0, 0 , 50) );
EntFireByHandle( tempCube, "setparent", newName, 0, null, null);
EntFireByHandle( tempCube, "addoutput", "rendercolor 255 12 12", 0, null, null);
printl("Found a placement helper at " + ent.GetOrigin() + " called " + newName);
}
ent <- null
while((ent = Entities.FindByClassname(ent,"info_target")) != null){
newName <- UniqueString();
EntFireByHandle( ent, "addoutput" "targetname " + newName, 0, null, null );
tempCube <- CreateProp("prop_physics", Vector(50,50,0), "models/props_bts/bts_chair.mdl", 1 );
EntFireByHandle( tempCube, "addoutput" "targetname " + newName + "_cube", 0, null, null );
tempCube.SetOrigin( ent.GetOrigin() + Vector( 0, 0 , 50) );
EntFireByHandle( tempCube, "setparent", newName, 0, null, null);
EntFireByHandle( tempCube, "addoutput", "rendercolor 12 12 255", 0, null, null);
printl("Found a placement target at " + ent.GetOrigin() + " called " + newName);
}
}setup();
[/spoiler]
I should stop distracting you from the next installment... world ends in 231 days, hurry!
Good news everybody! (HMW mainly...)
Thread derailment preventative...
So we know that info_placement_helpers belonging to env_portal_lasers are just disabled when the laser is off, and stick around for the life of the laser... But it turns out that when you interrupt the beam with a reflecto cube, it just disables it too.. but creates a new temporary one that is killed when the cube loses its laser source.
I also noticed that an info_target is placed at the mouth of every laser, and another at the start of the cube's laser. There's some weird issues whereby these move as the player does.. but from what I can see, the instant they're created, they're in the right place.
It's still not perfect, and it's not a *huge* help when tracing the path of the laser, but hopefully having targethelper pairs saves you a bunch of time
(Can't nest [bigspoiler]s, so the code's at the end...
Love the outline btw (so optimistic!)- never thought of using a logic_measure_movement like that! May there be no unforseen circumstances
Super curious as to how you grabbed a handle to the sprites at map spawn though... mind sending me a rough outline?
Oh yeah, the tiny writing.. something like this.
- Code: Select all
**point at george
ent_fire !picker addoutput "targetname george"
ent_fire george disablemotion
ent_fire george addoutput "angles 0 0 0"**point at emitter
ent_fire !picker setparent georgeent_fire george addoutput "angles 0 0 0"
**point at harry
ent_fire !picker addoutput "targetname harry"**point at barbra (button)
ent_fire !picker addoutput "targetname barbra"**stood next to cube
ent_fire !player setparent harryent_fire barbra press
And the nut script
- Code: Select all
//Remember to place a copy of the entity in the map before running to avoid precache error (crash) .
function setup(){ent <- null
while((ent = Entities.FindByClassname(ent,"info_placement_helper")) != null){
newName <- UniqueString();
EntFireByHandle( ent, "addoutput" "targetname " + newName, 0, null, null );
tempCube <- CreateProp("prop_physics", Vector(50,50,0), "models/props/lab_chair/lab_chair.mdl", 1 );
EntFireByHandle( tempCube, "addoutput" "targetname " + newName + "_cube", 0, null, null );
tempCube.SetOrigin( ent.GetOrigin() + Vector( 0, 0 , 50) );
EntFireByHandle( tempCube, "setparent", newName, 0, null, null);
EntFireByHandle( tempCube, "addoutput", "rendercolor 255 12 12", 0, null, null);
printl("Found a placement helper at " + ent.GetOrigin() + " called " + newName);
}
ent <- null
while((ent = Entities.FindByClassname(ent,"info_target")) != null){
newName <- UniqueString();
EntFireByHandle( ent, "addoutput" "targetname " + newName, 0, null, null );
tempCube <- CreateProp("prop_physics", Vector(50,50,0), "models/props_bts/bts_chair.mdl", 1 );
EntFireByHandle( tempCube, "addoutput" "targetname " + newName + "_cube", 0, null, null );
tempCube.SetOrigin( ent.GetOrigin() + Vector( 0, 0 , 50) );
EntFireByHandle( tempCube, "setparent", newName, 0, null, null);
EntFireByHandle( tempCube, "addoutput", "rendercolor 12 12 255", 0, null, null);
printl("Found a placement target at " + ent.GetOrigin() + " called " + newName);
}
}setup();
I should stop distracting you from the next installment... world ends in 231 days, hurry!
Quote from HMW on April 14, 2012, 6:34 pmThanks for the info sicklebrick! I didn't know you could use "addoutput" to change properties like that!
I think it's a good idea to keep adding [bigspoiler]'s for technical stuff so we don't scare casual readers
Progress!
[spoiler]I had a lot of fun with your debugging script. I did something similar while developing the current version of the sendificator.
A s you have seen, the placement helpers for all beams except for the last one are useless because they are not updated.Fortunately however, the env_laser end sprite trick still works in Portal 2!
sendtor_dev.jpgThe white beams are completely script-controlled and can be updated on command. They should overlap nicely with the 'real' laser.
To track the endpoint of a laser beam, you have to set its "End sprite" property to a valid texture. It will then create an env_sprite entity on start-up, for which you can get a handle with FindByClassnameNearest(). (You have to do this in some initialisation routine, when the location of the sprite is known.) Then just move the laser and/or target around and (after a very short delay) read out the position of the env_sprite to get the place where the laser hits something.
The rest consists of a whole lot of number crunching that I cbf to explain right now, but as soon as I have
1) developed this version of the system to the point where it can replace the current one, and
2) published the next map in the series,
I'll release all sendificator-related stuff separately so everyone can be beaming cubes around in their custom mapsThere is one problem I don't have an answer for yet: how to detect when a portal is inactive. The entities themselves always exist, so the script keeps finding them even if they are closed after being placed. It's the only missing piece of this script right now so if anyone knows how to do that, I'm all ears![/spoiler]
sicklebrick wrote:I should stop distracting you from the next installment... world ends in 231 days, hurry!I consider the scenario more and more likely that I'll have it finished in 231 days, and the world will end because of it
Thanks for the info sicklebrick! I didn't know you could use "addoutput" to change properties like that!
I think it's a good idea to keep adding [bigspoiler]'s for technical stuff so we don't scare casual readers
Progress!
A s you have seen, the placement helpers for all beams except for the last one are useless because they are not updated.
Fortunately however, the env_laser end sprite trick still works in Portal 2!
The white beams are completely script-controlled and can be updated on command. They should overlap nicely with the 'real' laser.
To track the endpoint of a laser beam, you have to set its "End sprite" property to a valid texture. It will then create an env_sprite entity on start-up, for which you can get a handle with FindByClassnameNearest(). (You have to do this in some initialisation routine, when the location of the sprite is known.) Then just move the laser and/or target around and (after a very short delay) read out the position of the env_sprite to get the place where the laser hits something.
The rest consists of a whole lot of number crunching that I cbf to explain right now, but as soon as I have
1) developed this version of the system to the point where it can replace the current one, and
2) published the next map in the series,
I'll release all sendificator-related stuff separately so everyone can be beaming cubes around in their custom maps
There is one problem I don't have an answer for yet: how to detect when a portal is inactive. The entities themselves always exist, so the script keeps finding them even if they are closed after being placed. It's the only missing piece of this script right now so if anyone knows how to do that, I'm all ears!
I consider the scenario more and more likely that I'll have it finished in 231 days, and the world will end because of it
Other Portal 2 maps: Medusa Glare
Portal 1 maps: Try Anything Twice | Manic Mechanic
Quote from evang on April 15, 2012, 12:21 amI was VERY impressed with this map! I had this dumb smirk on my face when I finally figured out the solution to the second puzzle.
You used the concept very cleverly, I'm totally recommending this to everyone I know with Portal 2.
I was VERY impressed with this map! I had this dumb smirk on my face when I finally figured out the solution to the second puzzle.
You used the concept very cleverly, I'm totally recommending this to everyone I know with Portal 2.
Quote from Lpfreaky90 on April 15, 2012, 5:10 amI let a friend play this map yesterday and he really enjoyed it. He isn't really experienced with playing portal 2 maps, it's just that I let him play my maps.
In the first map it took him quite some time to see that he could also portal up; he started off with trying to stack cubes and hoping he could jump up.
The second room took him about 20 minutes and he had a big smile on his face.
The third room took him about 15 minutes most of the time was trying to figure out how to fling hte cube and I realized that the level design is brilliant.
[spoiler]The first fling you make is the same as the one with the cube. So people do know about the fact this fling is possible, clever, very clever![/spoiler]5/5 from him too, keep up the good work.
I let a friend play this map yesterday and he really enjoyed it. He isn't really experienced with playing portal 2 maps, it's just that I let him play my maps.
In the first map it took him quite some time to see that he could also portal up; he started off with trying to stack cubes and hoping he could jump up.
The second room took him about 20 minutes and he had a big smile on his face.
The third room took him about 15 minutes most of the time was trying to figure out how to fling hte cube and I realized that the level design is brilliant.
5/5 from him too, keep up the good work.
Quote from Rotab on April 15, 2012, 7:06 amI managed to get a staircase "extended" without having anything on the button. (http://i.imgur.com/Y6jeN.jpg) I was just goofing around trying to reach the button other by jumping around.. Then when I looked around the staircase was there.
Here is a savegame if it helps: http://rotabland.eu/files/stairbug.sav
I managed to get a staircase "extended" without having anything on the button. (http://i.imgur.com/Y6jeN.jpg) I was just goofing around trying to reach the button other by jumping around.. Then when I looked around the staircase was there.
Here is a savegame if it helps: http://rotabland.eu/files/stairbug.sav
Quote from HMW on April 15, 2012, 7:50 amHmm... I thought I got rid of that bug. Thanks for pointing that out!
@lpfreaky90: Thanks for the '3rp party review'! It's always helpful to know how other players experience it, especially if they haven't played many custom maps yet.
There are lots of maps out there that use all kinds of tricks and engine quirks that you have to be 'in the know' of to be able to solve them. I want my maps to be hard, but possible to solve for someone whose only Portal experience is the original game. I'm glad to hear that this map complies with that principle
Hmm... I thought I got rid of that bug. Thanks for pointing that out!
@lpfreaky90: Thanks for the '3rp party review'! It's always helpful to know how other players experience it, especially if they haven't played many custom maps yet.
There are lots of maps out there that use all kinds of tricks and engine quirks that you have to be 'in the know' of to be able to solve them. I want my maps to be hard, but possible to solve for someone whose only Portal experience is the original game. I'm glad to hear that this map complies with that principle
Other Portal 2 maps: Medusa Glare
Portal 1 maps: Try Anything Twice | Manic Mechanic
Quote from sicklebrick on April 15, 2012, 8:00 amMoar Progress!
[spoiler]That's pretty swift progress man!I might actually have a solution for detecting portals too... but bear with... it's not exactly straightforward!
So I've been writing a Prey style script recently - that basically rotates the map (including portals and stuff) to the normal of whatever plane they player's stood on. I.e. wall walking... but there was a wee issue with portals appearing at the origin, which could kinda help.
Basically, if you follow these steps
-sv_allow_mobile_portals 1 (not sure if it's necessary, but it works with)
-ent_fire !Picker kill (point at one of your portals and kill it.. or both..)
-stand in a trigger_portal_cleanser (important bit, don't skip this step!)
-ent_fire !Player runscriptfile dumponce.nut (run dump script I pasted at the bottom... )Notice how the portal cleanser has re-created the missing portal and placed it on the origin?
You can manually re-enable the portals with ent_fire prop_portal setactivatedstate 2 if you wanna see them. One will be at 0,0,0, and the other will be where you left it.Basically, in my script, I've had to account for portals on 0,0,0 and delete them, as they're supposed to be disabled. That probably doesn't help much on its own, but if you run something like this in your script think, you'll be able to detect the state of a given portal based on what it's called.
- Code: Select all
while((ent = Entities.FindByClassname(ent,"prop_portal")) != null){
if ( ent.GetName() != "namedPortal" ){
//if it's already been named, skip it, so we don't add the OnPlacedSuccessfully more than once
Printl("Found a new portal, naming and triggering it. Yay!");
EntFireByHandle( ent, "addoutput", "targetname namedPortal", 0 , ent, ent);
EntFireByHandle( ent, "addoutput", "OnPlacedSuccessfully !self,addoutput,targetname activePortal", 0 , ent, ent);
}}
So your portals can either be named:
-nothing (untill the next script think)
-"namedPortal" (inactive)
-"activePortal" (active)Next double up all your fizzlers
I.e. anywhere you'd have a fizzler, have one with the flags set to detect Players (Clients) and one for Physics Objects
Have the client one do an explicit:
OnStartTouch ent_fire prop_portal kill
So cubes won't kill portals in the fizzler, but the player will.
(Also.. being in a fizzler, it'll auto-recreate the portals in their disabled state so it might be necessary to move a separate trigger onto the player briefly instead of sandwiching them together.)Now the act of standing in the fizzler will kill your portals properly, but putting a cube in the fizzler will not.
So when you trace, you can account for portals that aren't called "activePortal" and aren't centered on 0,0,0
It's a really roundabout ass way of detecting the state, but it does work at least!Sooo, if that works, mind explaining what you mean about setting the end sprite on a laser?
I couldn't find any .nuts in the Try Anything Twice source, and there's no mention of an end sprite in the FGD :p
- Code: Select all
//dump script I used - dumponce.nut
//runOnce allows you to place it as a script think that executes on the first available frame.
//running it manually works multiple times too 'cause it's overwritten.runOnce <- false;
function setup(){if ( !runOnce ){
ent <- null
while((ent = Entities.FindByClassname(ent,"*")) != null){
printl("Found an item at " + ent.GetOrigin() + " called " + ent);
EntFireByHandle( ent, "addoutput", "rendercolor 12 12 255", 0, null, null);
}
}
runOnce = true;
}setup();
Edit;
Lol, on reflection, I realise you don't need both parts... but hey.. can't hurt to have two methods at your disposal
[/spoiler]
Moar Progress!
I might actually have a solution for detecting portals too... but bear with... it's not exactly straightforward!
So I've been writing a Prey style script recently - that basically rotates the map (including portals and stuff) to the normal of whatever plane they player's stood on. I.e. wall walking... but there was a wee issue with portals appearing at the origin, which could kinda help.
Basically, if you follow these steps
-sv_allow_mobile_portals 1 (not sure if it's necessary, but it works with)
-ent_fire !Picker kill (point at one of your portals and kill it.. or both..)
-stand in a trigger_portal_cleanser (important bit, don't skip this step!)
-ent_fire !Player runscriptfile dumponce.nut (run dump script I pasted at the bottom... )
Notice how the portal cleanser has re-created the missing portal and placed it on the origin?
You can manually re-enable the portals with ent_fire prop_portal setactivatedstate 2 if you wanna see them. One will be at 0,0,0, and the other will be where you left it.
Basically, in my script, I've had to account for portals on 0,0,0 and delete them, as they're supposed to be disabled. That probably doesn't help much on its own, but if you run something like this in your script think, you'll be able to detect the state of a given portal based on what it's called.
- Code: Select all
while((ent = Entities.FindByClassname(ent,"prop_portal")) != null){
if ( ent.GetName() != "namedPortal" ){
//if it's already been named, skip it, so we don't add the OnPlacedSuccessfully more than once
Printl("Found a new portal, naming and triggering it. Yay!");
EntFireByHandle( ent, "addoutput", "targetname namedPortal", 0 , ent, ent);
EntFireByHandle( ent, "addoutput", "OnPlacedSuccessfully !self,addoutput,targetname activePortal", 0 , ent, ent);
}}
So your portals can either be named:
-nothing (untill the next script think)
-"namedPortal" (inactive)
-"activePortal" (active)
Next double up all your fizzlers
I.e. anywhere you'd have a fizzler, have one with the flags set to detect Players (Clients) and one for Physics Objects
Have the client one do an explicit:
OnStartTouch ent_fire prop_portal kill
So cubes won't kill portals in the fizzler, but the player will.
(Also.. being in a fizzler, it'll auto-recreate the portals in their disabled state so it might be necessary to move a separate trigger onto the player briefly instead of sandwiching them together.)
Now the act of standing in the fizzler will kill your portals properly, but putting a cube in the fizzler will not.
So when you trace, you can account for portals that aren't called "activePortal" and aren't centered on 0,0,0
It's a really roundabout ass way of detecting the state, but it does work at least!
Sooo, if that works, mind explaining what you mean about setting the end sprite on a laser?
I couldn't find any .nuts in the Try Anything Twice source, and there's no mention of an end sprite in the FGD :p
- Code: Select all
//dump script I used - dumponce.nut
//runOnce allows you to place it as a script think that executes on the first available frame.
//running it manually works multiple times too 'cause it's overwritten.runOnce <- false;
function setup(){if ( !runOnce ){
ent <- null
while((ent = Entities.FindByClassname(ent,"*")) != null){
printl("Found an item at " + ent.GetOrigin() + " called " + ent);
EntFireByHandle( ent, "addoutput", "rendercolor 12 12 255", 0, null, null);
}
}
runOnce = true;
}setup();
Edit;
Lol, on reflection, I realise you don't need both parts... but hey.. can't hurt to have two methods at your disposal
Quote from HMW on April 15, 2012, 11:15 amsicklebrick wrote:Moar Progress!"Even Moar Progress!
[spoiler]OH! I forgot about the OnPlacedSuccessfully output! That is super useful, thanks!
You approach looks very viable, so I'm going to try that. I'm only wondering how to detect when a portal has been closed because the surface it was on, moved. Probably best to deal with that on a case-by-case basis.About the end sprite: keep in mind that this is an env_laser, not a Portal laser. The env_laser has been around since the original Half-life and it's probably in another FGD, that the Portal FGD includes. (Also Portal 1 did not have .nut scripts yet, so that's why TA2 doesn't have any. (Boy would that have made my life easier back then!))
laser_array.pngI have a bunch of these set up as shown above. Since nothing is blocking the lasers, the env_sprite entities will be at the location of the info_targets, so I know exactly where to find them with FindByClassnameNearest().[/spoiler]
"Even Moar Progress!
You approach looks very viable, so I'm going to try that. I'm only wondering how to detect when a portal has been closed because the surface it was on, moved. Probably best to deal with that on a case-by-case basis.
About the end sprite: keep in mind that this is an env_laser, not a Portal laser. The env_laser has been around since the original Half-life and it's probably in another FGD, that the Portal FGD includes. (Also Portal 1 did not have .nut scripts yet, so that's why TA2 doesn't have any. (Boy would that have made my life easier back then!))
I have a bunch of these set up as shown above. Since nothing is blocking the lasers, the env_sprite entities will be at the location of the info_targets, so I know exactly where to find them with FindByClassnameNearest().
Other Portal 2 maps: Medusa Glare
Portal 1 maps: Try Anything Twice | Manic Mechanic
Quote from sicklebrick on April 15, 2012, 12:29 pmhoot!
[spoiler]Aaaah, env_laser! Now I've gotcha, much easier just to alter the rendercolor on a bunch of them than play with env_beamsCertainly is a shame they need a point target, but it's better than nothing.
I guess untill someone figures out a better detection method for portals a case-by-case way of handling moving portal surfaces is best too. Lucky it's safe enough just to kill portals outright
Gotta say, loving the insane amount of work you're putting into just flashing the laser >.<[/spoiler]
hoot!

I guess untill someone figures out a better detection method for portals a case-by-case way of handling moving portal surfaces is best too. Lucky it's safe enough just to kill portals outright
Gotta say, loving the insane amount of work you're putting into just flashing the laser >.<