df-structures icon indicating copy to clipboard operation
df-structures copied to clipboard

df.world.xml:incident_sub6 field determination investigation

Open PatrikLundell opened this issue 7 years ago • 0 comments

I've tried to determine some of the parameters of the _sub6 struct and believe I've had some success. This is what I've concluded:

    <struct-type type-name='incident_sub6' comment='Performance incident parameters'>
        <int32_t name='performance_event' type-name='performance_event_type'/>
        <stl-vector name='participants'>
            <pointer>
                <int32_t/>
                <int32_t/>
                <compound type-name='incident_hfid'/>
                <int32_t/>
            </pointer>
        </stl-vector>
        <int32_t name='reference_id' comment='history_event id/poetic_form id/musical_form id/dance_form_id or -1'/>
        <int32_t name='written_content id or -1'/>
        <int32_t/>
        <int32_t/>
        <int32_t/>
        <int32_t/>
    </struct-type>
    --  There ought to be either a type specific reference or a written content one. Not both.
    --  Story has only been seen with a history event id, not a written content one, but the sample was small.
    --  Poem has been seen with either a poetic form or a written content reference.
    --  Music has been seen only with a music form reference, but the sample was small.
    --    Music has been seen to be "sang" and "spoke" in DF displayed thoughts, but no instrument playing
    --    or simulation. It's still unknown how to determine what action participants took.
    --  Dance has been seen only with a dance form reference, but the sample was small.

I've used the following script to extract data from a small number of saves:

function x ()
  local civ_id = df.global.world.world_data.active_site [0].entity_links [0].entity_id
  
  local count = 0
  
  for i, incident in ipairs (df.global.world.incidents.all) do
    if incident.subtype == 6 then
      local active = false
      
      for k, participant in ipairs (incident.unk_v42_1.t6.anon_2) do
        local hf = df.historical_figure.find (participant.anon_3.hfid)
        
        if hf and hf.civ_id == civ_id then
          local unit = df.unit.find (hf.unit_id)
          
          if unit then
            for l, emotion in ipairs (unit.status.current_soul.personality.emotions) do
              if emotion.thought == df.unit_thought_type.Perform and
                 emotion.subthought == incident.id then
                if not active then
                  count = count + 1
                end

                dfhack.print ("Incident " .. tostring (incident.id))
                dfhack.print (", " .. dfhack.TranslateName (unit.name, false))
                dfhack.print (", Emotion " .. tostring (l) .. ", anon_1: " .. tostring (incident.unk_v42_1.t6.anon_1))
                dfhack.print (", anon_1: " .. tostring (participant.anon_1) .. ", anon_4: " .. tostring (participant.anon_4))
                -- incident.unk_v42_1.t6.anon_1 = df.performance_event_type
                if incident.unk_v42_1.t6.anon_1 == 0 then  --  History event story. anon_3 = event id, anon_4 = written contents id?
                  dfhack.println (", Tell History Event Story. anon_3: " .. tostring (incident.unk_v42_1.t6.anon_3))
                  
                elseif incident.unk_v42_1.t6.anon_1 == 1 then  --  Recite poem. anon_3 = poetry form, anon_4 = written contents id
                  if incident.unk_v42_1.t6.anon_3 == -1 then
                    dfhack.println (", Recite: Type: " .. tostring (df.written_content_type [df.written_content.find (incident.unk_v42_1.t6.anon_4).type]))
                    
                  else
                    dfhack.println (", Recite Poetic Form: " .. dfhack.TranslateName (df.poetic_form.find (incident.unk_v42_1.t6.anon_3).name, true))
                  end
                  
                elseif incident.unk_v42_1.t6.anon_1 == 2 then  --  Musical composition. anon_3 = music form?, anon_4 = written contents id
                  if incident.unk_v42_1.t6.anon_3 == -1 then
                    dfhack.println (", Speak/Sing: Type: " .. tostring (df.written_content_type [df.written_content.find (incident.unk_v42_1.t6.anon_4).type]))
                    -- Sang: anon_5: 0, anon_6: -1, anon_7: 137, anon_8: -1
                    --       anon_1: 2, anon_2: 0, anon_4: 14
                    -- Spoke:anon_5: -1, anon_6: -1, anon_7: 0, anon_8: -1 
                    --       anon_1: 2, anon_2: 0, anon_4: 0
                    -- Spoke:anon_5: -1, anon_6: -1, anon_7: 17, anon_8: -1
                    --       anon_1: 2, anon_2: 0, anon_4: 0
                    --### anon_5: -1 = Speak, , 0 = Sing, 1+ = instrument? Should be per participant, not individual?
                  else
                    dfhack.println (", Music: " .. dfhack.TranslateName (df.musical_form.find (incident.unk_v42_1.t6.anon_3).name, true))
                  end
                  
                elseif incident.unk_v42_1.t6.anon_1 == 3 then  --  Dance. anon_3 = dance form id, anon_4 = written contents id?
                  dfhack.println (", anon_3: " .. tostring (incident.unk_v42_1.t6.anon_3))
                  
                else
                  dfhack.println (", Unmapped type: " .. tostring (incident.unk_v42_1.t6.anon_1))                
                end
                active = true
              end
            end
          end
        end
      end
    end
  end
  
  dfhack.println ("Active performance incidents: " .. tostring (count))
end

x ()

The script used the "official" layout, not the one above (which hasn't yet been processed, so it may contain syntactic errors). The output of the script has been processed by looking up the listed citizens and DFHack the specified "emotion" entry to have the "unk2" and "strength" fields both set to 100 (and the flags [5] flag reset, if set; that's the "remembered" field). When that is done that emotion gets promoted to the one shown with extra details at the top on the unit's "Thoughts and Preferences" screen (which has to be refreshed for the changes to take effect). Obviously another 100/100 pair can trump the one you want, although I've seen that only with my own manipulations not being withdrawn. The thought has then been compared to what the parameters would produce, eventually leading to the conclusions above. I haven't gone through every poetry case (there were a lot of those), but each of the others (of which there were fewer than I'd like).

df.meetings.xml:activity_event_performancest seems to indicate that only poetry can reference written contents, not any of the other performance forms. I've seen nothing to contradict that conclusion, but there are written contents with types that might work as targets for stories, music, and dances, so the scripts tries to cater for such cases.

PatrikLundell avatar May 17 '18 17:05 PatrikLundell