Noble Ape
The Central Directories of the Noble Ape Simulation.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
episodic.c
Go to the documentation of this file.
1 /****************************************************************
2 
3  episodic.c
4 
5  =============================================================
6 
7  Copyright 1996-2014 Tom Barbalet. All rights reserved.
8 
9  Permission is hereby granted, free of charge, to any person
10  obtaining a copy of this software and associated documentation
11  files (the "Software"), to deal in the Software without
12  restriction, including without limitation the rights to use,
13  copy, modify, merge, publish, distribute, sublicense, and/or
14  sell copies of the Software, and to permit persons to whom the
15  Software is furnished to do so, subject to the following
16  conditions:
17 
18  The above copyright notice and this permission notice shall be
19  included in all copies or substantial portions of the Software.
20 
21  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28  OTHER DEALINGS IN THE SOFTWARE.
29 
30  This software and Noble Ape are a continuing work of Tom Barbalet,
31  begun on 13 June 1996. No apes or cats were harmed in the writing
32  of this software.
33 
34  ****************************************************************/
35 
40 #include "entity.h"
41 #include "entity_internal.h"
42 
47 #ifdef EPISODIC_ON
48 
49 static n_console_output * local_logging;
50 static n_int local_social;
51 
52 void episodic_logging(n_console_output * output_function, n_int social)
53 {
54  local_logging = output_function;
55  local_social = social;
56 }
57 
67 static void episodic_intention_update(noble_simulation * local_sim, noble_being * local, n_int episode_index)
68 {
69  noble_episodic * local_episodic = being_episodic(local);
70  n_byte event;
71  n_int learned_preference_index=-1;
72  if (local_episodic == 0L)
73  {
74  return;
75  }
76  event = local_episodic[episode_index].event - EVENT_INTENTION;
77  switch(event)
78  {
79  case EVENT_CHAT:
80  {
81  learned_preference_index = PREFERENCE_CHAT;
82  break;
83  }
84  case EVENT_GROOM:
85  {
86  if ((local_episodic[episode_index].arg&2)!=0)
87  {
88  learned_preference_index = PREFERENCE_GROOM_MALE;
89  }
90  else
91  {
92  learned_preference_index = PREFERENCE_GROOM_FEMALE;
93  }
94  break;
95  }
96  }
97 
99  if (learned_preference_index>-1)
100  {
101  if ((local_episodic[episode_index].arg&1)!=0)
102  {
103  if (local->learned_preference[learned_preference_index]<255)
104  {
105  local->learned_preference[learned_preference_index]++;
106  }
107  }
108  else
109  {
110  if (local->learned_preference[learned_preference_index]>0)
111  {
112  local->learned_preference[learned_preference_index]--;
113  }
114  }
115  }
116 }
117 
134 void episodic_cycle(noble_simulation * local_sim, noble_being * local_being, void * data)
135 {
136  if (being_awake(local_sim, local_being) == 0) return;
137 
138  {
139  n_int i;
140  noble_episodic * local_episodic = being_episodic(local_being);
141  n_genetics * genetics = being_genetics(local_being);
142 
143  if (!local_episodic) return;
144 
145  for (i=0; i<EPISODIC_SIZE; i++)
146  {
147  if (local_episodic[i].event == 0) continue;
148 
150  if (local_episodic[i].event >= EVENT_INTENTION)
151  {
153  if (being_name_comparison(local_being, local_episodic[i].first_name[BEING_MEETER], local_episodic[i].family_name[BEING_MEETER]))
154  {
155  if (spacetime_before_now(&local_episodic[i].space_time, local_sim->land))
156  {
157  local_episodic[i].event = 0;
158  continue;
159  }
160  }
161  episodic_intention_update(local_sim, local_being, i);
162  }
163 
165  if (local_episodic[i].affect < EPISODIC_AFFECT_ZERO)
166  {
168  if (EPISODIC_AFFECT_ZERO - local_episodic[i].affect > 16)
169  {
170  local_episodic[i].affect+=(1+GENE_NEGATIVE_AFFECT_FADE(genetics));
171  }
172  else
173  {
174  local_episodic[i].affect++;
175  }
176  }
177  else
178  {
179  if (local_episodic[i].affect > EPISODIC_AFFECT_ZERO)
180  {
182  if (local_episodic[i].affect - EPISODIC_AFFECT_ZERO > 16)
183  {
184  local_episodic[i].affect-=(1+GENE_POSITIVE_AFFECT_FADE(genetics));
185  }
186  else
187  {
188  local_episodic[i].affect--;
189  }
190  }
191  }
192  }
193  }
194 }
195 
208  noble_simulation * local_sim,
209  noble_being * meeter_being,
210  noble_being * met_being)
211 {
212  n_int i,j,celebrity=0,ctr,aff;
213  noble_episodic * meeter_episodic = being_episodic(meeter_being);
214  n_byte2 first_name = being_gender_name(met_being);
215  n_byte2 family_name = being_family_name(met_being);
216 
217  if (!meeter_episodic) return 0;
218 
220  for (i=0; i<EPISODIC_SIZE; i++)
221  {
222  aff = (n_int)(meeter_episodic[i].affect) - EPISODIC_AFFECT_ZERO;
223  if (aff>1) aff=1;
224  if (aff<-1) aff=-1;
225 
227  for (j=BEING_MEETER; j<=BEING_MET; j++)
228  {
229  ctr=0;
231  if (meeter_episodic[i].first_name[j]==first_name)
232  {
233  celebrity+=aff;
234  ctr++;
235  }
237  if (meeter_episodic[i].family_name[j]==family_name)
238  {
239  celebrity+=aff;
240  ctr++;
241  }
244  if (ctr==2)
245  {
246  celebrity+=aff*2;
247  }
248  }
249  }
250 
252  if (celebrity>16) celebrity=16;
253  if (celebrity<-16) celebrity=-16;
254  return celebrity;
255 }
256 
266  noble_simulation * local_sim,
267  noble_being * local,
268  n_byte intention)
269 {
270  n_int i,hits=0,memories=0;
271  noble_episodic * local_episodic = being_episodic(local);
272  if (local_episodic == 0L)
273  {
274  return 0;
275  }
276 
278  for (i=0; i<EPISODIC_SIZE; i++)
279  {
280  if (local_episodic[i].event>0)
281  {
282  if (intention!=0)
283  {
285  if (local_episodic[i].event >= EVENT_INTENTION)
286  {
287  hits++;
288  }
289  }
290  else
291  {
293  if (being_name_comparison(local, local_episodic[i].first_name[BEING_MEETER], local_episodic[i].family_name[BEING_MEETER]))
294  {
295  hits++;
296  }
297  }
298  memories++;
299  }
300  }
301  if (memories>0)
302  {
303  return hits*100/memories;
304  }
305  else
306  {
307  if (intention!=0)
308  {
309  return 0;
310  }
311  return 100;
312  }
313 }
314 
327 static n_int noble_episodic_replace_index(
328  n_byte event,
329  n_int affect,
330  n_byte2 name1, n_byte2 family1,
331  n_byte2 name2, n_byte2 family2,
332  noble_being * local,
333  noble_simulation * local_sim)
334 {
336  n_int abs_aff = affect;
337  n_int i;
338  n_int replace=-1;
339  n_int min;
340  n_byte event_exists=0;
341 
342  noble_episodic * local_episodic = being_episodic(local);
343 
344  if (!local_episodic) return -1;
345 
347  abs_aff = ABS(abs_aff);
348  min = abs_aff;
349  for (i=0; i<EPISODIC_SIZE; i++)
350  {
352  if (local_episodic[i].event == event)
353  {
355  if ((local_episodic[i].first_name[BEING_MEETER]==name1) &&
356  (local_episodic[i].family_name[BEING_MEETER]==family1))
357  {
359  n_int aff1 = ABS((n_int)(local_episodic[i].affect)-EPISODIC_AFFECT_ZERO);
361  event_exists = 1;
362  if (aff1 <= min)
363  {
364  min = aff1;
365  replace = i;
366  }
367  }
368  }
369  }
370 
371  if (event_exists==0)
372  {
374  for (i=0; i<EPISODIC_SIZE; i++)
375  {
376  if (local_episodic[i].event == 0)
377  {
378  return i;
379  }
380  }
381 
384  min = abs_aff;
385  for (i=0; i<EPISODIC_SIZE; i++)
386  {
388  n_int aff1 = ABS((n_int)(local_episodic[i].affect)-EPISODIC_AFFECT_ZERO);
390  if (aff1 < min)
391  {
392  min = aff1;
393  replace = i;
394  }
395  }
396  }
397 
398  return replace;
399 }
400 
414 static void episodic_store_full(
415  noble_being * local,
416  n_byte event,
417  n_int affect,
418  noble_simulation * local_sim,
419  n_byte2 name1, n_byte2 family1,
420  n_byte2 name2, n_byte2 family2,
421  n_byte2 arg,
422  n_byte food)
423 {
424  noble_episodic * local_episodic = being_episodic(local);
425  n_int replace;
426  n_byte old_event;
427  n_byte2 old_time;
428  n_byte2 new_time;
429 
430  if (local_episodic == 0L)
431  {
432  return;
433  }
434 
435  if (being_awake(local_sim, local)==FULLY_ASLEEP) return;
436 
437  replace = noble_episodic_replace_index(event,affect,name1,family1,name2,family2,local,local_sim);
438 
439  if (replace == -1) return;
440 
441  old_event = local_episodic[replace].event;
442  old_time = local_episodic[replace].space_time.time;
443 
445  local_episodic[replace].event = event;
446  local_episodic[replace].affect = (n_byte2)(affect+EPISODIC_AFFECT_ZERO);
447 
448  spacetime_set(&local_episodic[replace].space_time, local_sim->land, being_location(local));
449 
450  new_time = local_episodic[replace].space_time.time;
451 
452  local_episodic[replace].first_name[BEING_MEETER]=name1;
453  local_episodic[replace].family_name[BEING_MEETER]=family1;
454  local_episodic[replace].first_name[BEING_MET]=name2;
455  local_episodic[replace].family_name[BEING_MET]=family2;
456  local_episodic[replace].food=food;
457  local_episodic[replace].arg=arg;
458 
459  if ((event == 0) || (event>=EVENTS))
460  {
461  (void)SHOW_ERROR("Event outside scope");
462  }
463 
464  if (local_logging)
465  {
466  if ((old_event != event) || ((old_time+10) < (new_time)))
467  {
468  n_string_block description = {0};
469  n_string_block str = {0};
470  n_string_block time = {0};
471  n_string_block combination = {0};
472  n_int social_event;
473 
474  being_name_simple(local, str);
475 
476  social_event = episode_description(local_sim, local, replace, description);
477 
478  if ((local_social == 1) && (social_event == 0))
479  {
480  return;
481  }
482 
483  io_time_to_string(time, local_sim->land->time, local_sim->land->date);
484 
485  io_three_string_combination(combination, time, str, description, 35);
486 
487  (*local_logging)(combination);
488  }
489  }
490 }
498 void episodic_food(noble_simulation * local_sim, noble_being * local, n_int energy, n_byte food_type)
499 {
500  episodic_store_full(local, EVENT_EAT, energy, local_sim,
501  being_gender_name(local), being_family_name(local),
502  0, 0, 0, food_type);
503 }
504 
518  noble_being * local,
519  n_byte event,
520  n_int affect,
521  noble_simulation * local_sim,
522  n_byte2 name1, n_byte2 family1,
523  n_byte2 name2, n_byte2 family2,
524  n_byte2 arg)
525 {
526  episodic_store_full(local,event,affect,local_sim,name1,family1,name2,family2, arg, 0);
527 }
537  noble_simulation * local_sim,
538  noble_being * local,
539  n_byte event,
540  n_int affect,
541  n_byte2 arg)
542 {
543  episodic_store_memory(local, event, affect, local_sim,
544  being_gender_name(local), being_family_name(local),
545  0, 0, arg);
546 }
557  noble_simulation * local_sim,
558  noble_being * local,
559  noble_being * other,
560  n_byte event,
561  n_int affect,
562  n_byte2 arg)
563 {
565  local, event, affect, local_sim,
566  being_gender_name(other), being_family_name(other),
567  0,0, arg);
568 }
579  noble_simulation * local_sim,
580  noble_being * local,
581  noble_being * other,
582  n_byte event,
583  n_int affect,
584  n_byte2 arg)
585 {
587  local, event, affect, local_sim,
588  being_gender_name(local),being_family_name(local),
589  being_gender_name(other),being_family_name(other), arg);
590 }
591 
605  noble_simulation * local_sim,
606  noble_being * local,
607  n_int episode_index,
608  n_byte2 mins_ahead,
609  n_byte args)
610 {
611  n_int replace;
612  n_byte2 time;
613  n_byte4 date;
614  noble_episodic * local_episodic = being_episodic(local);
615  n_byte event;
616 
617  if (local_episodic == 0L)
618  {
619  return 0;
620  }
621 
622  event = local_episodic[episode_index].event;
623 
624  if (event==0) return 0;
625 
626  time = local_sim->land->time + mins_ahead;
627  date = local_episodic[episode_index].space_time.date;
628  if (time >= TIME_DAY_MINUTES)
629  {
631  time %= TIME_DAY_MINUTES;
632  date++;
633  }
634 
635  if (event >= EVENT_INTENTION)
636  {
638  local_episodic[episode_index].space_time.time = time;
639  local_episodic[episode_index].space_time.date = date;
640  local_episodic[episode_index].arg = args;
642  local_episodic[episode_index].first_name[BEING_MEETER] = being_gender_name(local);
643  local_episodic[episode_index].family_name[BEING_MEETER] = being_family_name(local);
644  return 1;
645  }
646 
648  if (!((event==EVENT_GROOM) ||
649  (event==EVENT_CHAT)))
650  {
651  return 0;
652  }
653 
655  replace = noble_episodic_replace_index(
656  EVENT_INTENTION + event,
657  (n_int)(local_episodic[episode_index].affect)-EPISODIC_AFFECT_ZERO,
658  being_gender_name(local),
659  being_family_name(local),
660  local_episodic[episode_index].first_name[BEING_MET],
661  local_episodic[episode_index].family_name[BEING_MET],
662  local, local_sim);
663 
664  if (replace == -1) return 0;
665 
666  local_episodic[replace] = local_episodic[episode_index];
667  local_episodic[replace].event = EVENT_INTENTION + event;
668  local_episodic[replace].space_time.time = time;
669  local_episodic[replace].space_time.date = date;
670  local_episodic[replace].first_name[BEING_MEETER] = being_gender_name(local);
671  local_episodic[replace].family_name[BEING_MEETER] = being_family_name(local);
672  local_episodic[replace].arg = args;
673 
674  return 1;
675 }
676 
685  noble_simulation * local_sim,
686  noble_being * local,
687  noble_being * other)
688 {
689  noble_episodic * local_episodic = being_episodic(local);
690  noble_episodic * other_episodic = being_episodic(other);
691  n_int affect;
692  n_byte event;
693  n_int replace,mult=1;
694 
695  if (local_episodic == 0L || other_episodic == 0L || local == other)
696  {
697  return 0;
698  }
699 
700  affect = (n_int)(local_episodic[GET_A(local,ATTENTION_EPISODE)].affect)-EPISODIC_AFFECT_ZERO;
701  event = local_episodic[GET_A(local,ATTENTION_EPISODE)].event;
702 
704  if ((event==0) ||
705  (being_awake(local_sim, local) == FULLY_ASLEEP) ||
706  (being_awake(local_sim, other) == FULLY_ASLEEP))
707  {
708  return 0;
709  }
710 
711  if (being_awake(local_sim, local) != FULLY_AWAKE)
712  {
714  mult=2;
715  }
716 
718  if (being_random(local) <
721  {
722  event = (n_byte)(being_random(local) % EVENTS);
723  }
724  if (being_random(local) <
727  {
729  affect = (affect * (64 + (n_int)(being_random(local) & 127))) / 128;
731  if (affect<-32000) affect=-32000;
732  if (affect>32000) affect=32000;
733  }
734 
736  replace = noble_episodic_replace_index(
737  event,affect,
738  local_episodic[GET_A(local,ATTENTION_EPISODE)].first_name[BEING_MEETER],
739  local_episodic[GET_A(local,ATTENTION_EPISODE)].family_name[BEING_MEETER],
740  local_episodic[GET_A(local,ATTENTION_EPISODE)].first_name[BEING_MET],
741  local_episodic[GET_A(local,ATTENTION_EPISODE)].family_name[BEING_MET],
742  local,local_sim);
743 
744  if (replace==-1) return 0;
745 
746  other_episodic[replace] = local_episodic[GET_A(local,ATTENTION_EPISODE)];
747  other_episodic[replace].event = event;
748  other_episodic[replace].affect = (n_byte2)(affect+EPISODIC_AFFECT_ZERO);
749 
751  GET_A(local,ATTENTION_EPISODE) = (n_byte)replace;
752 
753  return 1;
754 }
755 
756 #else
757 
762  noble_being * local,
763  n_byte event,
764  n_int affect,
765  noble_simulation * local_sim,
766  n_byte2 name1, n_byte2 family1,
767  n_byte2 name2, n_byte2 family2,
768  n_byte2 arg)
769 {
770 }
771 
772 #endif
773 
774