NPC Attraction - They love me, They love me not
anjuna edited this page 11 months ago

NPC preferences - They love, they love me not

Anjuna
Grand Duke of Telecommunications
December 25, 2023

1 Introduction

Welcome to the tutorial on the npc preference and attraction system, and how you can interact with it. If you have any other questions, you can always ask for help at the Discord.

I wish you a happy coding experience.

Your truly,

Anjuna

2 General Overview and terms

The entire preference system consists of roughly 4 parts:

  • pcs_has_attr Here we define what the preference actually is and means.
  • npc_set_preference Here we add, change, and remove preferences from npcs.
  • set_npc_attraction Here we calculate how attractive the npc finds Sveta (calculated in terms of appearance and hotcat).
  • npc_reactions Here npc’s choose a “bark” depending on their preferences.

We will go over each file and address its function, how to use it, and how to add to it.

We use the following terms repeatedly:

  • $npc_code is the string which defines an npc. These usually start with ‘A’, ‘B’, or ‘C’: ‘A12’, ‘B1’, ‘A154’, ‘C2’
  • $attr_name is the name of a preference that an npc has / attribute that Sveta has. ‘body_tits_small’, ‘clothing_exposed_ass’
  • [STUFF] indicates a placeholder or that you the reader needs to replace this (just like $npc_code and $attr_name)

3 pcs_has_attr

In pcs has attr we define each attribute/preference, and it is filled with code which checks whether Sveta has that attribute/preference.

3.1 How do we check whether Sveta has an attribute/preference?

We can then check whether Sveta has an attribute / conforms to a preference using func(‘pcs_has_attr’, $attr_name). In an if-statement this looks like:

    if func(‘pcs_has_attr’, $attr_name):
        [CODE HERE FOR WHEN SVETA CONFORMS TO THE PREFERENCE]
    else
        [CODE HERE FOR WHEN SVETA DOES NOT CONFORM TO THE PREFERENCE]
    end

3.2 How is an attribute/preference defined in the code?

The general structure of how we define a preference is as follows:

    if $ARGS[0] = [$attr_name]:
        if [SVETA CONFORMS TO THE PREFERENCE]:
            result = 1
        else
            result = 0
        end
    end

3.2.1 Examples

Example 1: A preference for red hair

    if $ARGS[0] = ‘hair_color_red’:
        if pcs_haircol = 2:
            result = 1
        else
            result = 0
        end
    end

and we can check it as:

    if func(‘pcs_has_attr’, ‘hair_color_red’):
        ‘Sveta, you have red hair’
    else
        ‘Sveta, you do not have red hair’
    end

3.3 Logic and multiple preferences

Having coded multiple preferences, we also added the basic ‘AND’ and ‘OR’ functions so you can check for multiple attributes as follows:

    if func(‘pcs_has_attr’, ‘AND’, $attr_name1, $attr_name2, $attr_name3, ...)
    if func(‘pcs_has_attr’, ‘OR’, $attr_name1, $attr_name2, $attr_name3, ...)

As of the time of writing, it’s currently not possible to nest ‘AND’ inside of ‘AND’ or ‘OR’ inside of ‘OR’. So it is possible to write:

    func(‘pcs_has_attr’, ‘AND’, func(‘pcs_has_attr’, ‘OR’, $attr_name1, $attr_name2),
    func(‘pcs_has_attr’, ‘OR’, $attr_name3, $attr_name4))

but not:

    func(‘pcs_has_attr’, ‘AND’, func(‘pcs_has_attr’, ‘OR’,
    func(‘pcs_has_attr’, ‘AND’, $attr_name1, $attr_name2), ...), ...)

3.4 Adding to pcs has attr

You can add to pcs has attr as follows:

  1. Check whether the attribute is already in pcs_has_attr
    • If the attribute is already in pcs_has_attr use that one
    • If the attribute is part of another attribute contact the discord to see whether we can split that attribute apart
  2. If the attribute is not already in pcs_has_attr, add it to the list
    • Give it a good name, following the naming convention (see below)
    • Use the basic setup we have shown above

3.4.1 Naming convention

The attribute/preference names follow the following convention: [class] [group] [subgroup], where the subgroup is optional.

  • ‘body_ass_bubble’
  • ‘body_tits_big’
  • ‘clothing_exposed_panties’
  • ‘cosmetics_deodorant’
  • ‘cosmetics_tattoo’
  • ‘hair_leg‘
  • ‘hair_leg not’
  • ‘hair_length_bra’
  • ‘hair_color_red’

4 npc set preference

Here we add, change, or remove preferences from npc’s.

4.1 How do we alter an npc’s preference?

The general structure for altering an npc’s preference is as follows:

    gs ‘npc_set_preference’, $npc_code, $attr_name, [DISPOSITION]

Here we used:

  • [DISPOSITION] describes what the npc things. You can either pass on of the following five strings: [‘hate’, ‘dislike’, ‘neutral’, ‘like’, ‘love’], or you can pass an integer (-10, -2, 0, 4, 8, 21, etc)

4.1.1 Examples

Example 1: Dimka (‘A1’) dislikes bimbo clothing:

    gs ‘npc_set_preference’, ‘A1’, ‘clothing_bimbo’, ‘dislike’

Example 2: Vladimir (step-dad) (‘A28’) likes you having a tan:

    gs ‘npc_set_preference’, ‘A28’, ‘body_tan’, ‘like’

Example 3: Mikhail (bio-dad) (‘A35’) dislikes you having cum on your face:

    gs ‘npc_set_preference’, ‘A35’, ‘cum_face’, ‘dislike’

4.2 How do we check which preferences and dispositions an NPC has

To limit the number of variables needed (which has a hard, build in, limit), as well as maximize our ability to loop through active preferences, checking the preferences that an NPC has is rather complicated. It is done as follows:

  1. create the $npc_pref_traits and npc_trait_values arrays

    dynamic $npc_preferences[$npc_code]
    dynamic $npc_pref_values[$npc_code]
    
  2. For a specific preference $PREF_NAME, the npc has a positive disposition if:

    if npc_trait_values[$attr_name] > 0:
    
  3. and a negative disposition if:

    if npc_trait_values[$attr_name] < 0:
    
  4. when done, clean up the created arrays:

    killvar ‘$npc_pref_traits’
    killvar ‘npc_trait_values’
    

4.2.1 Examples

Example 1: We want to know how Dimka (‘A1’) feels about bimbo clothing:

    dynamic $npc_pref_values[‘A1’]
    if npc_trait_values[‘clothing_bimbo’] > 0:
        ‘Dimka is positive about bimbo clothes’
    elseif npc_trait_values[‘clothing_bimbo’] < 0:
        ‘Dimka is negative about bimbo clothes’
    else
        ‘Dimka has no special opinion about bimbo clothes’
    end
    killvar ‘npc_trait_values’

Example 2: We want to know whether both Vladimir (step-dad) (‘A28’) and Natasha (bio-mom) (‘A29’) dislike Sveta having cum on her face:

This is rather difficult, since creating the array for the second NPC overwrites the first NPC. This thus needs to be done with temporary variables:

    dynamic $npc_pref_values[‘A28’]
    temp_vlad_cum_pref = npc_trait_values[‘cum_face’]
    dynamic $npc_pref_values[‘A29’]
    if temp_vlad_cum_pref < 0 and npc_trait_values[‘cum_face’] < 0:
        ‘Both parents dislike Sveta having cum on her face’
    else
        ‘At least one of her parents likes it if Sveta has cum on her face. Kinky’
    end
    killvar ‘npc_trait_values’
    killvar ‘temp_vlad_cum_pref’

If for some ungodly reason you need to simultaneously loop through the preferences of multiple npc’s, the build in copyarr function is the way to go.

4.3 Adding to npc set preference

You don’t!

5 set npc attraction

Here we use the preferences defined using npc set preference and calculate the a relative appearance (called attraction) and relative hotcat for Sveta from the eyes of an NPC.

5.1 How do we get the relative appearance and hotcat?

Getting the relative appearance and hotcat is relatively simple:

  1. First we fill the relevant entries in the npc_attraction and npc_rel_hotcat arrays

    gs ‘set_npc_attraction’, $npc_code, MAX_HOTCAT_DIFFERENCE
    
    • MAX_HOTCAT_DIFFERENCE is a number which limits the difference between the actual hotcat and relative hotcat. It defaults to 2. Plugging in a negative number ignores this setting
  2. Then the relative appearance (or attraction) is npc_attraction[$npc code]

  3. The relative hotcat is npc_rel_hotcat[$npc code].

5.1.1 Examples

Example 1: Sveta is talking to Artem (‘A2’) and if he finds her attractive enough (relative hotcat > 6) he might do something, but we only want the relative hotcat to increase/decrease by at most 3 points:

    gs ‘set_npc_attraction’, ‘A2’, 3
    if npc_rel_hotcat[‘A2’] > 6:
        [CODE HERE]
    end

Example 2: Vitek (‘A9’), Dan (‘A10’), and Vasily (‘A11’) might act differently depending on whether the majority finds Sveta attractive enough (relative hotcat > 5), and we allow any increase/decrease to the relative hotcat:

    gs ‘set_npc_attraction’, ‘A9’, -1
    gs ‘set_npc_attraction’, ‘A10’, -1
    gs ‘set_npc_attraction’, ‘A11’, -1
    if (npc_rel_hotcat[‘A9’] > 5 and npc_rel_hotcat[‘A10’] > 5) or
       (npc_rel_hotcat[‘A9’] > 5 and npc_rel_hotcat[‘A11’] > 5) or
       (npc_rel_hotcat[‘A10’] > 5 and npc_rel_hotcat[‘A11’] > 5):
            [CODE HERE]
    end

5.2 Adding to set npc attraction

You don’t!

6 npc reactions

TBD

7 List of currently implemented preferences/attributes

  • body
    • ass
      • body_ass_flat: pcs_butt <= 4
      • body_ass_average: pcs_butt >= 5 and pcs_butt <= 7
      • body_ass_big: pcs_butt >= 8 and pcs_butt <= 12
      • body_ass_bubble: pcs_butt >= 13
    • bmi
      • body_bmi_starving: pcs_bmi <= 15
      • body_bmi_underweight: pcs_bmi >= 16 and pcs_bmi <= 18
      • body_bmi_normal: pcs_bmi >= 19 and pcs_bmi <= 24
      • body_bmi_overweight: pcs_bmi >= 25 and pcs_bmi <= 29
      • body_bmi_obese: pcs_bmi >= 30
    • eyes
      • body_eyes_brown: pcs_eyecol = 0
      • body_eyes_grey: pcs_eyecol = 1
      • body_eyes_green: pcs_eyecol = 2
      • body_eyes_blue: pcs_eyecol = 3
    • lips
      • body_lips_thin: pcs_lips <= 0
      • body_lips_normal: pcs_lips = 1
      • body_lips_plump: pcs_lips = 2
      • body_lips_big: pcs_lips = 3
      • body_lips_pillowy: pcs_lips >= 4
    • skin
      • body_skin_bad: pcs_skin <= 399
      • body_skin_normal: pcs_skin >= 400 and pcs_skin <= 599
      • body_skin_good: pcs_skin >= 600
    • strength
      • body_strength_weak: strenbuf <= 20 and stren_plus_lvl <= 0
      • body_strength_normal: strenbuf >= 21 and strenbuf <= 100 and stren_plus_lvl <= 0
      • body_strenght_strong: strenbuf >= 100 and stren_plus_lvl > 0
    • sweat
      • body_sweat_none: pcs_sweat <= 21
      • body_sweat_sweaty: pcs_sweat >= 22 and pcs_sweat <= 39
      • body_sweat_stinky: pcs_sweat >= 40
    • tits
      • body_tits_small: pcs_cupsize <= 10
      • body_tits_average: pcs_cupsize >= 11 and pcs_cupsize <= 25
      • body_tits_big: pcs_cupsize >= 26
    • body_fit: pcs_bmi >= 19 and pcs_bmi <= 24 and (pcs_vital∗2 + pcs_agil + pcs_stren)/4 >= 60
    • body_pregnant: func(’body_din’, ’pregnancyVisibility’)
    • body_tan: pcs_tan >= 6
    • body_tan not: pcs_tan <= 5
  • clothes
    • exposed
      • clothes_exposed_ass: CoverBack >= 1
      • clothes_exposed_bra: $braworntype ! ’none’ and PBraCover >= 1
      • clothes_exposed_panties: $pantyworntype ! ’none’ and (PCloCoverBack >= 1 or PCloCoverFront >= 1)
      • clothes_exposed_pussy: CoverFront >= 1
      • clothes_exposed_tits: CoverTop >= 1
    • skirt
      • clothes_skirt_long: CloSkirtShortness <= 2
      • clothes_skirt_normal: CloSkirtShortness >= 3 and CloSkirtShortness <= 4
      • clothes_skirt_short: CloSkirtShortness >= 5
    • style
      • clothes_style_bimbo: bimbo_flag = 1
      • clothes_style_goth: goth_flag = 1
      • clothes_style_punk: punk_flag = 1
    • clothes_thin: CloThinness >= 5
  • cosmetics
    • cosmetics_deodorant: deodorant_on ! 0
    • cosmetics_makeup: pcs_makeup > 1
    • cosmetics_piercing: Visible piercings -> (pirsA > 0 and pirsA < 10000) or (pirsB > 0 and pirsB < 10000) or (pirsD > 0 and pirsD < 10000) or (pirsE > 0 and pirsE < 10000) or (pirsE > 0 and pirsE < 10000 and (PCloBra > 0 or CloThinness > 5))
    • cosmetics_tattoo: Visible tattoos -> atarm >= 1 or tatlip >= 1 or tatneck >= 1 or tathand >= 1 or tatfce >= 1 or ((tatback >= 1 or tatblly >= 1 or tatside >= 1 or tatlech >= 1 or tatwrist >= 1) and (PCloBra > 0 or CloThinness > 5)) or (tatankle >= 1 and (CloSkirtShortness > 1 or CloPantsShortness > 1)) or (tatleg >= 1 and (CloSkirtShortness > 2 or CloPantsShortness > 2))
  • cum
    • cum_face: cumloc[11] = 1 or cumloc[16] = 1
    • cum_clothes: cumloc[6] = 1 or cumloc[7] = 1
  • hair
    • color
      • hair_color_black: pcs_haircol = 0
      • hair_color_brown: pcs_haircol = 1
      • hair_color_red: pcs_haircol = 2
      • hair_color_blonde: pcs_haircol = 3
      • hair_color_dyed: pcs_haircol >= 4
    • length
      • hair_length_veryshort: pcs_hairlng <= 30
      • hair_length_short: pcs_hairlng >= 31 and pcs_hairlng <= 80
      • hair_length_chin: pcs_hairlng >= 81 and pcs_hairlng <= 160
      • hair_length_shoulder: pcs_hairlng >= 161 and pcs_hairlng <= 260
      • hair_length_bra: pcs_hairlng >= 261 and pcs_hairlng <= 400
      • hair_length_long: pcs_hairlng >= 401
    • pubes
      • hair_pubes_shaven: pcs_pubes <= 10 or lashair = 1
      • hair_pubes_grown: pcs_pubes >= 11 and lashair = 0
      • hair_pubes_styled: pcs_pubes >= 17 and pcs_pubes <= 25 and lashair = 0 and func(’pcs_has_attr’, ’clothes_exposed_pussy’) and ((pubestyle >= 2 and pubestyle <= 9) or (pubestyle >= 12 and pubestyle <= 14))
    • hair_leg: pcs_leghair >= 4
    • hair_leg_not: pcs_leghair <= 3
    • hair_curly: curly >= 1
    • hair_straight: curly <= 0