/** * @brief Remember a particular interaction between two beings * @param local_sim Pointer to the simulation object * @param local Pointer to the being * @param other Pointer to the being being interacted with * @param event The type of event * @param affect The affect associated with the interaction * @param arg Any additional argument */ void episodic_interaction( noble_being * local, noble_being * other, being_episodic_event_type event, AFFECT_TYPE affect, n_byte2 arg) { episodic_store_memory( local, event, affect, being_gender_name(local),being_family_name(local), being_gender_name(other),being_family_name(other), arg); }
/** * @brief Store an episodic memory about the self * @param local_sim Pointer to the simulation object * @param local Pointer to the being * @param event The type of event * @param affect An affect value associated with the event * @param arg Any additional argument */ void episodic_self( noble_being * local, being_episodic_event_type event, AFFECT_TYPE affect, n_byte2 arg) { episodic_store_memory(local, event, affect, being_gender_name(local), being_family_name(local), 0, 0, arg); }
/** * @brief Returns a celebrity factor based upon how many apes within * the episodic memory of the given ape have a similar name to the * met ape, and their friend or foe values. * This means that initial beliefs about other apes are partly * a form of stereotyping * @param local_sim pointer to the simulation * @param meeter_being pointer to the ape * @param met_being pointer to another ape * @return celebrity value of the met ape */ n_int episodic_met_being_celebrity( noble_being * meeter_being, noble_being * met_being) { n_int i,j,celebrity=0,ctr,aff; noble_episodic * meeter_episodic = being_episodic(meeter_being); n_byte2 first_name = being_gender_name(met_being); n_byte2 family_name = being_family_name(met_being); if (!meeter_episodic) return 0; /** check all episodic memories of the meeter */ for (i=0; i<EPISODIC_SIZE; i++) { aff = (n_int)(meeter_episodic[i].affect) - EPISODIC_AFFECT_ZERO; if (aff>1) aff=1; if (aff<-1) aff=-1; /** check both the meeter and the met ape for each memory */ for (j=BEING_MEETER; j<=BEING_MET; j++) { ctr=0; /** same first name */ if (meeter_episodic[i].first_name[j]==first_name) { celebrity+=aff; ctr++; } /** same family name */ if (meeter_episodic[i].family_name[j]==family_name) { celebrity+=aff; ctr++; } /** if both first name and family name match then increase the celebrity value further */ if (ctr==2) { celebrity+=aff*2; } } } /** limit within range */ if (celebrity>16) celebrity=16; if (celebrity<-16) celebrity=-16; return celebrity; }
/** * @brief Generate an intention. * Note that intentions are stored together with episodic memories, * with the event type making the difference between a memory about * the past and an intention about the future. * @param local_sim Pointer to the simulation * @param local Pointer to the ape * @param episode_index Episodic memory array index to use. * @param mins_ahead The number of minutes into the future for which the intention will last. * @param args Any additional arguments * @return Returns 1 if the update was successful, or 0 otherwise. */ n_byte episodic_intention( noble_being * local, n_int episode_index, n_byte2 mins_ahead, n_byte args) { n_byte4 date; n_byte4 time; n_int replace; n_byte event; noble_episodic * local_episodic = being_episodic(local); if (local_episodic == 0L) { return 0; } event = local_episodic[episode_index].event; if (event==0) return 0; time = land_time(); date = local_episodic[episode_index].space_time.date; if (time >= TIME_DAY_MINUTES) { /** increment date by one day */ time %= TIME_DAY_MINUTES; date++; } if (event >= EVENT_INTENTION) { /** extend the time of an existing intention */ local_episodic[episode_index].space_time.time = time; local_episodic[episode_index].space_time.date = date; local_episodic[episode_index].arg = args; /** if this was someone else's intention it now becomes yours */ local_episodic[episode_index].first_name[BEING_MEETER] = being_gender_name(local); local_episodic[episode_index].family_name[BEING_MEETER] = being_family_name(local); return 1; } /** only certain types of events become intentions */ if (!((event==EVENT_GROOM) || (event==EVENT_CHAT))) { return 0; } /** find a memory index to replace */ replace = noble_episodic_replace_index( EVENT_INTENTION + event, (n_int)(local_episodic[episode_index].affect)-EPISODIC_AFFECT_ZERO, being_gender_name(local), being_family_name(local), local_episodic[episode_index].first_name[BEING_MET], local_episodic[episode_index].family_name[BEING_MET], local); if (replace == -1) { return 0; } if (replace == episode_index) { return 0; } memory_copy((n_byte*)&local_episodic[episode_index], (n_byte*)&local_episodic[replace], sizeof(noble_episodic)); local_episodic[replace].event = EVENT_INTENTION + event; local_episodic[replace].space_time.time = time; local_episodic[replace].space_time.date = date; local_episodic[replace].first_name[BEING_MEETER] = being_gender_name(local); local_episodic[replace].family_name[BEING_MEETER] = being_family_name(local); local_episodic[replace].arg = args; return 1; }
/** * @brief Remember eating * @param local_sim Pointer to the simulation object * @param local Pointer to the being * @param energy Energy obtained from food * @param food_type The type of food */ void episodic_food(noble_being * local, n_int energy, n_byte food_type) { episodic_store_full(local, EVENT_EAT, energy, being_gender_name(local), being_family_name(local), 0, 0, 0, food_type); }
/** * @brief Updates the sex drive * @param local Pointer to the ape * @param awake whether the ape is awake * @param local_sim Pointer to the simulation */ static void drives_sex( noble_being * local, n_int awake, noble_simulation * local_sim) { n_int i,max; noble_social * local_social_graph = being_social(local); n_int age_in_days = AGE_IN_DAYS(local); #ifdef EPISODIC_ON noble_episodic * local_episodic = being_episodic(local); #endif /** is the being mature */ if (age_in_days > AGE_OF_MATURITY) { /** is the being awake and its sex drive not saturated */ if (awake) { /** increase the sex drive */ being_inc_drive(local, DRIVE_SEX); /** if sex drive is above a mate seeking threshold and the being has no current goal */ if ((being_drive(local, DRIVE_SEX) > THRESHOLD_SEEK_MATE) && being_check_goal(local, GOAL_NONE)) { /** either search for a preferred mate, or mate randomly */ if (GENE_MATE_SEEK(being_genetics(local))&1) { /** look for a mate */ #ifdef EPISODIC_ON if (!local_episodic) return; /** does the being remember mating in the recent past */ for(i=0; i<EPISODIC_SIZE; i++) { if (local_episodic[i].event == EVENT_MATE) { /** not someone else's mate */ if (being_name_comparison(local, local_episodic[i].first_name[BEING_MEETER], local_episodic[i].family_name[BEING_MEETER])) { /** set a goal to seek the remembered mate */ being_set_goal_mate(local, local_episodic[i].first_name[BEING_MET], local_episodic[i].family_name[BEING_MET]); /** remember seeking a mate */ episodic_store_memory( local_sim, local, EVENT_SEEK_MATE, AFFECT_SEEK_MATE, being_gender_name(local), being_family_name(local), local->delta.goal[1], local->delta.goal[2],0); break; } } } #endif /** if the being is not seeking a remembered mate then examine the social graph for attractive prospects */ if (being_check_goal(local, GOAL_MATE) == 0) { max = 0; if (!local_social_graph) return; for(i=1; i<SOCIAL_SIZE_BEINGS; i++) { if (!SOCIAL_GRAPH_ENTRY_EMPTY(local_social_graph,i)) { if ((local_social_graph[i].attraction) > max) { /** who are we most attracted to? */ max=local_social_graph[i].attraction; being_set_goal_mate(local, local_social_graph[i].first_name[BEING_MET], local_social_graph[i].family_name[BEING_MET]); } } } /** if an attractive mate was found then remember this event */ if (being_check_goal(local, GOAL_MATE)) { episodic_store_memory( local_sim, local, EVENT_SEEK_MATE, AFFECT_SEEK_MATE, being_gender_name(local), being_family_name(local), local->delta.goal[1], local->delta.goal[2],0); } } } } /** during gestation reduce the sex drive */ if (being_pregnant(local) != 0) { if (being_drive(local, DRIVE_SEX) >= GESTATION_SEX_DRIVE_DECREMENT) { being_dec_drive(local, DRIVE_SEX); } } } else { /** while sleeping reduce sex drive */ being_dec_drive(local, DRIVE_SEX); } /** if sex drive falls below the mate seeking threshold and the being is seeking a mate, then stop seeking a mate */ if ((being_drive(local, DRIVE_SEX) < THRESHOLD_SEEK_MATE) && being_check_goal(local, GOAL_MATE)) { being_set_goal_none(local); } } }