Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
•All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
comm_ai.cpp
Go to the documentation of this file.
1 #include "comm_ai.h"
2 #include "faction_generic.h"
3 #include "communication.h"
4 #include "cmd/collection.h"
5 #include "gfx/cockpit_generic.h"
6 #include "cmd/images.h"
7 #include "configxml.h"
8 #include "vs_globals.h"
10 #include "cmd/unit_util.h"
11 #include "vs_random.h"
12 #include "cmd/unit_find.h"
13 #include "cmd/pilot.h"
14 #include "universe_util.h"
15 
17  int stype,
18  float mood,
19  float anger,
20  float appeas,
21  float moodswingyness,
22  float randomresp ) : Order( ttype, stype )
23  , anger( anger )
24  , appease( appeas )
25  , moodswingyness( moodswingyness )
26  , randomresponse( randomresp )
27  , mood( mood )
28 {
29  if (appease > 665 && appease < 667) {
30  static float appeas = XMLSupport::parse_float( vs_config->getVariable( "AI", "EaseToAppease", ".5" ) );
31  this->appease = appeas;
32  }
33  if ( (anger > 665 && anger < 667) || (anger > -667 && anger < -665) ) {
34  static float ang = XMLSupport::parse_float( vs_config->getVariable( "AI", "EaseToAnger", "-.5" ) );
35  this->anger = ang;
36  }
37  if (moodswingyness > 665 && moodswingyness < 667) {
38  static float ang1 = XMLSupport::parse_float( vs_config->getVariable( "AI", "MoodSwingLevel", ".2" ) );
39  this->moodswingyness = ang1;
40  }
41  if (randomresp > 665 && moodswingyness < 667) {
42  static float ang2 = XMLSupport::parse_float( vs_config->getVariable( "AI", "RandomResponseRange", ".8" ) );
43  this->randomresponse = ang2;
44  }
45 }
46 
47 bool MatchingMood( const CommunicationMessage &c, float mood, float randomresponse, float relationship )
48 {
49  static float pos_limit = XMLSupport::parse_float( vs_config->getVariable( "AI",
50  "LowestPositiveCommChoice",
51  "0" ) );
52  static float neg_limit = XMLSupport::parse_float( vs_config->getVariable( "AI",
53  "LowestNegativeCommChoice",
54  "-.00001" ) );
55  const FSM::Node *n = (unsigned int) c.curstate
56  < c.fsm->nodes.size() ? (&c.fsm->nodes[c.curstate]) : (&c.fsm->nodes[c.fsm->getDefaultState(
57  relationship )]);
58  std::vector< unsigned int >::const_iterator iend = n->edges.end();
59  for (std::vector< unsigned int >::const_iterator i = n->edges.begin(); i != iend; ++i) {
60  if (c.fsm->nodes[*i].messagedelta >= pos_limit && relationship >= 0)
61  return true;
62  if (c.fsm->nodes[*i].messagedelta <= neg_limit && relationship < 0)
63  return true;
64  }
65  return false;
66 }
67 
69 {
70  Unit *targ = c.sender.GetUnit();
71  float relationship = 0;
72  if (targ) {
73  relationship = parent->pilot->GetEffectiveRelationship( parent, targ );
74  if (targ == parent->Target() && relationship > -1.0)
75  relationship = -1.0;
76  mood += (1-randomresponse)*relationship;
77  }
78  //breaks stuff
79  if ( ( c.curstate >= c.fsm->GetUnDockNode() ) || !MatchingMood( c, mood, randomresponse, relationship ) )
80  c.curstate = c.fsm->getDefaultState( relationship ); //hijack the current state
81  return c.fsm->getCommMessageMood( c.curstate, mood, randomresponse, relationship );
82 }
83 
84 using std::pair;
85 
86 void GetMadAt( Unit *un, Unit *parent, int numhits = 0 )
87 {
88  if (numhits == 0) {
89  static int snumhits = XMLSupport::parse_int( vs_config->getVariable( "AI", "ContrabandMadness", "5" ) );
90  numhits = snumhits;
91  }
92  CommunicationMessage hit( un, parent, NULL, 0 );
93  hit.SetCurrentState( hit.fsm->GetHitNode(), NULL, 0 );
94  for (int i = 0; i < numhits; i++)
95  parent->getAIState()->Communicate( hit );
96 }
97 
99 {
100  Unit *ally;
101  static float contraband_assist_range =
102  XMLSupport::parse_float( vs_config->getVariable( "physics", "contraband_assist_range", "50000" ) );
103  float relation = 0;
104  static float minrel = XMLSupport::parse_float( vs_config->getVariable( "AI", "max_faction_contraband_relation", "-.05" ) );
105  static float adj = XMLSupport::parse_float( vs_config->getVariable( "AI", "faction_contraband_relation_adjust", "-.025" ) );
106  float delta;
107  int cp = _Universe->whichPlayerStarship( un );
108  if (cp != -1) {
109  if ( ( relation = UnitUtil::getRelationFromFaction( un, faction ) ) > minrel )
110  delta = minrel-relation;
111  else
112  delta = adj;
113  UniverseUtil::adjustRelationModifierInt( cp, faction, delta );
114  }
116  (ally = *i) != NULL;
117  ++i)
118  //Vector loc;
119  if (ally->faction == faction) {
120  if ( ( ally->Position()-un->Position() ).Magnitude() < contraband_assist_range ) {
121  GetMadAt( un, ally );
122  Flightgroup *fg = ally->getFlightgroup();
123  if (fg) {
124  if ( fg->directive.empty() ? true : toupper( *fg->directive.begin() ) != *fg->directive.begin() ) {
125  ally->Target( un );
126  ally->TargetTurret( un );
127  } else {
128  ally->Target( un );
129  ally->TargetTurret( un );
130  }
131  }
132  }
133  }
134  //}
135 }
136 
137 void CommunicatingAI::TerminateContrabandSearch( bool contraband_detected )
138 {
139  //reports success or failure
140  Unit *un;
141  unsigned char gender;
142  std::vector< Animation* > *comm_face = parent->pilot->getCommFaces( gender );
143  if ( ( un = contraband_searchee.GetUnit() ) ) {
144  CommunicationMessage c( parent, un, comm_face, gender );
145  if (contraband_detected) {
146  c.SetCurrentState( c.fsm->GetContrabandDetectedNode(), comm_face, gender );
147  GetMadAt( un, 0 );
149  } else {
150  c.SetCurrentState( c.fsm->GetContrabandUnDetectedNode(), comm_face, gender );
151  }
152  Order *o = un->getAIState();
153  if (o)
154  o->Communicate( c );
155  }
157 }
158 
159 void CommunicatingAI::GetMadAt( Unit *un, int numHitsPerContrabandFail )
160 {
161  ::GetMadAt( un, parent, numHitsPerContrabandFail );
162 }
163 
164 static int InList( std::string item, Unit *un )
165 {
166  float numcontr = 0;
167  if (un) {
168  for (unsigned int i = 0; i < un->numCargo(); i++)
169  if (un->GetCargo( i ).content == item)
170  if (un->GetCargo( i ).quantity > 0)
171  numcontr++;
172  }
173  return float_to_int( numcontr );
174 }
175 
177 {
178  static unsigned int contraband_search_batch_update =
179  XMLSupport::parse_int( vs_config->getVariable( "AI", "num_contraband_scans_per_search", "10" ) );
180  for (unsigned int rep = 0; rep < contraband_search_batch_update; ++rep) {
182  if ( u && (u->faction != parent->faction) ) {
183  //don't scan your buddies
184  if ( which_cargo_item < (int) u->numCargo() ) {
185  if (u->GetCargo( which_cargo_item ).quantity > 0) {
186  int which_carg_item_bak = which_cargo_item;
187  std::string item = u->GetManifest( which_cargo_item++, parent, SpeedAndCourse );
188  static bool use_hidden_cargo_space =
189  XMLSupport::parse_bool( vs_config->getVariable( "physics", "use_hidden_cargo_space", "true" ) );
190  static float speed_course_change =
191  XMLSupport::parse_float( vs_config->getVariable( "AI", "PercentageSpeedChangeToStopSearch", "1" ) );
192  if (u->CourseDeviation( SpeedAndCourse, u->GetVelocity() ) > speed_course_change) {
193  unsigned char gender;
194  std::vector< Animation* > *comm_face = parent->pilot->getCommFaces( gender );
195  CommunicationMessage c( parent, u, comm_face, gender );
196  c.SetCurrentState( c.fsm->GetContrabandWobblyNode(), comm_face, gender );
197  Order *o;
198  if ( ( o = u->getAIState() ) )
199  o->Communicate( c );
200  GetMadAt( u, 1 );
202  }
203  float HiddenTotal = use_hidden_cargo_space ? ( u->getHiddenCargoVolume() ) : (0);
204  Unit *contrabandlist = FactionUtil::GetContraband( parent->faction );
205  if (InList( item, contrabandlist ) > 0) {
206  //inlist now returns an integer so that we can do this at all...
207  if (HiddenTotal == 0 || u->GetCargo( which_carg_item_bak ).quantity > HiddenTotal) {
208  TerminateContrabandSearch( true ); //BUCO this is where we want to check against free hidden cargo space.
209  } else {
210  unsigned int max = u->numCargo();
211  unsigned int quantity = 0;
212  for (unsigned int i = 0; i < max; ++i)
213  if (InList( u->GetCargo( i ).content, contrabandlist ) > 0) {
214  quantity += u->GetCargo( i ).quantity;
215  if (quantity > HiddenTotal) {
217  break;
218  }
219  }
220  }
221  }
222  } else {
223  TerminateContrabandSearch( false );
224  }
225  }
226  }
227  }
228 }
229 
230 static bool isDockedAtAll( Unit *un )
231 {
232  return ( un->docked&(Unit::DOCKED_INSIDE|Unit::DOCKED) ) != 0;
233 }
234 
236 {
237  for (unsigned int i = 0; i < _Universe->numPlayers(); ++i) {
238  Unit *target = _Universe->AccessCockpit( i )->GetParent();
239  if (target) {
240  FSM *fsm = FactionUtil::GetConversation( this->parent->faction, target->faction );
241  if ( fsm->StopAllSounds( (unsigned char) ( parent->pilot->getGender() ) ) ) {
244  }
245  }
246  }
247  this->Order::Destroy();
248 }
249 
250 void CommunicatingAI::InitiateContrabandSearch( float playaprob, float targprob )
251 {
252  Unit *u = GetRandomUnit( playaprob, targprob );
253  if (u) {
255  if (un) {
258  Unit *v;
259  if ( ( v = contraband_searchee.GetUnit() ) ) {
260  if (v == u)
261  return;
262  TerminateContrabandSearch( false );
263  }
266  unsigned char gender;
267  std::vector< Animation* > *comm_face = parent->pilot->getCommFaces( gender );
268  CommunicationMessage c( parent, u, comm_face, gender );
269  c.SetCurrentState( c.fsm->GetContrabandInitiateNode(), comm_face, gender );
270  if ( u->getAIState() )
271  u->getAIState()->Communicate( c );
272  which_cargo_item = 0;
273  }
274  }
275  }
276 }
277 
278 void CommunicatingAI::AdjustRelationTo( Unit *un, float factor )
279 {
280  if (Network)
281  return; //Server will handle this.
282 
283  Order::AdjustRelationTo( un, factor );
284  float newrel = parent->pilot->adjustSpecificRelationship( parent, un, factor, un->faction );
285 
286  {
287  int whichCp = _Universe->whichPlayerStarship( parent );
288  Flightgroup *toFg;
289  int toFaction;
290  float oRlyFactor = factor;
291  if (whichCp != -1) {
292  toFg = un->getFlightgroup();
293  toFaction = un->faction;
294  } else {
295  /* Instead use the Aggressor's cockpit? */
296  whichCp = _Universe->whichPlayerStarship( un );
297  toFg = parent->getFlightgroup();
298  toFaction = parent->faction;
299  }
300  if (whichCp != -1) {
301  if (toFg && un->faction != parent->faction)
302  oRlyFactor = factor*0.5;
303  if (toFg)
304  UniverseUtil::adjustFGRelationModifier( whichCp, toFg->name, oRlyFactor*parent->pilot->getRank() );
305  if (un->faction != parent->faction)
306  UniverseUtil::adjustRelationModifierInt( whichCp, toFaction, oRlyFactor*parent->pilot->getRank() );
307  }
308  }
309  if ( newrel < anger || (parent->Target() == NULL && newrel+UnitUtil::getFactionRelation( parent, un ) < 0) ) {
310  if ( parent->Target() == NULL
311  || (parent->getFlightgroup() == NULL || parent->getFlightgroup()->directive.find( "." ) == string::npos) ) {
312  parent->Target( un ); //he'll target you--even if he's friendly
313  parent->TargetTurret( un ); //he'll target you--even if he's friendly
314  } else if (newrel > appease) {
315  if (parent->Target() == un) {
316  if (parent->getFlightgroup() == NULL || parent->getFlightgroup()->directive.find( "." ) == string::npos) {
317  parent->Target( NULL );
318  parent->TargetTurret( NULL ); //he'll target you--even if he's friendly
319  }
320  }
321  }
322  }
323  mood += factor*moodswingyness;
324 }
325 
326 //modified not to check player when hostiles are around--unless player IS the hostile
327 Unit* CommunicatingAI::GetRandomUnit( float playaprob, float targprob )
328 {
329  if (vsrandom.uniformInc( 0, 1 ) < playaprob) {
330  Unit *playa = _Universe->AccessCockpit( rand()%_Universe->numPlayers() )->GetParent();
331  if (playa)
332  if ( ( playa->Position()-parent->Position() ).Magnitude()-parent->rSize()-playa->rSize() )
333  return playa;
334  }
335  if ( vsrandom.uniformInc( 0, 1 ) < targprob && parent->Target() )
336  return parent->Target();
337  //FIXME FOR TESTING ONLY
338  //return parent->Target();
340  vsrandom.uniformInc( -1, 1 ),
341  vsrandom.uniformInc( -1, 1 ) );
342  Collidable wherewrapper( 0, 0, where );
343 
344  //FIXME cm and unitRad below cause unused variable warnings because VS_ENABLE_COLLIDE_KEY is obviously not defined.
345  //Anybody knows if this ifdef serves an important purpose or can be removed?
347  static float unitRad =
348  XMLSupport::parse_float( vs_config->getVariable( "graphics", "hud", "radar_search_extra_radius", "1000" ) );
349  NearestUnitLocator unitLocator;
350 #ifdef VS_ENABLE_COLLIDE_KEY
351  CollideMap::iterator iter = cm->lower_bound( wherewrapper );
352  if (iter != cm->end() && (*iter)->radius > 0)
353  if ( (*iter)->ref.unit != parent )
354  return (*iter)->ref.unit;
356 
357  Unit *target = unitLocator.retval.unit;
358  if (target == NULL || target == parent)
359  target = parent->Target();
360 #else
361  Unit *target = parent->Target();
362 #endif
363  return target;
364 }
365 
366 void CommunicatingAI::RandomInitiateCommunication( float playaprob, float targprob )
367 {
368  Unit *target = GetRandomUnit( playaprob, targprob );
369  if (target != NULL) {
371  && UnitUtil::getFlightgroupName( parent ) != "Base" && !isDockedAtAll( target )
372  && UnitUtil::getDistance( parent, target ) <= target->GetComputerData().radar.maxrange) {
373  //warning--odd hack they can talk to you if you can sense them--it's like SETI@home
374  for (std::list< CommunicationMessage* >::iterator i = messagequeue.begin(); i != messagequeue.end(); i++) {
375  Unit *un = (*i)->sender.GetUnit();
376  if (un == target)
377  return;
378  }
379  //ok we're good to put a default msg in the queue as a fake message;
380  FSM *fsm = FactionUtil::GetConversation( target->faction, this->parent->faction );
381  int state = fsm->getDefaultState( parent->getRelation( target ) );
382  unsigned char gender;
383  std::vector< Animation* > *comm_face = parent->pilot->getCommFaces( gender );
384  messagequeue.push_back( new CommunicationMessage( target, this->parent, state, state, comm_face, gender ) );
385  }
386  }
387 }
388 
390 {
391  if (0 && mood == 0) {
392  FSM::Node *n = c.getCurrentState();
393  if (n)
394  return rand()%n->edges.size();
395  else
396  return 0;
397  } else {
398  static float moodmul = XMLSupport::parse_float( vs_config->getVariable( "AI", "MoodAffectsRespose", "0" ) );
399  static float angermul = XMLSupport::parse_float( vs_config->getVariable( "AI", "AngerAffectsRespose", "1" ) );
400  static float staticrelmul =
401  XMLSupport::parse_float( vs_config->getVariable( "AI", "StaticRelationshipAffectsResponse", "1" ) );
402  return selectCommunicationMessageMood( c, moodmul*mood+angermul*parent->pilot->getAnger( parent,
403  un )+staticrelmul
405  }
406 }
407 
409 {
410  if ( messagequeue.back()->curstate < messagequeue.back()->fsm->GetUnDockNode() ) {
412  FSM *tmpfsm = c.fsm;
413  Unit *targ = c.sender.GetUnit();
414  if ( targ && UnitUtil::getUnitSystemFile( targ ) == UnitUtil::getUnitSystemFile( parent ) && !isDockedAtAll( targ ) ) {
416  FSM::Node *n = c.getCurrentState();
417  if (n) {
418  if ( n->edges.size() ) {
419  Unit *un = c.sender.GetUnit();
420  if (un) {
421  int b = selectCommunicationMessage( c, un );
422  Order *o = un->getAIState();
423  unsigned char gender;
424  std::vector< Animation* > *comm_face = parent->pilot->getCommFaces( gender );
425  if (o)
426  o->Communicate( CommunicationMessage( parent, un, c, b, comm_face, gender ) );
427  }
428  }
429  }
430  c.fsm = tmpfsm;
431  }
432  }
433 }
434 
436