Jump to content


  • Posts

  • Joined

  • Last visited

1 Follower

Profile Information

  • Gender
  • Modding Interests

Contact Methods

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

MoonDog's Achievements

  1. MoonDog

    Icarus Scripting

    Introduction/Setup There are times when entities fall short. There are some things you just can't accomplish with plain old entity modding. This is where Icarus scripts come into play. Icarus is just the type of script file that JKA uses in game. (.ibi) So, first off, what can we use it for? Icarus comes in handy for a great many things, so here are a few examples. You can make entities unusable. You can manipulate them with rotations and moving them around. You can set special Parameters on players to give them "special clearance" for other functions on your map. You can manipulate NPC's, heal players and give them shield. Control scale, setup timers, etc...So, what do we need? In order to write and compile scripts into .ibi files for use in JKA, you need to use a program called Behaved. You may also find it handy to have its counterpart, Devaheb. (It decompiles scripts so you can look at them. Do not copy other people's scripts without asking permission. It's perfectly okay to look at them to learn how to do it yourself though.) You can attain these tools by downloading the SDK. You may also download GTKRadiant. So first parts first. You HAVE to set it up properly. Do not skip these steps.First off, I use GTKRadiant 1.4. So, my Behaved resides in Star Wars Jedi Knight Jedi Academy\GameData\Radiant-1.4\Tools. If you use the SDK your's will be located projects/JEDI_Academy_SDK/Tools folder Next open up Behaved. You'll see a few sections on the right side, from top to bottom. Under the Application section, open up "Prefs". When the new window pops up, look for "Set All Options to JKA Default". Click it. Next, make sure the paths are consistent with where you extracted your BehavEd and DEvaheb folder. So, for IBIZE.EXE. C:\Wherever you extracted to\BehavEd and DEvaheb\IBIze.exe For the Command Line Description file make sure C:\Wherever you extracted to\BehavEd and DEvaheb\behaved.bhc is selected. And last, but certainly not least, "Source Files Path". Inside the BehavEd and DEvaheb folder you made, there will be another folder called "SourceForBehavEd". Make sure it's set to the proper path of your folder. For instance, mine is: C:\Program Files\LucasArts\Star Wars Jedi Knight Jedi Academy\GameData\Radiant-1.4\Tools\BehavEd and DEvaheb\SourceForBehavEd Excellent! You should be fully setup. If not, you will get error codes when you try to use the drop down menus of the commands. If so, follow the steps above until you get it right. Universal Set Scale/Unusable Unusable/Setscale script Making our first script: Universal Scale/Unusable script. How to utilize scripts in entity coding.(Beginner) If you've gotten this far I'm going to assume you understand proper entity syntax and are familiar with their keys and spawnflags. If not, set your eyes upon one of the other tutorials here on JKHub. Or download GTKRadiant and familiarize yourself with the Entity List(N). Now, since we are using scripts, we have a new entity to consider and several new entity keys. First off, we have the entity "target_scriptrunner". This entity reads from the scripts folder in your pk3 to the script you specify. So, make sure your PK3 has a folder called "scripts". If you wish to keep your scripts organized you can split them into subfolders inside the scripts folder within the PK3. You just have to make sure your coding reflects that. So, let's assume you just did "scripts" inside your PK3 and simply placed all your IBI files therein.. Your scriptrunner would just look like this: { "classname" "target_scriptrunner" "targetname" "myscript" "count" "-1" "spawnflags" "1" "usescript" "FirstScript" } Notice you don't need to put scripts/ before the script name? However, if your script was inside a different folder within the scripts folder you'd HAVE to specify that folder. Like so: "usescript" "tutorial/FirstScript" By this time you should already be familiar with spawnflags and keys like wait, count, delay, etc... If you aren't I'd highly recommend running GTKRadiant and looking through the entity list. (Press N) Here are but a few of the keys we can use associated with scripting: "usescript" - "script_targetname" - "parm1" through "parm16" - "spawnscript" - "deathscript" "usescript" : You can add this entity on triggers or other func_ entities. This specifies that, when used, this entity will fire the script you specify. "script_targetname" : This is meant specifically for the affect command in BehavED. This means you will be doing something to this entity at some point with a script. "parm1" through "parm16" : Every entity you make can have 16 variables set on it. Think of them as little bookmarks for information that the script can read and then use. You can put any number or text string into this key so that you may call on it in your scripts. "spawnscript" : When this entity spawns, it will run this script. "deathscript" : When this entity is killed, it will run this script. So! Armed with this information, let's make our first script. Hopefully by now, you are advanced enough in entity modding to know that you can use misc_model_health_power_converter entities in order to spawn models throughout your map. However, there's a couple problems with this method. One, the entity will still be usable as a health converter. Two, you can't set the scale on the entity. So, in order to fix this we are going to make a script to tell the entity it cannot be used by players and to check "parm1" on the entity for setting scale up or down. So, let's make a simple tree from map_objects/yavin. { "origin" "0 0 0" "model" "models/map_objects/yavin/tree02_b.md3" "classname" "misc_model_health_power_converter" } First off, we need to add one of the keys we talked about. "spawnscript" I've already decided that I will name my script UniSSUnus. So, I'll add the spawnscript key. "spawnscript" "UniSSUnus" Remember when I said you could store variables directly on an entity with the parm keys? Well, the script we are going to write will read parm1 and then set the entities scale to parm1. So, I want this tree to be 175% bigger than its original size. Let's add it to the entity as "parm1" "1.75" { "origin" "0 0 0" "spawnscript" "UniSSUnus" "parm1" "1.75" "model" "models/map_objects/yavin/tree02_b.md3" "classname" "misc_model_health_power_converter" } Now, let's open up BehavED. On the left side of the UI, you'll see a section called "Events". This is pretty self explanatory. You click the command you want to use, and drag it into the center window called "Script Flow". Specifically, we are going to use the set event for setting specific Icarus callbacks. Drag two of these into your script flow. Now, by default it will be at SET_PARM1, DEFAULT. Double click this line to bring up a config box.You should see a drop down menu on the left and a str box on the right. Open the drop box. If you setup BehavED properly you'll see all sorts of icarus callbacks, conveniently sorted into sections. If not, you'll probably get an error and see nothing. Follow the installation steps on the first page to setup BEhaved correctly. We are going to start with making the entity unusable. Scroll down to the Booleans section and look for SET_PLAYER_USABLE and click it. It should show that as your selection in the SET box. Now move to the str box and type false and hit Ok. The line should now read (SET_PLAYER_USABLE, false). Now lets move onto setting the scale. Open up a second Set command in the script flow. Open the drop box again and scroll down to floats. Near the bottom you should see SET_SCALE. Click it. Now, instead of typing anything into the str box, click Helper. You'll see another drop box pop up with a Get button next to it. Remember how we set the scale on our entity in "parm1"? You guessed it! Make sure SET_PARM1 is selected in the drop box and click Get. You should now see 'get(FLOAT, "SET_PARM1") in the str box. Click Ok. If all went as planned you should see (SET_PLAYER_UNUSABLE, false ) (SET_SCALE, get(FLOAT, "SET_PARM1") ) The rem line is used to comment your script. It has no affect on the flow of the script. Click Save As, and type UniSSUnus. Save. After you save click Compile !. If you did everything right it will compile with no errors in whatever directory you saved it in. If we open it up with notepad or behaved we should see rem ( "Unusable/setscale" ); set ( /*@SET_TYPES*/ "SET_PLAYER_USABLE", "false" ); set ( /*@SET_TYPES*/ "SET_SCALE", $get( FLOAT, "SET_PARM1")$ ); Go ahead and place it inside your "scripts" folder within your maps PK3. Compile your map, load up, test. You should now see your model at 175% of its normal scale, and it will be unusable as a health generator. Shield Dispenser Making our second script: A shield Dispenser (Intermediate) This script will be a bit trickier than the last one. misc_model_health_power_converter works just fine for recovering HP in our map modding without the need of any scripting. However, you've probably tried to use a misc_model_shield_power_converter and noticed it doesn't work/crashes your game. This is one of limitations with ent modding we are about to overcome. Let's get started. First off, decide what "model" you will be using for your shield dispenser and make a misc_model_health_power_converter and specify the the model you chose. Specify your origin and angle. Remember that handy unusable script we made last time? You are going to add that to the "spawnscript" key to make sure this thing can't be used to regain health. It's merely here to display a model. { "origin" "0 0 0" "angles" "0 0 0" "parm1" "2.5" "model" "models/items/psd.md3" "spawnscript" "UniSSUnus" "classname" "misc_model_health_power_converter" } I went ahead and included the model I use for my shield dispensers, and the scale I set it to in the code above. Now we need 2 more ents. First: a trigger_multiple, second: A target_scriptrunner that's going to be targeted by your trigger_multiple. { "angles" "0 180 0" "wait" "1" "target" "shieldscript" "spawnflags" "6" //Press use to activate and must be facing 180 "origin" "0 0 0" "model" "*8" "classname" "trigger_multiple" } { "usescript" "shieldtutorial" "count" "-1" //Can be executed infinitely "targetname" "shieldscript" "spawnflags" "1" //This spawnflag means that this scriptrunner will run on the entity that used it. Or the entity that triggered the entity that used it. Players are entities. "classname" "target_scriptrunner" } I've taken the liberty of deciding that we will be naming the script "shieldtutorial". Now we are ready to make the script. Let's dive into Behaved. Our main commands for this script are going to be if and else. Basically *if* checks for some kind of variable. IF the condition matches It executes the block of commands under it. If the condition doesn't match, it moves to the else line. (Unless you don't specify an else condition. In which case, nothing happens. ) First drag an if expression into the script flow. We are going to be working with a lot of these. In order to fully simulate a shield dispenser we are going to use multiple "if" statements to check if your shield is below a certain level. If it is, it will set your shield up to the level it checked. Basically if you have less than 25 it will set it to 25. Less than 50, it sets to 50 and so on until you are at 100. This also means we will be putting "if" s inside "else" commands to smooth it out. So, open up that IF command you made. In the first expr open up the drop down menu next to Get. Scroll down to "ints" and look for SET_ARMOR. Click it, then click the Get button. We should now see get( FLOAT, "SET_ARMOR") in the first expr box. Now in the middle box you are going to see < > ! =. Those are operators meaning less than, greater than, not, and equal to. We will be check to see if our shield is lower than 25. So, select less than . In the last expr box type 25. Click okay. You should now see if (get(FLOAT, "SET_ARMOR"), < ,25) This statement says IF the float shield is less than 25. So what will happen if the shield is less than 25? We will raise it to 25. Drag a set event into the script flow INSIDE the IF. Open the set up by double click it. Open the drop box and scroll down to "ints" and again select SET_ARMOR. In the value box type 25. Basically what we just did was check to see the state of the players armor. If its less than 25, we will bump it up to 25. That's all fine and dandy. But what if its less than 50 and more than 25? Well, that's where our "else" commands start to come in. Make sure your IF is collapsed before you drag your else into the script flow. If you else is inside your IF command under set and sound, you did it wrong. Move it out of the IF, collapse the IF, place it UNDER the IF. Now, you are going to select that last if block you made and clone it by pressing the space bar. You'll see a new IF popup collapsed. Drag that whole block into that ELSE you made. Double click it. You'll notice it's exactly the same as the last IF. Change the 25 to 50. Open up the SET event in this if, and likewise change it to 50. The pattern should be immediately evident to you by now. We are increment the integer valuer of the shield in each IF block. Basically, we are going to repeat this structure until we reached the desired end result of 100 shield. Each IF should have an ELSE attached to it. In the ELSE should be the next IF statement checking a greater value for the integer shield. If you followed the steps correctly, you will have something like the picture above. Save it and compile it. Your ent code to use this script should look something like this: { "angles" "0 180 0" "wait" "1" "target" "shieldscript" "spawnflags" "6" "origin" "0 0 0" "model" "*8" "classname" "trigger_multiple" } { "usescript" "shieldtutorial" "count" "-1" "targetname" "shieldscript" "spawnflags" "1" "classname" "target_scriptrunner" } The trigger_multiple waits 1 second in between triggering to make it feel smoother. Adjust that as you please. Place the script inside your "scripts" folder in your custom map's PK3, compile your map's .ent file. Save it all up, try it out. Good luck and enjoy. *Extra* I like to spice mine up by having it play sounds at each IF/else check. Admin Key Making our third script: An admin key (Beginner) This script is ridiculously simple. Again, you'll need 2 entities. The first being a target_scriptrunner. { // admin key "classname" "target_scriptrunner" "count" "-1" "spawnflags" "1" "targetname" "adminkey" "usescript" "credentials" } Our script will be called "credentials". Count -1 ensures that this script can be used any number of times. "spawnflags" "1" says that it will activate on the trigger that executed the script. Or the entity that triggered the trigger that triggered the script. (In this case the player is the entity). The second entity can be anything the player will use to execute the script. An item_ysalimari, a trigger_multiple, whatever. In this case, we will use an ysalimari. { // Admin Key "classname" "item_ysalimari" "target" "adminkey" "wait" "4" "origin" "X Y Z" "count" "-1" "noglobalsound" "1" } When the player picks up the ysalimari it will trigger the target scriptrunner, thus executing our admin key script. Now that the entities are all setup, let's open up BehavED. Now, the first thing you need is a set "set_types" Double click it in the Script Flow box. Now, this is very simple. Just choose one of the set_parms. Any of them will do. Just make sure you remember which parm you used. It will now be your admin key. We will use set_parm2 for this. Type 1 in the "str box". It should now read SET_PARM2, 1. When the player picks up the ysalimari, his parm1 variable will be set to 1. Now you can make scripts that specifically check for that value before allowing the player to use it. Thus creating a lock system, or an admin key system. If you want, you can always add another line to the script to activate a target_print in your ent coding to tell the player they picked up the key. Just use an use "str" command. Type the name of the target_print in the str box. In the end you should have this: Here's a quick example of one of my scripts that uses the admin key system. Variable reset timer Making our fourth script: Parameter Reset Timer (Intermediate) In the previous tutorial I showed you a very simple way of using a parm as a key to enable players to have special permissions. As you start to allow the players to interact with the map more, and do things that are going to require you to set parms on the players, you are going to need to be able to reset them periodically or when the player reconnects. For instance, you are using parm2 for a setscale script, the player grows large with it and then reconnects a bit later. They will spawn large again because that parm hadn't been reset. So before we get into more advanced scripting where I'll show you how to do all these things like make admin restricted scripts, setscale, timescales, Juggernaut mode, etc... we need to develop a system for our map to control the chaos. I learned this method by observing how Nab622's map tpcv3 works. He graciously gave me permission to share this information with you all. So let's open up Behaved. First step. Drag 2 declares into the script flow. Make sure they are both declared as floats and name them timer and timer2. (NOTE: "timer1" in the following screenshots should be named "timer") Second step. Drag one wait into the script flow and leave it at 1000. Next, drag two set events into the script flow. have the first one set timer to 0 and the second one set timer2 to 25. Third step. Drag a loop into the script flow and leave it at -1. Place a wait 1000 and two set eventss into the loop -1. You may copy them from above or make new ones. Now this is important. Make the first one set timer +1 and the second one set timer2 +1. This has the effect of increasing our two global variable timers by 1 every second indefinitely. That's it for this script. Save it and compile it. Place it in your PK3. If you are using GTKRadiant make an info_null. Press (N). Add this key. spawnscript value: tuttimer (or whatever you named it). Save it. If you are .ent modding make the following entity. { "spawnscript" "tuttimer" "origin" "0 0 0" "classname" "info_notnull" "targetname" "startupnull" } When the map loads up all the entities the info_notnull will use it's spawnscript, thus setting up our global variables and starting the timers. I forgot the targetname in the screenshot. But add it as well. Target he info_notnull with something like a info_player_intermission. That's it for the first part. Now we need to head back to BehaveD and setup the script that will loop on each player as they spawn. First step. Drag a wait into the script flow and set it to 100. Drag a TASK into the script flow and name it "reset". If you followed my other tutorial you used Parm2 as your "admin key". Drag a set E"set_types" into the script flow and. Have this line set PARM2 to 0. Pretty much any parameter you use on the players that you'd like to be reset goes in this task. Since I only used PARM2 in these tutorials so far, that's all I put in. As I show other scripts I'll remind you that we are using a Parameter that will need to be added to this script later on. For now, let's just finish the script up by adding in the timer check. Start by dragging an IF event into the command flow. I plan on using PARM1 on the player to hold the timer information. So, make sure FLOAT is selected in the first drop box, and PARM1 is selected in the second and click GET. Do the same thing in the far right fields. However when the text is generated delete SET_PARM1 and type timer instead. In the middle field place the less than sign. (<) After you finish all that click Okay. Drag a DO into the if command subfield and set it to do the task called "reset". We are very nearly finished. The last step is to setup the loop that will set the timer information from the global variable "timer2" into the player's PARM1 field. So drag a loop into the script flow and leave it at -1. Make sure it's under the if(), not inside it. Drag a set E"Set_types" into the loop. Double click it to open it. Leave the first drop box as "SET_PARM1". Click helper on the right box to bring up the variable selector. It will start on SET_PARM1. Just click Get. If it says get( STRING, change it to get( FLOAT. Replace SET_PARM1 with "timer2". Save it, compile it, place it in your PK3. If you are using GTKRadiant make a target_scriptrunner. Make sure runonactivator is selected and type the following keys in key: usescript value: tutorialclientloop key: delay value: .001 key: count value: -1 key: targetname value: playerspawn If you are .ent modding the entity will look like this: { "delay" "0.001" "count" "-1" "usescript" "tutorialclientloop" "spawnflags" "1" "targetname" "playerspawn" "classname" "target_scriptrunner" } Now, have all your player spawns target the scriptrunner. If you are .ent modding the entity will look like this: { "angle" "270" "origin" "680 1424 -56" "classname" "info_player_start" "target" "playerspawn" } Load up your map and spawn up. Everything should be working fine. If you'd like to make certain it is working as it should, load up your map with /devmap mapname. Once you are loaded into the map type /developer 1 in the console. You should see the lines of your scripts working. If you made a mistake it will be shown to you in the console. Just follow the steps back until you find your mistake and fix it.
  2. Disclaimer: This tutorial assumes you already know how to extract entities from a bsp file, make them into a .ent file and then recompile your changes back into the .bsp file. Q: How do I make teleports without using Ysalimari's or Force Boons? A: This concept is a little complicated, but not overly so. However, you may not understand it at first. I like to use 4 entities to do this, however you MAY use less. First we need a "trigger_multiple". Now, depending on the map you are modding, the bmodels will vary. If you have Boba Fett's UU, type !bmodels to get a list. Try to find one that's physical, and small. !modelshader works good for this(Tells you the textures a certain model uses. If its something like a trigger it will say, no shader/texture found. Meaning, this is an invisible entity. Usage: !modelshader *8) . This is important because you MUST specify a brush model for this entity, or you will get an error when you load the map. Let's look at an FFA3 example. { "classname" "trigger_multiple" "model" "*8" "target" "exampletele" "origin" "1646 -1364 292" "spawnflags" "2" "angle" "90" } As you can see on FFA3 I like to use *8. It's part of an elevator, so it's originally a func_door. However, since we are using an entity that is invisible, the model will likewise, be invisible. Now origin can't just be whatever you are looking at in the GPS/getcoords. We are cloning *8 for this. So, the position of the ORIGINAL *8 is treated as 0 0 0. So, you either have to do some math, or use Boba Fett's ultra utility(Highly Recomend!). Stand at the spot you want the trigger to be(Where you step to get teleported) and type !brushmoveorigin *8. It will give you the coordinates you need to use for the origin of the trigger. You may have to raise or lower Z depending on the Bmodel/position. *IMPORTANT* You are NOT changing the original *8 coding. You can leave that alone. Simply specify the "model" as *8 and you will have cloned it. Now for the other parts of the entity. I like to make it so you have to FACE the entity to use it. (I.E. you can't walk backwards through the tele and still use it.) To do that I simply add the spawnflag "2". (2 is facing). Since we added the facing spawnflag, we have to add the angle you need to face to use it now. "90" happens to be the direction I want people to face before they can use it. (If you need to get angles use Boba Fett's UU. Type !openmenu and navigate to the GPS. It will tell you the angle.) If you want to see other spawnflags I'd recommend downloading GTKRadiant and using the Entity List(N). It will calculate spawnflags for you if you don't have them memorized. Alright, let's move onto the other 3 entities we need. My "target" is "exampletele". So, let's keep that in mind when writing the next ents. Now we need the entity that actually does the teleporting. "classname" "target_teleporter". It need's to have the targetname specified in the trigger_multiple. Also, it will be targeting a "target_position"(Where you will be teleported to). So, let's write it out. { "classname" "target_teleporter" "targetname" "exampletele" "target" "exampleposition" } Well that was simple. Let's get the position. Go to where ever it is you want to be teleported to and use the GPS again if you have Boba Fett's UU. Note the origin and yaw(Angle you face when it spits you out at the position specified. Specify this with the "angle" key.) { "classname" "target_position" "origin" "20 20 20" "angle" "270" "targetname" "exampleposition" } Now this next part is completely optional. I like to print some text to tell people where they just ended up. To do this, you need a "target_print". It needs to have the same "targetname" as the target_teleporter. We want it to be triggered by the trigger_multiple at the same time. So, let's write it out and take a look. { "classname" "target_print" "targetname" "exampletele" "message" "You in the Ghetto neow" "spawnflags" "4" } Looking over it, its pretty self explanatory. In the message field you can use ^ color codes just like you do in game. Also, if you wanted to make a line break you'd use \n. Again we have a "spawnflags" key. On this entity "spawnflags" "4" makes it so only the person who triggered the Entity see's the text. If you left it out, everyone would see the text regardless of whether or not they teleported. So, here's the finished deal: (Let's use // to comment the entities, so we remember what teleport it is) { // Trigger multiple for my first tele ever "classname" "trigger_multiple" "model" "*8" "target" "exampletele" "origin" "20 23 20" "spawnflags" "2" "angle" "90" } { // Teleporter for first tele "classname" "target_teleporter" "targetname" "exampletele" "target" "exampleposition" } { // Position - first tele "classname" "target_position" "origin" "20 20 20" "angle" "270" "targetname" "exampleposition" } { // Text for first tele "classname" "target_print" "targetname" "exampletele" "message" "You in the Ghetto neow" "spawnflags" "4" } Also, for added effect, you can place a fx_runner over the spot the teleporter is to indicate its there. I like to use force/kothos_recharge to indicate the position of my ports. All the effects can be found in assets1.pk3 in your base folder. Just open up the effects folder within the pk3. Indicate the fx with "fxfile" and make sure you include the subfolder. You should end up with something like this: { // FFX for first tele "classname" "fx_runner" "fxfile" "force/kothos_recharge" "origin" "0 0 0" }
  3. Part I : Mitre In Radiant terminology, to perform a mitre means to join two brushes at a point by beveling them. The advantages of which include less verts/tris/poly's what have you. In the long term this means better performance. This step is very commonly overlooked. For example, this is where two walls meet. While it could work this way, it's not efficient. Let's have a look at why. Compiling the walls in this manner, and loading up the map with developer 1 and enabling r_showtris shows us the inefficiency of this design choice. Because we are using two faces of the brush unnecessarily, we have created 6 total triangles as defined by 8 vertices. In this very simple design, that doesn't mean much. If you add that up at the end of a larger, more complex design however, performance will take a hit. To save ourselves trouble, we will "mitre" the brushes together. Step one of the process. Select one of the two brushes. Extend the brush until it occupies the same space as the other brush. After you have done so, select both brushes at the same time. Enable the clipper (X) and select clip points at the joining corners. In Radiant you can hold control and then right click to quickly place clip points on the grid. (Except for 1.5.0) Press Shift+Enter to split both brushes along the clip line. Select the two walls and hide them with (H). You'll be left with the two trash brushes we wish to delete. Select them and delete them. Unhide the walls with Shift+H. You'll notice that both walls have been beveled at the place where they join. This eliminates the use of a face unnecessarily. This means we have eliminated 2 vertices and two triangles. Let's compile it and take a look! Remember, type /developer 1 in the console followed by /r_showtris 1. You'll notice that we've eliminated two triangles. Finally, let's look at the two design choices side by side. You'll notice a significant difference. *** An alternate(and way better/faster) method to using the clipper is to use vertex manipulation mode(V), or edge manipulation mode(E). In most cases these are faster. If you are comfortable with these two methods, it will streamline your design process that much more. Be careful with your manipulations in this manner as it could trash a brush quite easily. Here is a gif displaying use of Edge mode manipulation to achieve the same desired outcome. ********* Additional Examples:
  4. Q: I injected a BSP with "misc_bsp". The sky is all screwed up in the new area! How do I fix it? A: When you insert a misc_bsp into an area of portaled void, you may have noticed that the skyboxes for those BSP ares blurred and incurring the hall of mirrors effect. In order to fix this, you must use a "misc_skyportal" entity. What this entity does is create a 360 degree snapshot and apply it to all skyboxes, including the misc_bsp entities' skyboxes. So, what you need to do is insert the entity WITHIN THE SKYBOX OF THE ORIGINAL LEVEL. You see that last sentence in red? Re-read it like 5 times. A good practice is to place the entity as far into a corner of the skybox as possible without putting it in the void. You are going to catch some of the original map on the skyboxes'. This is unavoidable. So try to keep it in an area where it sees as few entities and geometry as possible. Example: { "classname" "misc_skyportal" "origin" "X Y Z" }
  5. Q: How do I insert models into my map? Why aren't they solid? A: First, let me tell you that your model's will never be solid. Model's are never solid to begin with even in GTKRadiant. What makes a model solid is a brush called clip. Or physics_clip. There are several different types but they accomplish the same thing. It's an invisible structural brush that blocks the player. So, in GTKRadiant you make your model, and then you construct a "box" around it as close to the shape of the object as possible and then make that box Clip. (You could also add the spawnflag to the model to make q3map2 auto-clip the object, but that's beside the point.) Obviously, in entity modding you cannot modify the map in this manner. Thus, your models will remain non solid. HOWEVER! The main method of inserting a model is using misc_model_health_power_converter entities and then specifying the "model" as the object you wish to use. Now, misc_model_health_power_converter has its own hitbox, which isn't very big. But it blocks the player, which is handy for simulating clipping around models. For example, in my FFA3 I have three consoles I use in my Logistics area. I'll show you one. { "origin" "258 2655 700" "angle" "270" "model" "models/map_objects/h_evil/control_station.md3" "classname" "misc_model_health_power_converter" "spawnscript" "unusablesetscale" "parm1" "1.2" } As you can see I'm using the script I showed everyone how to make in my scripting tutorial to make the object unusable as a health power converter, and to increase the objects size to 120% of its normal size. The one downside of this method is that the object will still recover player's HP when you press use, but it's easily correctable with that script. Scripting tutorial Now, just ONE misc_model_health_power_converter hit box isn't enough to make the whole object solid. So, I'll need to make other ones exactly where I'd like the object to be solid, thus abusing them for my purpose. For this step, you don't need to specify a model, just a spawscript to make it unusable. That makes sure it's invisible. Like this: { "classname" "misc_model_health_power_converter" "origin" "257 2655 729" "spawnscript" "unusable" } It's that simple. Note that I didn't just magically specify "unusable" as the spawnscript making it unusable. I actually have a script by that name that only has one line, Seting player usable false. That's all. You'll need to make one as well. There is a second method to make objects on your map, but I wouldn't recommend using it if you don't have to. You make a func_static with a bmodel from your map specified in "model" field. Then, you make another key called "model2" and put the map_object/model whatever in that key. This is handy because you don't need a script for this entity. Not even to set the scale. You can use the key model2scale in order to change the scale of model2, which is the model you desire on your map. Keep in mind, there is no hitbox for this entity, and unlike misc_model_health_power_converter you'll be able to walk straight through it. I'll show you an example of what this would look like: { "classname" "func_static" "model" "*2" "model2" "models/map_objects/imperial/cell_door_frame.md3" "origin" "X Y Z" "angle" "45" "model2scale" "150" } Note that you don't have to use !brushmoveorigin to place this entity. The origin for this entity can be wherever you actually want it. It's very important that you don't go overboard. You can only have 256 entities at a time in one snapshot(area). If you go over this, it will truncate them down to 256 thus making things start to disappear. Also, certain entities like trigger_multiples may stop working. Don't place too many func_statics in one area or any other entities for that matter. Also, only specify model's that come in the assets1.pk3. You want everyone to be able to enjoy your map. This means you have to work with what Ravensoft gave you. Good luck.
  • Create New...