Comme promis, voici le script du PNJ qui contrôle la catapulte.
Quelques règles pour faire une bataille navale.
- 2 navires minimums : l'un est destiné à l'ennemi
- 1 PNJ et 1 catapulte, tous deux, faction Hostile sur le bateau ennemi.
- 1 PNJ et 1 catapulte, tous deux, faction Défenseur sur votre bateau.
- Sur les catapultes, placer dans leur OnUsed, le script donné plus haut.
- Sur les PNJ, mettre une variable locale type int "Tireur_Catapulte" de valeur =1
(ceci parce que, pour moi-même, j'ai créé un dialogue avec le PNJ qui me permet de prendre le contrôle de la catapulte ou de le rendre au PNJ).
- Placer le script ci-dessous dans le OnHeartBeat de chaque PNJ qui utilise une catapulte.
- facultatif : placer un levier de sol pour les commandes de la catapulte (le levier n'a pas de réelle utilité pour le PNJ tireur. J'en ai créer un pour effectuer les divers réglages de la catapulte lorsque c'est le PJ qui en prend le contrôle).
Tag de la catapulte : "Catapulte_" + Tag du PNJ
Tag du levier : "Levier_" + Tag de la catapulte.
Fonctionnement basique du script du PNJ
----------------------------------------------------
- Le PNJ cherche un ennemi
- Si ennemi présent : le PNJ règle la catapulte et tire tant que l'ennemi ou lui-même n'est pas mort.
Fonctionnement détaillé :
--------------------------------
Point d"origine de la zone : en bas à gauche
Ce que fait le script lorsqu'un ennemi est présent (j'ai dû ressortir les cours de trigonométrie) :
- Déplacemement du point d'origine de la zone pour le placer sur la catapulte (la catapulte devient donc le nouveau point d'origine de la zone).
- Recherche l'angle formé entre la catapulte et l'ennemi.
- Recherche l'angle formé entre l'ennemi et l'orientation de la catapulte.
- Définir dans quel sens tourner la catapulte
- Definir la distance entre la catapulte, la cible de la catapulte et l'ennemi visé.
- Affecter les commandes à la catapulte pour faire les réglages adéquats et tirer.
Voici le script du PNJ (il est assez lourd)
//////////////////////////////////////
// Tireur de catapulte automatise //
// (C) OF, Dec 2006 //
// //
// v1.2 //
//////////////////////////////////////
//
// A placer dans le OnHeartbeat du PNJ qui controle la catapulte
//
// Condition de fonctionnnement :
//-------------------------------
// - Creer un PNJ et placer ce code dans son OnHeartBeat
// - Dans les proprietes du PNJ, placer une variable locale "Tireur_Catapulte" type int
// - si =0 : le PNJ se ballade aleatoirement (vous pouvez, par exemple, etablir un dialogue avec le PNJ
// - si =1 : le PNJ prend le controle de la catapulte
// - Creer une balliste d'apparence "Catapulte"
// - Tag de la catapulte : "Catapulte_" + Tag du PNJ
// - Placer dans le OnUsed de la catapulte "of_used_catap"
// - Changer la faction de la catapulte et mettre la même que celui du PNJ tireur
//
//Facultatif
//----------
// - Creer un levier au sol pres de la catapulte
// - Tag du levier : "Levier_" + Tag de la catapulte
void ReglerDist(object oCatapulte, object oTireur, float fDistEnnemi)
{
int iDist=abs(FloatToInt(fDistEnnemi));
object oLevier=GetObjectByTag("Levier_"+GetTag(oCatapulte));
float fDelai=0.1;
if (GetLocalInt(oTireur,"Levier")) //Le tireur doit actionner le levier de commandes ?
{//OUI
AssignCommand(oTireur,ActionInteractObject(oLevier)); //Le tireur actionne le levier de commande (ne fait rien si le levier n'existe pas).
fDelai=1.3;
}
DeleteLocalInt(oTireur,"Levier"); //Le tireur n'est plus autorise a utiliser le levier de commandes.
//Definir la valeur du reglage
SetLocalFloat(oCatapulte,"Reglage",1.0); //Defaut
if (iDist>1) SetLocalFloat(oCatapulte,"Reglage",1.0);
if (iDist>5) SetLocalFloat(oCatapulte,"Reglage",5.0);
if (iDist>10) SetLocalFloat(oCatapulte,"Reglage",10.0);
DelayCommand(fDelai,AssignCommand(oTireur,ActionInteractObject(oCatapulte))); //Le tireur actionne la catapulte
DelayCommand(fDelai+0.3,SpeakString("La catapulte est réglée sur "+FloatToString(GetLocalFloat(oCatapulte,"DistCible"),3,0)+" mètres."));
}
void ReglerOrient(object oCatapulte, object oTireur, float fOrientEnnemi)
{
object oLevier=GetObjectByTag("Levier_"+GetTag(oCatapulte));
float fDelai=0.1;
if (GetLocalInt(oTireur,"Levier")) //Le tireur doit actionner le levier de commandes ?
{//OUI
AssignCommand(oTireur,ActionInteractObject(oLevier)); //Le tireur actionne le levier de commande
fDelai=1.3;
}
DeleteLocalInt(oTireur,"Levier"); //Le tireur n'est plus autorise a utiliser le levier de commandes.
int iDiffAng=abs(FloatToInt(fOrientEnnemi-GetFacing(oCatapulte)));
//Definir la valeur de l'angle de reglage
SetLocalFloat(oCatapulte,"Reglage",1.0);
if (iDiffAng>1) SetLocalFloat(oCatapulte,"Reglage",1.0);
if (iDiffAng>5) SetLocalFloat(oCatapulte,"Reglage",5.0);
if (iDiffAng>10) SetLocalFloat(oCatapulte,"Reglage",10.0);
DelayCommand(fDelai,AssignCommand(oTireur,ActionInteractObject(oCatapulte))); //Le tireur actionne la catapulte
DelayCommand(fDelai+0.3,SpeakString("Angle de tir : "+FloatToString(GetFacing(oCatapulte),3,0)+" degrés."));
}
void main()
{
//ExecuteScript("nw_c2_default1", OBJECT_SELF);
//Placer des // sur les 2 lignes suivantes pour que le PNJ soit le seul a utiliser la catapulte.
if ( (!GetLocalInt(OBJECT_SELF,"Tireur_Catapulte")) || (!IsInConversation(OBJECT_SELF)) ) ActionRandomWalk();
if ( (!GetLocalInt(OBJECT_SELF,"Tireur_Catapulte")) || (IsInConversation(OBJECT_SELF)) ) return;
ClearAllActions();
object oEnnemiCible=GetLocalObject(OBJECT_SELF,"EnnemiCible");
object oArea=GetArea(OBJECT_SELF);
object oCatapulte=GetObjectByTag("Catapulte_"+GetTag(OBJECT_SELF));
object oLevier=GetObjectByTag("Levier_"+GetTag(oCatapulte));
float fDelai=0.1;
float fDistEnnemi=500.0;
if (GetLocalFloat(OBJECT_SELF,"DistEnnemi")<=10.0) SetLocalFloat(OBJECT_SELF,"DistEnnemi",fDistEnnemi);
//Recherche d'un ennemi
if (oEnnemiCible==OBJECT_INVALID)
{//Le PNJ n'a pas encore identifie un ennemi, il en cherche un
object oEnnemi=GetFirstObjectInArea(oArea);
while (oEnnemi!=OBJECT_INVALID || oEnnemiCible!=OBJECT_INVALID)
{
if (GetObjectType(oEnnemi)==OBJECT_TYPE_CREATURE)
{
if ( (GetIsEnemy(oEnnemi, OBJECT_SELF)) && (oEnnemiCible==OBJECT_INVALID) || ( ((oEnnemiCible!=OBJECT_INVALID) && (fDistEnnemi<GetDistanceBetween(OBJECT_SELF, oEnnemi))) ) )
{
SetLocalObject(OBJECT_SELF,"EnnemiCible",oEnnemi); //Ennemi identifie.
SetLocalFloat(OBJECT_SELF,"DistEnnemi",GetDistanceBetween(OBJECT_SELF, oEnnemi));
SpeakString("Navire ennemi en vue ! Je vais régler la catapulte.");
}
}
oEnnemi=GetNextObjectInArea(oArea);
}
} else
{//Le PNJ a deja un ennemi. Verifie s'il est mort.
if (GetIsDead(oEnnemiCible)) DeleteLocalObject(OBJECT_SELF,"EnnemiCible"); //L'ennemi est mort : preparation pour en chercher un autre
else
{//L'ennemi est encore vivant : verifie que la catapulte le vise.
float fDistVisee=GetLocalFloat(oCatapulte,"DistCible"); //Distance du tir actuellement règle
if (fDistVisee<10.0) fDistVisee=10.0;
SetLocalFloat(oCatapulte,"DistCible",fDistVisee);
float fDistCible=GetDistanceBetween(oCatapulte, oEnnemiCible); //Distance entre ennemi et catapulte
fDistEnnemi=fDistCible-fDistVisee; //Distance entre ennemi et reglage de la cible de la catapulte
vector vEnnemi=GetPositionFromLocation(GetLocation(oEnnemiCible)); //Position de l'ennemi sur la carte
vector vCatapulte=GetPositionFromLocation(GetLocation(oCatapulte)); //Position de la catapulte sur la carte
//Origine de la carte : point en bas a gauche.
//float fOrigineX=vCatapulte.x; //Deplacement d'absysse vers la catapulte
//float fOrigineY=vCatapulte.y; //Deplacement d'ordonnee vers la catapulte
//Deplacement du point d'origine de la zone (en bas a gauche) pour le placer sur la catapulte.
float fEnnemiX=vEnnemi.x-vCatapulte.x; //Absysse de la cible par rapport a la catapulte
float fEnnemiY=vEnnemi.y-vCatapulte.y; //Ordonnee de la cible par rapport a la catapulte
float fCorrAngle=8.0; //Valeur de la correction de l'erreur d'orientation
if (fDistCible>37.0) fCorrAngle=fCorrAngle/2.0; //nouvelle correction en fonction de la distance de la cible.
float fOrientEnnemi=VectorToAngle(Vector(fEnnemiX*cos(fDistCible), fEnnemiY*sin(fDistCible),0.0)); //Calcul de l'angle forme par la cible par rapport a la catapulte
//Correction de l'angle de tir (bizarrement la catapulte tir a cote de la cible. Le code ci-dessus permet de remedier au probleme).
if ( ((fOrientEnnemi>=0.0) && (fOrientEnnemi<=90.0)) || ((fOrientEnnemi>=180.0) && (fOrientEnnemi<=270.0)) )
{
fOrientEnnemi=fOrientEnnemi+fCorrAngle;
//SendMessageToPC(GetFirstPC(),GetName(OBJECT_SELF)+" / Correction d'angle +"+FloatToString(fCorrAngle,3,0)+"."); //Debug
}
else
if ( ((fOrientEnnemi>=270.0) && (fOrientEnnemi<=360.0)) || ((fOrientEnnemi>=90.0) && (fOrientEnnemi<=180.0)) )
{
fOrientEnnemi=fOrientEnnemi-fCorrAngle;
//SendMessageToPC(GetFirstPC(),GetName(OBJECT_SELF)+" / Correction d'angle +"+FloatToString(fCorrAngle,3,0)+"."); //Debug
}
float fAngle=fOrientEnnemi-GetFacing(oCatapulte); //Angle entre orientation (et la position par rapport a l'ennemi) de la catapulte et l'ennemi
int CmdCatap; //Commande de la catapulte
CmdCatap=0; //Charger/Tirer par defaut.
//Reglage distance avec une petite marge pour que le tireur evite de regler la distance indefiniement.
if (fDistEnnemi>=0.0) { if (fDistEnnemi>=(IntToFloat(Random(300))/100)) CmdCatap=3; }
if (fDistEnnemi<=0.0) { if (-fDistEnnemi>=(IntToFloat(Random(300))/100)) CmdCatap=4; }
//Reglage orientation
if (abs(FloatToInt(fAngle))>=Random(5)) //Marge de reglage : evite que le PNJ règle indefiniement la catapulte
{
if (fAngle>=0.0)
{ if (fAngle<=180.0) CmdCatap=2; else CmdCatap=1; }
else
{ if (fAngle<=-180.0) CmdCatap=2; else CmdCatap=1; }
}
//SendMessageToPC(GetFirstPC(),GetName(OBJECT_SELF)+" / - Angle entre catap et ennemi : / "+FloatToString(fOrientEnnemi-GetFacing(oCatapulte),3,0)+"/"); //Debug
//Actions du tireur
switch(CmdCatap)
{
case 1:
{//Tourner a droite
if (GetLocalInt(oCatapulte,"Commande")!=1) SetLocalInt(OBJECT_SELF,"Levier",1);
SetLocalInt(oCatapulte,"Commande",1);
ReglerOrient(oCatapulte, OBJECT_SELF, fOrientEnnemi);
break;
}
case 2:
{//Tourner a gauche
if (GetLocalInt(oCatapulte,"Commande")!=2) SetLocalInt(OBJECT_SELF,"Levier",1);
SetLocalInt(oCatapulte,"Commande",2);
ReglerOrient(oCatapulte, OBJECT_SELF, fOrientEnnemi);
break;
}
case 3:
{//Viser plus loin
if (GetLocalInt(oCatapulte,"Commande")!=3) SetLocalInt(OBJECT_SELF,"Levier",1);
SetLocalInt(oCatapulte,"Commande",3);
ReglerDist(oCatapulte,OBJECT_SELF,fDistEnnemi);
break;
}
case 4:
{//Viser plus pres
if (GetLocalInt(oCatapulte,"Commande")!=4) SetLocalInt(OBJECT_SELF,"Levier",1);
SetLocalInt(oCatapulte,"Commande",4);
ReglerDist(oCatapulte,OBJECT_SELF,fDistEnnemi);
break;
}
default:
{//Charger la catapulte / Tirer sur l'ennemi
if (GetLocalInt(oCatapulte,"Commande")!=0) SetLocalInt(OBJECT_SELF,"Levier",1);
if (GetLocalInt(OBJECT_SELF,"Levier"))
{
AssignCommand(OBJECT_SELF,ActionInteractObject(oLevier));
fDelai=1.3;
}
DeleteLocalInt(OBJECT_SELF,"Levier");
SetLocalInt(oCatapulte,"Commande",0);
DelayCommand(fDelai, AssignCommand(OBJECT_SELF,ActionInteractObject(oCatapulte)));
break;
}
}
}
}
}