Jump to content

Walker White

Member
  • Posts

    89
  • Joined

  • Last visited

    Never

Everything posted by Walker White

  1. A Truly Complicated Example: AdvancedNPC Truly generic target assessment turns out to be much more complicated that I thought. A lot of things you take for granted in programming languages don't exist in AvernumScript. This is not really Jeff's fault. These things aren't easy and he had to make some design decisions. But in the end it limits what you can do. However, if you really know how to program, there is a lot of dark code magic that you can summon to make these programs do what you want to do. That is what I have done in advancednpc.txt . This is a fairly generic AI that allows the user to control everything through memory cells. In this AI I break everything into five categories. Closest targets Melee targets Archer targets Mage targets Priest targets To use the script, just put the selection strategy in Cell 4, and fill out how you feel about each of the categories in Cells 5-9. The instructions are in the comments. You will notice that this script has a lot of states. That is because, as advanced programmers will see, I am really using the states as functions. However, they are not the same as function. Functions return to where you called them; they don't start the state over; and they have return values. I fake all this using variables. It's a lot like programming in assembly at times. I am not going to say much more about this script as it is really only for the very advanced programmer (and if you are really advanced, I feel ashamed at showing you my hacks). I consider it a failure as it is a lot of code to do very little. Try it and see. As the last example taught us, chosing a target is not always as important as reassessing the situtation, running away, or yelling for help. What this script did teach me was a lot of limitations in AvernumScript. It also inspired me to look for other innovative ways to do target selection. And that is what I talk about next.
  2. Next: Modified Magekiller *i was good enough to post a magekiller script in this thread. Short, sweet and to the point. However, it has two minor issues in it. It cannot be used by NPCs that are allied with the party. It cannot target allies that are not in the party. This includes wizard allies that might be following the party through a custom script. We are going to solve these problems, but in doing so our script is going to become much more complicated. This introduces us to the world of "engineering trade offs". If neither of the two points above apply to you, then use *i's script; it is much more efficient. But if you care about them, then you should play with mine and see if the slowdown is acceptable. In the end, the choice is up to you, the scenario designer. I am going to present two modified mage killers, each pointing out features of AvernumScript. The first mage killer has several important features to consider when manually choosing targets. I keep target acquistion as a separate state from the START_STATE. This is not necessary, but it makes the code easier to read. Note that I do it by checking if there are any targets at all in range, and then dropping into state 4 to manually chose a target. This is a trick that I will do a lot. If you use set_state_continue(), it will not be that expensive compared to the rest of your script. I find a target by looping through all characters 0 through 119. These are all the characters there are in a town, as outlined in the docs. I always check that a character can be seen and is hostile. If you do not do these things in manual target selection, your monsters may run out the room to attack their friends. I have a weird way of measuring mage strength. I don't consider just spell level; I consider a mixture of spell level and bonus. A character with one spell level lower than another, but twice the bonus, is going to do a lot more damage in his spells, and thus be more dangerous. Hence my metric is somewhat justified by a measurement of average damage the spells can deliver. The complete details are in the script, as well as instructions for changing it if you disagree. If we do not find any mage or priest, we always revert to the basicnpc strategy. In all manual target selection, you should always revert to the basicnpc behavior. Even if you think you have every case covered. This means less bugs. Notice how much more complicated this is than *i's. This is something we must always consider when we write these things. We can make them really complicated, but is it worth it? If you need an allied magekiller, then yes. Otherwise, it is less clear. One of the issues in this new script is that we created a new problem that did not occur in *i's script. To see what I mean, put a character with this script in a room and watch what happens when your party enters. More than likely your front line fighter got targetted. HUH? How did that happen after all that work? The problem is your fighter entered the room first, and the bad guy saw him, but did not see the mage. So, he targetted the fighter as an alternative, which is proper behaviour for the script (*i's script does not check line of sight, and so does not have this problem). Unfortunately, the script will not reselect a target until the fighter dies, and you certainly will not let that happen. Hence the mage is never targetted. To solve this problem, we need a script that forces the character to reacquire a target every few rounds. That is what we do in the second mage killer . Notice that if we have a mage, we never stay on it until it is dead. However, if we do not have a mage, we look for one every few rounds. When you play this script, you will discover that this addition makes a big difference. So the moral is that initial assessment is not always as important as continual reassessment. This is something to keep in mind when writing your own targetting AI.
  3. Ok. I am Back I said I would have the next installment in a week. It has been over a week, but real work got in the way. Plus, some of the stuff that I wanted to do turned out to be a lot harder than I thought, or virtually impossible. I have certainly started to discover the boundaries of AvernumScript now. Its nice, but it is missing some very desirable (and simple to implement functions). But more on that later. I have a lot of goodies this week, so I will keep each one to an individual post. As I said last time, this week I planned to play around with target acquisition and combat AI. All of these scripts are for enemies, not for party NPCs. Next week I will implement familiars and pets, and that will address some of Boot's comments at the beginning of this thread. Throughout all of these script postings I will be working with a slightly modified form of basicnpc. The modified script that I am using is available here . What's the difference you ask? I changed the AI for responding to who_hit_me(). If your think about it, there is very little reason to put who_hit_me() after target selection. The only way this will be called if no one is in range, but someone hit you. While possible, this is rare. So, it makes more sense to react to being hit before standard target selection, at least if the target is in within melee range. However, if you do this, you must check that the who_hit_me() character is alive. It is possible that you were hit, but your buddy dispatched him before the script was called. If you do not check for this fact, target acquisition will put you in an infinite loop. I still retain the old code for who_hit_me() after standard target selection. This is for hunting down people who hit you but are now out of range. Anway, the code is not much more complicated than the standard basicnpc, and it will provide the basis for my next several posts.
  4. Quote: Originally written by *i: All right, I've uploaded the magekiller script. I am not trying to disparage your coding skills *i (script looks fine to me and -- more importantly -- it is easy for beginners to read). However, now that I have read your magekiller script I wanted to point out a quick tip to everyone on optimizing code (as scripts can slow the game down). The magekiller script has the following code fragment (UBB forces me to use ~ to represent space indentations): randtarg = get_ran(1,0,1); if (randtarg == 0) { ~~~if (char_with_highest_skill(11) >= 0) { ~~~~~~caster = char_with_highest_skill(11); ~~~} else { ~~~~~~caster = char_with_highest_skill(12); ~~~} } if (randtarg > 0) { ~~~if (char_with_highest_skill(12) >= 0) { ~~~~~~caster = char_with_highest_skill(12); ~~~} else { ~~~~~~caster = char_with_highest_skill(11); ~~~} } This is a lot of branch checking, which can be expensive (especially on Pentiums). Moreover, the second if group looks almost like the first, just with different numbers. Using a little mathematics, you can collapse this to a single if-else statement. randtarg = get_ran(1,0,1); if (char_with_highest_skill(11 + rantarg) >= 0) { ~~~caster = char_with_highest_skill(11 + rantarg); } else { ~~~rantarg = 1 - rantarg; ~~~caster = char_with_highest_skill(11 + rantarg); } Of course, some people may find this a little harder to read (which is a legitimate concern if we are sharing scripts). However, it is more efficient. Edit: And if you really want it tigher, you can edit it down to this. randtarg = get_ran(1,0,1); if (char_with_highest_skill(11 + rantarg) < 0) { ~~~rantarg = 1 - rantarg; } caster = char_with_highest_skill(11 + rantarg);
  5. There probably should be a movement to add some improvements to the editor -- but let's wait until Jeff most of the bugs out of the main program first. Personally, I want a tool that allows me to click on a square and tell me the x,y coordinates of that square. Relying on this "center square" stuff is annoying.
  6. Quote: Originally written by Captain Uglyhead: Would there be any way to tie one monster's effectiveness to another monster? Say you've got this huge, beefed-up magical bodyguard critter that protects a physically frail spellcaster. Would there be any way to suddenly cripple such bodyguard creature(s) if the spellcaster is killed before they are? (the spellcaster is the source of their power- would be explained in plot/dialogue) That can be done with messaging capabilities, but you have to make a script for each. In the DEAD_STATE of the spellcaster, just send a message to the bodyguard, calling a state that drops the bodyguard's stats.
  7. Ah. Much Better. That is what I really wanted to do. Now my phase spiders teleport for real. They get in a hit, and if you manage to hit them back, they teleport to safety. In fact, I used memory cells to define a lot of "safety locations" so that you can have them teleporting all over the place. To fight it out with the spiders, try this one room scenario . Programmers might also want to look at the room to see how I use the memory cells. If you are just interested in the script , here is the source code . For intermediate/low-level programmers, note how I used a lot of different states for combat. There is a defensive webbing state, and a melee attack state. I also have transition states for moving between the two using set_state_continue().
  8. Quote: Originally written by Drakefyre: In that magekiller script, monsters will target characters based on spell-level, which is a more simplistic way of going about it and doesn't take much more into account, but it's still great to have. That's one way to do it, but for such scripts, we should ideally make them as general as possible. Use memory cells to customize priorities such as mage spells, priest spells, missile fire or melee skill. That way, script-shy people can just customize the memory-cell values. At least that is what my next project is.
  9. Quote: Originally written by *i: Actually you can indeed move monsters around and simulate teleportation. Look at the cutscene calls. Ah. That would be the relocate_character() call. Missed that; thanks. Will put out v1.1 of the Phase Spider later to fix that.
  10. Quote: Originally written by Boots: EDIT: Of course, now that I actually read your entire post, I see that next week may deliver just this. Sorry. Actually, I was planning to show how to intelligently assess combatant abilities so that archers don't waste time on the fighters (which select_target() usually returns) when they clearly should be killing the ice lance mage. Or the fighter healing cleric. However, I will see about addressing your concern.
  11. I am way too busy to ever finish a scenario. I would like to believe otherwise, but BoE taught me the reality (and I had a lot of free time then). But I can whip out some pretty cool monster scripts quickly. And since some people might be overwhelmed by the scripting language, I thought that I would make some of my ideas freely available as a public service -- and to have my ideas see the light of day. Feel free to use these in your scenario, as long as my name remains in the credits in the script header. I have a few ideas for some monsters and hope to post one a week. The first one is a monster that I desparately wanted to do in BoE: the phase spider. Unfortunately, I could not do it for two reasons. A monster cannot both web and be invisible. I could not control monster movement to make the spider teleport. Unfortunately, BoA does not allow me 1 or 2 either (you can select a destination for movement, but movement is controlled by the path-finding algorithms, and you cannot teleport non-player creatures) because of very legitimate design decisions on Jeff's part. But that's okay, because with scripts I can fake it. For example, the spiders don't really teleport, I just use effects and cutscene calls to make it look like they do. For those interested, download my arena and try them out. Completing this adventure will not increment your scenarios won or started, so you can experiment safely. Phase Spider Example Next week: Manual combat targetting for user-defined combat AI.
  12. I have been playing around with modifying corescendata.txt in the Avernum files. The reason? In all of the Avernum series (1-3 and now Blades), I have never once seen a spider throw webs. Supposedly they have the ability (cr_special_abil = 5), but I have never, ever seen them use it. Examining the scripts in corescendata.txt I suspect it is because they have the melee AI. So, I wanted to change the default spider behavior to archer/caster, which is what it was in the Exile series (and the reason why spider rooms were some of the most deadly encounters ever). I changed the file and loaded a default game (in VoDT) where I was about to enter a spider room. Nothing happened. Spiders still run into melee, making them boring, flavorless monsters. Now, I know the file is being loaded, because I misspelt cr_default_strategy the first time, and hence it would not process my saved game. After fixing the spelling mistake, the game loaded perfectly. But the changes did not register. So, what's the issue here? Will script changes only load each time you start up a new scenario, with mid-scenario being ignored? Or can we not make global changes in corescendata.txt (Spiders need to be fixed, dammit)?
×
×
  • Create New...