was going to post this in a dead thread didnt think anyone would answer...
i need to know how i can setup an instant .dll to first use the correct AIP plans i set for it depending on difficulty chosen and also the races...
and of course, spawn the correct units and monitor recyclers etc..
after that my other modifications should be easy =]... its just the initial setup that is difficult...
ill be using the bzi scriptor btw... not fluent in anything else =[
The closest thing I've got to what you want would be my BZ2 Bench Test. You can get the script at: http://www.starfleetplatoon.com/users/sonic/bz2/dll_scripts/bz2benchtest.bzs
While it doesn't use AIPs, you can see how I grabed variables to decide what units to attack with, for both teams. I believe you can get the full map and stuff from bzscrap.
Well, my discussions with Natty over the years has given me a fairly decent understanding of how the DLL should work...
To select an AIP, certain conditions have to be met. The standard naming convention for AIPs covers several stages of gameplay, from base building to initial attacks, to late game attacks, to 'siege mode'.
Now, in Natty's case the conditions are simple. All he does is have the DLL determine:
"What is the meanest thing the AI could do when the player does ________?"
So, getting too far from your base triggers the 'crush them completely' AIP. Holing up in your base, otoh, triggers the 'death of 1000 archers' routine...
See?
So basically you'd determine conditions by doing things like watching the distance of the player from his Recy, the distance of the Player to the AI Recy, how many GT's he's got vs Turrets, that sort of thing.
-Av-
the difficult bit really is getting the .dll to take the shell information when you select a map/race/AIP level
its for instant games, so if i decide i want to play as the scion against the AAN on a diffucult match, i ned it to spawn fvrecycpu, avrecy, avscout and fvscout probabaly...
Hehe, Avatar just reminded me what I ran into when I was modifying the MPI source code the other day under taunts.cpp...
"OK Natty, now what do I do?",
Conditions can be rather simple to do, just have a routine that runs checking various things like the distance of the nereast human controled unit to the enemy recycler. If its below 250, switch AIP to anti-siege. Or you could monitor the Enemy Recycler's health, if it gets below a certain value, switch plans and suprise the players.
I wrote up a quick Scriptor script (may have errors) that mimics somewhat the instant.dll with AIPs. Its just basic, you will have to do a good amount of editing to take in account races and what not, but it should get you started:
[routine,AIPExample,1,true]
SetPlan,"startup.aip",6
Wait,180
SETPLAN:
ConsoleWord,"Anti-Siege Off"
Set,SiegeCount,0
RandJump,PLAN2,PLAN3 // Randomly select a 'normal' plan
PLAN1:
SetPlan,"plan1.aip",6
GoTo,ENDSETPLAN
PLAN2:
SetPlan,"plan2.aip",6
GoTo,ENDSETPLAN
PLAN3:
SetPlan,"plan3.aip",6
ENDSETPLAN:
Wait,1
NearEnemy,human,EnemyRecycler
IsODF,human,"ivscav" // We don't care about scavengers
IfEQ,true,ENDSETPLAN
DistObject,human,EnemyRecycler
IfGT,250,RESETSIEGE
Add,SiegeCount,1
IfGT,45,ANTISIEGE // If a human has been nearby for about 45 seconds, kick Anti-Siege on
GoTo,ENDSETPLAN
RESETSIEGE:
Set,SiegeCount,0 // Zero out Counter
GoTo,ENDSETPLAN
ANTISIEGE:
ConsoleWord,"Anti-Siege Mode Initilized"
SetPlan,"antisiege.aip",6
CHECKSIEGE:
Wait,120 // Check Conditions every 2 minutes
NearEnemy,human,EnemyRecycler
DistObject,human,EnemyRecycler
IfGT,250,SETPLAN // Turn Anti-Siege Off
GoTo,CHECKSIEGE
Personally though, I like doing this stuff in C++ now...it can get alot more evil. >:D
// Check Enemy Recycler, when health reaches certain points do stuff
// Not recomended for games with Sanity installed...
void instantMission::RecyclerDefense()
{
float RecyRatioH=GetHealth(enemy_recycler);
Handle hTemp;
Vector NewPos;
int i;
// Discharge Defense if Recycler takes enough damage
if((bPkKiller) && (RecyRatioH < 0.75f)) {
bPkKiller=false;
SendPKs(true,true);
NewPos=GetPositionNear(EnemyRecyPos,20.0f,30.0f);
hTemp=BuildStartingVehicle(comp_team,CPUTeamRace,"*vservcpu","*vserv",NewPos);
Service(hTemp,enemy_recycler);
AddScrap(comp_team,30);
}
if((bSpiceDefense) && (RecyRatioH < 0.5f)) {
bSpiceDefense=false;
last_spiceattack=turn_counter;
SendLacourSpices(true);
for(i=0;i<3;i++) { // Create Service Trucks and heal
NewPos=GetPositionNear(EnemyRecyPos,20.0f,30.0f);
hTemp=BuildStartingVehicle(comp_team,CPUTeamRace,"*vservcpu","*vserv",NewPos);
SetMaxHealth(hTemp,21000); // Make it not easy to blow these guys up
SetCurHealth(hTemp,21000);
Service(hTemp,enemy_recycler);
}
if(bReinforcements)
Reinforcements(false);
if(mySide==1) // Make more of a distraction to get 'em off our backs!
FuryRun();
else
SiegeTankRun();
AddScrap(comp_team,60);
AddHealth(enemy_recycler,3000); // Damnit! Seriously, who sealed the Nine Tails inside their Recycler?
}
if((bFinalLineofDefense) && (RecyRatioH < 0.15f)) { //Oh mighty Cursix, HELP ME!
bFinalLineofDefense=false; // Note, we get more than one now! >:D
last_finalline=turn_counter;
DoTaunt(TAUNTS_FinalLine);
PrintConsoleMessage("ATTENTION: Final Line of Defense has been breached!");
if(bReinforcements) // Only because if it was off, count would be 1, meaning they would SUCK!
Reinforcements(false);
SendPKs(true,false);
SendLacourSpices(false);
if(mySide==1)
FuryRun();
else
SiegeTankRun();
AddHealth(enemy_recycler,21000); // Hey, who gave the CPU access to the Support Symbology Package?
// All Evil Credit goes to CmptrWz.
Handle hndPlayer;
Vector hisSpeed;
float rnd=GetRandomFloat(1.0f);
for(i=0; i<MAX_TEAMS; i++) {
hndPlayer=GetPlayerHandle(i);
if(hndPlayer) {
if(GetTeamNum(hndPlayer) != strat_team) {
// We have a Player! Screw with them!
if((!IsPerson(hndPlayer)) && (rnd > 0.5f)) // About 50% chance that player ejects
EjectPilot(hndPlayer);
// OK, so this part was my idea -Sonic
hndPlayer=GetPlayerHandle(i); // Re-Grab Player as they may have ejected
if(hndPlayer && IsAround(hndPlayer)) { // Make sure we have an object
hisSpeed=GetVelocity(hndPlayer);
hisSpeed.x-=111.1f;
hisSpeed.y+=150.0f;
hisSpeed.z+=333.3f;
SetVelocity(hndPlayer,hisSpeed); // How high will they go?
}
}
}
}
// Drop a service truck and let it service what needs serviced
NewPos=GetPositionNear(EnemyRecyPos,25.0f,30.0f);
hTemp=BuildStartingVehicle(comp_team,CPUTeamRace,"*vservcpu","*vserv",NewPos);
SetMaxHealth(hTemp,21000);
SetCurHealth(hTemp,21000);
// We're most likely thristy at this point, lets have a drink!
AddScrap(strat_team,-120);
AddScrap(comp_team,120);
}
// Recharge Defense if Recycler Heals Enough
if((!bPkKiller) && (RecyRatioH > 0.95f))
bPkKiller=true;
if((!bSpiceDefense) && (RecyRatioH > 0.7f) && (turn_counter > (last_spiceattack + (180 * m_GameTPS))))
bSpiceDefense=true;
// We Recharge Final Line of Defense 15 Minutes after it was triggered last
if((!bFinalLineofDefense) && (turn_counter > (last_finalline + (900 * m_GameTPS))))
bFinalLineofDefense=true;
}
-120 scrap to the human team if the AI recy is less then 15% health, the frick?
When the humans have insane custom assets including but not limited to a Recycler with 80 scrap storage, I think the AI needs a break. ;)
I think the heart of what Jamsh is asking is something I've asked before and never gotten an answer to...
How can a Scriptor-made DLL read the buttons selected at the start of a match?
In my case I wanted to find out if the Scriptor could read the Game Difficulty setting, so I could adjust for Easy/Medium/Hard settings.
Never did figure out how to do that...
-Av-
thats exactly it... conditions i can do... getting it to read the setup information i cant get it to do...
lizard added a new .dll to his fleshstorm mod i think which enabled you to pick the races in match much like fe for 1.2
Quote from: Avatar on December 29, 2007, 05:47:14 AM
I think the heart of what Jamsh is asking is something I've asked before and never gotten an answer to...
How can a Scriptor-made DLL read the buttons selected at the start of a match?
In my case I wanted to find out if the Scriptor could read the Game Difficulty setting, so I could adjust for Easy/Medium/Hard settings.
Never did figure out how to do that...
-Av-
I never figured that out either, it may be one of the limitations of the scriptor, there's nothing to stop you having a popup panel that appears once you launch the mission with options on it like in FleshStorm, FE and even G66, you can pretty much have any options you like on one of those from difficulty settings to race selections and a whole lot more besides.
You should be able to grab information from the shell before launch if the shell stores things in the right place. You would grab the information the same way I did in the bench test.
IFaceGetInt,"options.instant.int1"
StoreResult,Difficulty
...
Add,Difficulty,0
IfEQ,0,EASY
IfEQ,1,MEDIUM
IfEQ,2,HARD
EASY:
...
GoTo,ENDDIFFICULTY
MEDIUM:
...
GoTo,ENDDIFFICULTY
HARD:
...
ENDDIFFICULTY:
...
Is that actual code? (other than 'goto' needs to be 'jumpto') To determine difficulty? That would be awesome, although it would also probably make me go back and redo all of the BZC Scripts... :)
It would be worth it, though, to be able to select the mission difficulty. It's such a tough thing making a decent mission given how wide a range of players there are.
***
Trying it I guess it's not complete... it comes up 'easy' no matter what I select.
So, it's an example... how do we find out the actual iface entry to look for? When I pull up options the console spams 'page 0' and 'selected 0'... not sure what that means.
We're very close, so thanks for the nudge in the right direction... now to nail it down to the actual entry...
***
Looking over BZESCAPE_PLAY.CFG I find:
//Easy
UseVar("options.play.difficulty");
Value(0);
//Medium
Value(1);
//Hard
Value(2);
Off to try that...
***
YEEEEHA!
Good thing Sonic's not here 'cause I'd kiss him right on the lips... :roll:
Here you go, the code to read the selected difficulty:
DoAgain:
IFaceGetInt,"options.play.difficulty"
StoreResult,Difficulty
Add,Difficulty,0
IfEQ,0,EASY
IfEQ,1,MEDIUM
IfEQ,2,HARD
EASY:
ConsoleWord,"Easy"
JumpTo,ENDDIFFICULTY
MEDIUM:
ConsoleWord,"Medium"
JumpTo,ENDDIFFICULTY
HARD:
ConsoleWord,"Hard"
ENDDIFFICULTY:
Wait,3
Jumpto,DoAgain
The jumpto,doagain bit is just for testing, so I can watch it. Awesome... this explains a lot, and now pretty much any difficulty setting can be read by a Scriptor-built script.
That's been bugging me for years, literally.
Thanks, Sonic! Very cool...
-Av-
very good!
now we jsut need to get it to read race type, AIP plans player respawn and the like and volia lol!
Yea, the options.instant.int1 was just an example you could use if you made your own CFG for your instant map. Glad I could be of help.
Racetype works JUST LIKE DIFFICULTY!!! :-D
I'm gonna use the My .cfg (which is bassed off of the FE chaos maps.cfg, yes, i cant remember the name of the exact .cfg) as an example (based off of Av's one as im too lazy to pull up the real one):
DoOnce:
IFaceGetInt,"race1.count"
StoreResult,race_player
Add,race_player,0
IfEQ,0,ISDF
IfEQ,1,HADEAN
IfEQ,2,RODIAN
EASY:
ConsoleWord,"ISDF in Battle"
JumpTo,ENDDIFFICULTY
MEDIUM:
ConsoleWord,"Hadean in Battle"
JumpTo,ENDDIFFICULTY
HARD:
ConsoleWord,"Rodian in Battle"
ENDDIFFICULTY:
Wait,3
Jumpto,DoAgain
DoAgain:
IFaceGetInt,"race2.count"
StoreResult,race_cpu
Add,race_cpu,0
IfEQ,0,ISDF
IfEQ,1,HADEAN
IfEQ,2,RODIAN
EASY:
ConsoleWord,"ISDF in Battle"
JumpTo,ENDDIFFICULTY
MEDIUM:
ConsoleWord,"Hadean in Battle"
JumpTo,ENDDIFFICULTY
HARD:
ConsoleWord,"Rodian in Battle"
ENDDIFFICULTY:
Wait,3
Jumpto,Setup_player
Setup_player:
//inset your spawning lines here according to race selection
Setup_cpu:
//again, place lines here.
That is basically how thats done.
Very cool... :)
I personally am shooting for NOT using an in game console, as I'd rather just use whatever the player's normal settings are. Then again I don't need anything much extra for the stock races.
The 'Ancients', OTOH, might need some unusual options set... then there's a few options for MP that I haven't dealt with such as the game ending when a life limit is reached...
-Av-
im aiming for the same as avatar, No in game console...
"options.instant.<bla>" is used for Instant Action Missions while "network.session.<blah>" is used for Multiplayer. IA maps are easy when it comes to variables, however, multiplayer variables require that the variable is the same on both sides. An interesting thing I noticed was network.session.svar60 was not traversing the network. So while the host saw svar60 as "blah", the clients saw it as "" which caused rsyncs when ever the DLL evaluated what svar60 was. Because of this, it probobly is a good pratice in 1.3 to do all your variables in the BZ2 shell BEFORE the game launch instead of launching a shell in game.
Or just have the host dll send it to the client dll's so they all stay in sync fine that way, just need to take into account network delay.
BZ2 doesn't propagate svar/ivar changes after the game starts.
-- GSH
Functions were added in one of the earlier 1.3pb dll's that allow the host to send information to a client. Just make sure to take into account latency so everything stays perfectly timed, and so forth...