(Animation du jeu COD adaptée pour CODUO)
Tutorial de
Tropheus avec l'aide de Bushman.
Dans ce tutorial vous allez apprendre à
insérer dans vos cartes solos l'animation de la carte Pathfinder
où les soldats allemands jouent aux échecs.
La méthode utilisée ici est très similaire
de celle utilisée pour faire pisser
les personnages.

1/ MAPPING
Créer votre map comme d'habitude. Ensuite
vous allez insérer les différentes entités
que voici :
* 2 Actor/axis toujours
avec un kar car l'animation est faite avec un kar, avec les case
SPAWNER et FORCESPAWN cochées.
model /
xmodel/character_german_wehrmact_officer
classname / actor_axis_wehrmacht_clean_officer_pistol
spawnflags / 3
origin / 144 128 24
targetname / ducon
export / 5
angles / 0 90 0
* 1 node_scripted
qui sera le siège de l'animation. (Les angles du node donnent
la direction de la l'animation)
classname / node_scripted
target / ducon
targetname / chess //
Ici chess est "obligatoire" car sinon il faudrait le
changer dans le script. (allons au plus simple)
origin / 48 16 40
angles / 0 135 0
* 3 Triggers : 2 Trigger_multiple qui seront les
déclencheurs de début et de fin d'animation.
: 1 Trigger_damage qui sera le déclencheur si on tire sur
les joueurs (simulation d'attaque).
Trigger_multiple
1 (Start de l'animation quand le joueur
passe le trigger)
classname /
trigger_multiple
targetname / ducon
target / auto1
Trigger_multiple
2 (Stoppe l'animation quand le joueur passe
le trigger)
classname /
trigger_multiple
targetname / auto1
Trigger_damage
(Stoppe l'animation si on tire dessus)
classname / trigger_damage
targetname / auto1
Pour résumer voici ce que ça donne.

ATTENTION !!!

Screen dans radiant
-
Comme vous pouvez le voir sur les screens et dans le jeu, le soldat
debout s'appuie à un mur alors que l'autre est assis sur
une caisse. Il faut donc que vous trouviez le bon brush dans la
bonne position afin de rendre l'animation crédible.
-
Le second bruh dont vous devez faire attention est celui qui tient
le fusil du soldat assis. là aussi c''est à vous
de trouver la bonne orientation taille etc....
- La
troisième difficulté réside dans le fait
que la caisse sur laquelle repose le jeu n'est pas solide. (on
passe à travers.) Il faut donc que vous tailliez un brush
de la taille de la caisse voire un peu inférieur (20 x
24 x 20) (Longueur x hauteur x largeur). Ce brush vous allez le
texturer avec la texture "clip_wood" que vous trouverez
dans le répertoire "common".

: Pour trouver la bonne position
des brushes je vous conseille d'en créer plusieurs avec
des textures différentes. De les placer sur votre map,
et de voir ce que cela donne dans le jeu et ensuite d'affiner
leur position.
Voici finie la partie mapping.
2/ SCRIPTING
a/ le fichier
ma_map.gsc
main()
{
maps\_load::main();
maps\test_chess_anim::main();
maps\test_chess_anim::props();
//GIVE PLAYER WEAPONS
level.player takeallweapons();
level.player giveWeapon("panzerfaust");
level.player giveWeapon("springfield");
level.player giveWeapon("colt");
level.player giveWeapon("fraggrenade");
level.player switchToWeapon("springfield");
precacheModel("xmodel/chessgame_animrig");
precacheModel("xmodel/holophane_lamp");
precacheModel("xmodel/chessgame_animnode");
precacheModel("xmodel/chessgame_animrig");
thread chess (getnode ("chess","targetname"));
//envoie vers la methode chess avec comme
variable l'entité ayant chess comme targetname.
}
////////////////////////////////
deleter ()
{
self endon ("death");
println ("waiting for soundplayer deletion");
level waittill ("chess interrupted");
println ("deleting soundplayer");
// self stopsound();
self delete();
}
/////////////////////////////////
stopChessSounds ()
{
self endon ("death");
self waittill ("fight");
if (self.chessSounds)
self animscripts\face::SaySpecificDialogue (undefined, "german_enemy_sighted",
1.0);
}
///////////////////////////////////
chessSounds (guy1, guy2)
{
guy1 endon ("death");
guy2 endon ("death");
guy1 endon ("fight");
guy2 endon ("fight");
guy1 thread stopChessSounds();
guy2 thread stopChessSounds();
guy1.chessSounds = false;
guy2.chessSounds = false;
level.chessTalkTrigger waittill ("trigger");
guy1.chessSounds = true;
guy2.chessSounds = true;
println ("^5 TIME TO CHESS TALK");
level endon ("chess interrupted");
guy1 animscripts\face::SaySpecificDialogue (undefined, "Pathfinder_German_Guard1_wonder",
1.0, "sounddone");
guy1 waittill ("sounddone");
guy2 animscripts\face::SaySpecificDialogue (undefined, "Pathfinder_German_Guard2_1sttoknow",
1.0, "sounddone");
guy2 waittill ("sounddone");
guy1 animscripts\face::SaySpecificDialogue (undefined, "Pathfinder_German_Guard1_wrong",
1.0, "sounddone");
guy1 waittill ("sounddone");
guy2 animscripts\face::SaySpecificDialogue (undefined, "Pathfinder_German_Guard2_thepointis",
1.0, "sounddone");
guy2 waittill ("sounddone");
guy1 animscripts\face::SaySpecificDialogue (undefined, "Pathfinder_German_Guard1_sowhat",
1.0, "sounddone");
guy1 waittill ("sounddone");
maps\pathfinder_anim::enableChessSounds();
guy1.chessSounds = false;
guy2.chessSounds = false;
}
chess_leap_deathanim
()
{
self endon ("death");
while (1)
{
self waittill ("single anim", notetrack);
if (notetrack ==
"god mode")
{
// self.allowdeath = false;
props[0] = level.chess_pieces;
// if ((isalive (guy[0])) && (isdefined (guy[0].deathanim)))
thread anim_single (props, "fight", undefined, level.chess_pieces);
continue;
}
if (notetrack !=
"normal death")
continue;
self.allowdeath = true;
self.deathanim = undefined;
// self notify ("stop leaping");
// self.health = 90;
return;
}
}
chessSpecialDeath
(spawn, node)
{
// self endon ("stop leaping");
spawn.allowdeath = true;
// spawn.health = 50000;
spawn waittill ("pain");
// spawn.deathanim = level.scr_anim[spawn.animname]["leap
death"];
anim_single_solo (spawn, "leap death", undefined, node);
spawn DoDamage ( spawn.health + 50, spawn.origin );
}
chess ( node )
{
targets = getentarray (node.target,"targetname");
spawners = [];
for (i=0;i<targets.size;i++)
{
if (targets[i].classname == "trigger_multiple")
{
start_trigger = targets[i];
level.chessTalkTrigger = start_trigger;
stop_triggers = getentarray (start_trigger.target,"targetname");
}
else
spawners[spawners.size] = targets[i];
}
targets = undefined;
spawners[0].animname = "sit";
spawners[1].animname = "stand";
// thread maps\_anim::anim_spawner_teleport (spawners, "move
1", undefined, node);
guy = [];
for (i=0;i<spawners.size;i++)
{
spawners[i].count = 1;
while (1)
{
guy[i] = spawners[i] stalingradspawn();
if (isalive (guy[i]))
break;
else
wait (1);
}
}
for (i=0;i<guy.size;i++)
{
if (!i)
{
guy[i].animname = "sit";
guy[i].deathanim = level.scr_anim[guy[i].animname]["sit death"];
guy[i] thread chess_leap_deathanim();
}
else
{
guy[i].animname = "stand";
guy[i].deathanim = level.scr_anim[guy[i].animname]["death"];
}
guy[i].allowdeath = true;
guy[i].health = 1;
// guy[i] endon ("death");
// guy[i] endon ("pain");
}
thread chessSounds(guy[0], guy[1]);
chess_node = spawn ("script_model",(0,0,0));
chess_node setmodel ("xmodel/chessgame_animnode");
chess_node.origin = node.origin;
chess_node.angles = node.angles;
chess_pieces = spawn ("script_model",(0,0,0));
chess_pieces setmodel ("xmodel/chessgame_animrig");
chess_pieces.animname = "pieces";
chess_pieces.origin = chess_node gettagorigin ("TAG_crate");
chess_pieces.angles = chess_node gettagangles ("TAG_crate");
chess_pieces UseAnimTree(level.scr_animtree[chess_pieces.animname]);
level.chess_pieces = chess_pieces;
level thread chess_think( guy, node, chess_pieces );
array_thread (stop_triggers, ::trigger_stop, start_trigger);
// array_levelthread (guy, ::chess_pain);
level thread chess_radius( guy[0] );
start_trigger waittill ("stop trigger");
newguy = [];
continuer = false;
for (i=0;i<guy.size;i++)
{
if (isalive (guy[i]))
{
// if (guy[i].animname == "sit")
// thread chessSpecialDeath (guy[i], chess_node);
newguy[newguy.size]
= guy[i];
continuer = true;
}
}
if (!continuer)
return;
guy = newguy;
level notify ("chess interrupted");
guy[0] notify ("fight");
anim_single (guy, "fight", undefined, node);
for (i=0;i<guy.size;i++)
{
if (isalive (guy[i]))
{
guy[i].deathanim = undefined;
// guy[i].health = 100;
}
}
}
chess_pain ( ai )
{
ai waittill ("pain");
if (isalive (ai))
ai notify ("end_sequence");
}
chess_radius ( guy
)
{
guy endon ("death");
guy endon ("fight");
while (distance (level.player.origin, guy.origin) > 350)
wait (0.5);
guy notify ("player approaches");
}
chess_think ( guy,
node, chess_pieces )
{
level endon ("chess interrupted");
for (i=0;i<guy.size;i++)
{
guy[i] endon ("death");
guy[i] endon ("pain");
guy[i] endon ("fight");
}
props[0] = chess_pieces;
guy[0] thread anim_loop
( guy, "idle", undefined, "player approaches",
node);
println ("^c 1");
guy[0] waittill ("player approaches");
guy[0] anim_single
(guy, "guard", undefined, node);
props[0] thread
anim_single (props, "move 1", undefined, chess_pieces);
guy[0] anim_single (guy, "move 1", undefined, node);
guy[0] anim_single
(guy, "think 1", undefined, node);
guy[0] anim_single (guy, "think 2", undefined, node);
guy[0] anim_single (guy, "think 1", undefined, node);
guy[0] anim_single (guy, "think 1", undefined, node);
guy[0] anim_single (guy, "think 2", undefined, node);
guy[0] anim_single (guy, "think 1", undefined, node);
guy[0] anim_single (guy, "think 2", undefined, node);
guy[0] anim_single (guy, "think 1", undefined, node);
props[0] thread
anim_single (props, "move 2", undefined, chess_pieces);
guy[0] anim_single (guy, "move 2", undefined, node);
guy[0] anim_single
(guy, "think 1", undefined, node);
guy[0] anim_single (guy, "think 1", undefined, node);
guy[0] anim_single (guy, "think 2", undefined, node);
guy[0] anim_single (guy, "think 1", undefined, node);
props[0] thread
anim_single (props, "move 3", undefined, chess_pieces);
guy[0] anim_single (guy, "move 3", undefined, node);
level anim_loop ( guy, "idle", undefined, "chess
interrupted", node);
}
///////////////////////////////////////
trigger_stop ( trigger )
{
if (self.classname == "trigger_damage")
self enableGrenadeTouchDamage();
self waittill ("trigger");
trigger notify ("stop trigger");
}
//////////////////////////////////////////////////
anim_single (guy, anime, tag, node, tag_entity)
{
maps\_anim::anim_single (guy, anime, tag, node, tag_entity);
}
////////////////////////////
anim_single_solo (guy, anime, tag, node, tag_entity)
{
newguy[0] = guy;
maps\_anim::anim_single (newguy, anime, tag, node, tag_entity);
}
////////////////////////////////
anim_loop ( guy, anime, tag, ender, node, tag_entity )
{
maps\_anim::anim_loop ( guy, anime, tag, ender, node, tag_entity
);
}
//////////////////////////
array_thread (ents, process, var, excluders)
{
maps\_utility::array_thread (ents, process, var, excluders);
}
////////////////////
b/ Le fichier map_map_anim.gsc.
#using_animtree("generic_human");
main()
{
/*
chess animations; // Explications en angalis du fichier jeu pathinder_anim.gsc
play (think) animations on both characters until the player gets
close enough to see them..
play (guard) for the last line of the guards dialogue
play (move1), then (move2), and finally (move3).These need to
be played in order but you can play (think) between them if you
need
to slow it down...
play (think) until the player interupts the seqence...
if (stand) guy is killed play a normal standing death. If he sees
the player or is alerted by the player... play (panic) and he
will move to corner behavior in cover.
if (sit) guy is killed play (death). If he sees the player or
is alerted by the player... play (leap) go for his gun.
chess animations; rig
when the (sit) guy reacts to the player he kicks and moves some
of the props so play the corresponding anim (leap/death)
you will also need to play the corresponding chess piece animations
for the moves (move1,move2,move3)
if this is done correctly the game board will look different based
on when you interupt it and he will still be able to kick the
board at any point in the game...
*/
level.scr_animtree["stand"] =
#animtree;
level.scr_anim["stand"]["fight"] = (%chess_standguy_paniccover);
level.scr_anim["stand"]["move 1"] = (%chess_standguy_move01);
level.scr_anim["stand"]["move 2"] = (%chess_standguy_move02);
level.scr_anim["stand"]["move 3"] = (%chess_standguy_move03);
level.scr_anim["stand"]["idle"][0] = (%chess_standguy_thinkidle);
level.scr_anim["stand"]["idle"][1] = (%chess_standguy_thinktwitch);
level.scr_anim["stand"]["think 1"] = (%chess_standguy_thinkidle);
// level.scrsound["stand"]["think 1"] = "Pathfinder_German_Guard1_hmm";
level.scr_anim["stand"]["think 2"] = (%chess_standguy_thinktwitch);
// level.scrsound["stand"]["think 2"] = "Pathfinder_German_Guard1_hmm";
level.scr_anim["stand"]["guard"] = (%chess_standguy_guard102);
level.scr_anim["stand"]["death"] = (%death_run_left);
level.scr_animtree["sit"] = #animtree;
level.scr_anim["sit"]["sit death"] = (%chess_sitguy_sitdeath);
level.scr_anim["sit"]["leap death"] = (%chess_sitguy_leapingdeath);
level.scr_anim["sit"]["fight"]
= (%chess_sitguy_leapforgun);
level.scr_anim["sit"]["move 1"] = (%chess_sitguy_move01);
// level.scrsound["sit"]["move 1"] = "Pathfinder_German_Guard2_kibitz";
level.scr_anim["sit"]["move 2"] = (%chess_sitguy_move02);
// level.scrsound["sit"]["move 2"] = "Pathfinder_German_Guard2_kibitz";
level.scr_anim["sit"]["move 3"] = (%chess_sitguy_move03);
// level.scrsound["sit"]["move 3"] = "Pathfinder_German_Guard2_kibitz";
level.scr_anim["sit"]["idle"][0] = (%chess_sitguy_thinkidle);
level.scr_anim["sit"]["idle"][1] = (%chess_sitguy_thinktwitch);
level.scr_anim["sit"]["think 1"] = (%chess_sitguy_thinkidle);
level.scr_anim["sit"]["think 2"] = (%chess_sitguy_thinktwitch);
level.scr_anim["sit"]["guard"] = (%chess_sitguy_guard102);
}
///////////////////////////////
enableChessSounds ()
{
level.scrsound["stand"]["think 1"] = "Pathfinder_German_Guard1_hmm";
level.scrsound["stand"]["think 2"] = "Pathfinder_German_Guard1_hmm";
level.scrsound["sit"]["move 1"] = "Pathfinder_German_Guard2_kibitz1";
level.scrsound["sit"]["move 2"] = "Pathfinder_German_Guard2_kibitz2";
level.scrsound["sit"]["move 3"] = "Pathfinder_German_Guard2_kibitz1";
}
#using_animtree("animation_rig_chessgame");
props()
{
level.scr_animtree["pieces"] = #animtree;
level.scr_anim["pieces"]["move
1"] = (%chess_pieces_move01);
level.scr_anim["pieces"]["move 2"] = (%chess_pieces_move02);
level.scr_anim["pieces"]["move 3"] = (%chess_pieces_move03);
level.scr_anim["pieces"]["fight"] = (%chess_props_leapforgun);
level.scr_anim["pieces"]["death"] = (%chess_props_sitdeath);
}
Cette fois-ci pas de fichiers sons à modifier...
Pour télécharger la map test CODUO
seulement, cliquez ici.