Advertisement
Guest User

ACS conversation system - code

a guest
Sep 26th, 2015
173
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 16.85 KB | None | 0 0
  1. #include "zcommon.acs"
  2. #library "ZZCONV"
  3.  
  4. #define CONV_MAX_ITEMS 64
  5. bool ConvInternal_Active = false;
  6. int ConvInternal_Count = 0;
  7. str ConvInternal_Text = "";
  8. str ConvInternal_Strings[CONV_MAX_ITEMS];
  9. int ConvInternal_Visible[CONV_MAX_ITEMS];
  10. int ConvInternal_CanActivate[CONV_MAX_ITEMS];
  11. int ConvInternal_Target[CONV_MAX_ITEMS];
  12. int ConvInternal_VisibleArgs[CONV_MAX_ITEMS*3];
  13. int ConvInternal_CanActivateArgs[CONV_MAX_ITEMS*3];
  14. int ConvInternal_TargetArgs[CONV_MAX_ITEMS*3];
  15. int ConvInternal_VisibleNamed[CONV_MAX_ITEMS];
  16. int ConvInternal_CanActivateNamed[CONV_MAX_ITEMS];
  17. int ConvInternal_TargetNamed[CONV_MAX_ITEMS];
  18. int ConvInternal_CurrentItem = -1;
  19.  
  20. #define ZZCONV_VISIBLE 0
  21. #define ZZCONV_CAN_ACTIVATE 1
  22. #define ZZCONV_TARGET 2
  23.  
  24. function void ConvInternal_CallScript(int where, int num)
  25. {
  26.     int args[3];
  27.     int j;
  28.     int scr;
  29.     str named_scr;
  30.     switch(where)
  31.     {
  32.         case ZZCONV_VISIBLE:
  33.             scr = ConvInternal_Visible[num];
  34.             named_scr = ConvInternal_VisibleNamed[num];
  35.             for (j = 0; j < 3; j++)
  36.                 args[j] = ConvInternal_VisibleArgs[num*3+j];
  37.             break;
  38.         case ZZCONV_CAN_ACTIVATE:
  39.             scr = ConvInternal_CanActivate[num];
  40.             named_scr = ConvInternal_CanActivateNamed[num];
  41.             for (j = 0; j < 3; j++)
  42.                 args[j] = ConvInternal_CanActivateArgs[num*3+j];
  43.             break;
  44.         case ZZCONV_TARGET:
  45.             scr = ConvInternal_Target[num];
  46.             named_scr = ConvInternal_TargetNamed[num];
  47.             for (j = 0; j < 3; j++)
  48.                 args[j] = ConvInternal_TargetArgs[num*3+j];
  49.             break;
  50.         default:
  51.             return;
  52.     }
  53.     if (scr) ACS_ExecuteAlways(scr, 0, args[0], args[1], args[2]);
  54.     else if (strlen(named_scr)) ACS_NamedExecuteAlways(named_scr, 0, args[0], args[1], args[2]);
  55. }
  56.  
  57. function int ConvInternal_CallScriptResult(int where, int num, int def)
  58. {
  59.     int args[3];
  60.     int j;
  61.     int scr;
  62.     str named_scr;
  63.     switch(where)
  64.     {
  65.         case ZZCONV_VISIBLE:
  66.             scr = ConvInternal_Visible[num];
  67.             named_scr = ConvInternal_VisibleNamed[num];
  68.             for (j = 0; j < 3; j++)
  69.                 args[j] = ConvInternal_VisibleArgs[num*3+j];
  70.             break;
  71.         case ZZCONV_CAN_ACTIVATE:
  72.             scr = ConvInternal_CanActivate[num];
  73.             named_scr = ConvInternal_CanActivateNamed[num];
  74.             for (j = 0; j < 3; j++)
  75.                 args[j] = ConvInternal_CanActivateArgs[num*3+j];
  76.             break;
  77.         case ZZCONV_TARGET:
  78.             scr = ConvInternal_Target[num];
  79.             named_scr = ConvInternal_TargetNamed[num];
  80.             for (j = 0; j < 3; j++)
  81.                 args[j] = ConvInternal_TargetArgs[num*3+j];
  82.             break;
  83.         default:
  84.             return def;
  85.     }
  86.     if (scr) return ACS_ExecuteWithResult(scr, 0, 0, 0);
  87.     else if (strlen(named_scr)) ACS_NamedExecuteWithResult(named_scr, 0, 0, 0, 0);
  88.     return def;
  89. }
  90.  
  91. function int ConvInternal_StrToInt(str string)
  92. {
  93.     int integer = 0;
  94.     int string_len = strlen(string);
  95.     int mul = 1;
  96.    
  97.     for (int i = string_len-1; i >= 0; i--)
  98.     {
  99.         int ch_raw = getchar(string, i);
  100.         if (ch_raw < '0' || ch_raw > '9')
  101.         {
  102.             if (ch_raw == '-' && i == 0) // this should be the last (oops, I mean first) character
  103.             {
  104.                 return -integer;
  105.             }
  106.             else
  107.             {
  108.                 return 0;
  109.             }
  110.         }
  111.        
  112.         ch_raw -= '0';
  113.         integer += ch_raw * mul;
  114.         mul *= 10;
  115.     }
  116.    
  117.     return integer;
  118. }
  119.  
  120. function bool Conversation_CheckActiveChoice(int num)
  121. {
  122.     return !!ConvInternal_CallScriptResult(ZZCONV_CAN_ACTIVATE, num, 1);
  123. }
  124.  
  125. function str ConvInternal_ParseScriptArgs(str sc, int where, int num)
  126. {
  127.     // returns new str.
  128.     str out_sc = "";
  129.     bool in_args = false;
  130.     int argc = 0;
  131.     int argv[3];
  132.     str arg = "";
  133.    
  134.     for (int i = 0; i < strlen(sc); i++)
  135.     {
  136.         int ch = getchar(sc, i);
  137.         if (in_args)
  138.         {
  139.             if (ch == ')' || ch == ',')
  140.             {
  141.                 if (ch == ')')
  142.                 {
  143.                     in_args = false;
  144.                     break;
  145.                 }
  146.                
  147.                 // arg = current arg.
  148.                 argv[argc] = ConvInternal_StrToInt(arg);
  149.                 argc++;
  150.                 arg = "";
  151.                
  152.                 if (argc >= 3)
  153.                 {
  154.                     in_args = false; // more than 3 args isn't supported
  155.                     break;
  156.                 }
  157.                
  158.                 continue;
  159.             }
  160.            
  161.             arg = strparam(s:arg, c:ch);
  162.            
  163.             continue;
  164.         }
  165.         else
  166.         {
  167.             if (ch == '(')
  168.             {
  169.                 in_args = true;
  170.                 continue;
  171.             }
  172.         }
  173.        
  174.         out_sc = strparam(s:out_sc, c:ch);
  175.     }
  176.    
  177.     // argv should contain args now.
  178.     // argc should contain arg count, although we'll copy all 3 anyway
  179.     int j;
  180.     switch(where)
  181.     {
  182.         case ZZCONV_VISIBLE:
  183.             for (j = 0; j < 3; j++)
  184.                 ConvInternal_VisibleArgs[num*3+j] = argv[j];
  185.             break;
  186.         case ZZCONV_CAN_ACTIVATE:
  187.             for (j = 0; j < 3; j++)
  188.                 ConvInternal_CanActivateArgs[num*3+j] = argv[j];
  189.             break;
  190.         case ZZCONV_TARGET:
  191.             for (j = 0; j < 3; j++)
  192.                 ConvInternal_TargetArgs[num*3+j] = argv[j];
  193.             break;
  194.         default:
  195.             break;
  196.     }
  197.    
  198.     return out_sc;
  199. }
  200.  
  201. function bool Conversation_Init(str format)
  202. {
  203.     if (ConvInternal_Active) // you must deactivate the current conversation EXPLICITLY to switch a conversation screen.
  204.         return false;
  205.  
  206.     format = strparam(s:format, c:'\n');
  207.  
  208.     // format is as follows:
  209.     // <anything>[parameter=value,parameter=value]
  210.     // example:
  211.     // Hi[visible=10,target=11]
  212.     int current_item = 0;
  213.     int format_len = strlen(format);
  214.    
  215.     // now item-local declarations
  216.     bool reading_text = true;
  217.     bool reading_metadata = false; // after [
  218.     bool reading_parameter = false;
  219.     bool reading_value = false;
  220.     bool reading_args = false;
  221.     str current_parameter = "";
  222.     str current_value = "";
  223.    
  224.     str current_string = "";
  225.     int current_can_activate = 0;
  226.     str current_can_activate_named = "";
  227.     int current_target = 0;
  228.     str current_target_named = "";
  229.     int current_visible = 0;
  230.     str current_visible_named = "";
  231.     bool current_default = false;
  232.    
  233.     ConvInternal_Count = 0;
  234.     ConvInternal_CurrentItem = -1; // current active item is -1, means no item is selected.
  235.     ConvInternal_Active = true; // activate the conversation
  236.    
  237.     for (int i = 0; i <= format_len; i++)
  238.     {
  239.         int ch = getchar(format, i);
  240.         // if not reading metadata, this is either start of metadata or actual string.
  241.         if (!reading_metadata)
  242.         {
  243.             if (ch == '\n') // save.
  244.             {
  245.                 if (reading_text)
  246.                 {
  247.                     ConvInternal_Text = current_string;
  248.                     reading_text = false;
  249.                     current_string = "";
  250.                 }
  251.                 else
  252.                 {
  253.                     // test logging
  254.                     /*
  255.                     print(s:"string = ", s:current_string, c:'\n',
  256.                           s:"can_activate = ", d:current_can_activate, c:'\n',
  257.                           s:"can_activate_named = ", s:current_can_activate_named, c:'\n',
  258.                           s:"target = ", d:current_target, c:'\n',
  259.                           s:"target_named = ", s:current_target_named, c:'\n',
  260.                           s:"visible = ", d:current_visible, c:'\n',
  261.                           s:"visible_named = ", s:current_visible_named);*/
  262.                    
  263.                     // make sure that this line is visible.
  264.                     ConvInternal_Strings[current_item] = current_string;
  265.                     ConvInternal_Visible[current_item] = current_visible;
  266.                     ConvInternal_VisibleNamed[current_item] = current_visible_named;
  267.                     ConvInternal_CanActivate[current_item] = current_can_activate;
  268.                     ConvInternal_CanActivateNamed[current_item] = current_can_activate_named;
  269.                     ConvInternal_Target[current_item] = current_target;
  270.                     ConvInternal_TargetNamed[current_item] = current_target_named;
  271.                     if (ConvInternal_CallScriptResult(ZZCONV_VISIBLE, current_item, 1))
  272.                     {
  273.                         if (current_default)
  274.                             ConvInternal_CurrentItem = ConvInternal_Count;
  275.                         ConvInternal_Count++;
  276.                         current_item++;
  277.                     }
  278.                    
  279.                     // nullify the temporary data
  280.                     current_string = "";
  281.                     current_can_activate = 0;
  282.                     current_can_activate_named = "";
  283.                     current_target = 0;
  284.                     current_target_named = "";
  285.                     current_visible = 0;
  286.                     current_visible_named = "";
  287.                     current_default = false;
  288.                 }
  289.             }
  290.             else if (!reading_text && ch == '[')
  291.             {
  292.                 reading_metadata = true;
  293.                 reading_parameter = true;
  294.                 reading_value = false;
  295.                 current_parameter = "";
  296.                 current_value = "";
  297.             }
  298.             else
  299.             {
  300.                 current_string = strparam(s:current_string, c:ch);
  301.             }
  302.         }
  303.         else
  304.         {
  305.             // if reading parameter, append to parameter (if not = or ] or ,)
  306.             // if reading value, append to value (if not ] or ,)
  307.             if (!reading_args && (ch == ',' || ch == ']')) // end of current parameter
  308.             {
  309.                 // current_parameter = name, current_value = value.
  310.                 if (ch == ']')
  311.                 {
  312.                     reading_metadata = false;
  313.                     reading_parameter = false;
  314.                 }
  315.                 else // ,
  316.                 {
  317.                     reading_parameter = true;
  318.                 }
  319.                
  320.                 reading_value = false;
  321.  
  322.                 // parse parameter and value here
  323.  
  324.                 //print(s:current_parameter);
  325.                 //print(s:current_value);
  326.                
  327.                 // ZDoom 2.7.x promises that we can compare strings with ==
  328.                 if (!strcmp(current_parameter, "visible"))
  329.                 {
  330.                     current_visible = ConvInternal_StrToInt(ConvInternal_ParseScriptArgs(current_value, 0, current_item));
  331.                     current_visible_named = "";
  332.                 }
  333.                 else if (!strcmp(current_parameter, "visible_named"))
  334.                 {
  335.                     current_visible = 0;
  336.                     current_visible_named = ConvInternal_ParseScriptArgs(current_value, 0, current_item);
  337.                 }
  338.                 else if (!strcmp(current_parameter, "can_activate"))
  339.                 {
  340.                     current_can_activate = ConvInternal_StrToInt(ConvInternal_ParseScriptArgs(current_value, 1, current_item));
  341.                     current_can_activate_named = "";
  342.                 }
  343.                 else if (!strcmp(current_parameter, "can_activate_named"))
  344.                 {
  345.                     current_can_activate = 0;
  346.                     current_can_activate_named = ConvInternal_ParseScriptArgs(current_value, 1, current_item);
  347.                 }
  348.                 else if (!strcmp(current_parameter, "target"))
  349.                 {
  350.                     current_target = ConvInternal_StrToInt(ConvInternal_ParseScriptArgs(current_value, 2, current_item));
  351.                     current_target_named = "";
  352.                 }
  353.                 else if (!strcmp(current_parameter, "target_named"))
  354.                 {
  355.                     current_target = 0;
  356.                     current_target_named = ConvInternal_ParseScriptArgs(current_value, 2, current_item);
  357.                 }
  358.                 else if (!strcmp(current_parameter, "default"))
  359.                 {
  360.                     current_default = true;
  361.                 }
  362.  
  363.                 current_parameter = "";
  364.                 current_value = "";
  365.             }
  366.             else if (reading_parameter)
  367.             {
  368.                 if (ch == '=')
  369.                 {
  370.                     reading_value = true;
  371.                     reading_parameter = false;
  372.                 }
  373.                 else
  374.                 {
  375.                     current_parameter = strparam(s:current_parameter, c:ch);
  376.                 }
  377.             }
  378.             else if (reading_value)
  379.             {
  380.                 if (ch == '(')
  381.                 {
  382.                     reading_args = true;
  383.                 }
  384.                 else if (ch == ')')
  385.                 {
  386.                     reading_args = false;
  387.                 }
  388.                
  389.                 current_value = strparam(s:current_value, c:ch);
  390.             }
  391.         }
  392.     }
  393.    
  394.     return true;
  395. }
  396.  
  397. script 999 ENTER CLIENTSIDE
  398. {
  399.     // I have literally NO IDEA if this will compile with non-Zandronum headers.
  400.     if (PlayerNumber() != ConsolePlayerNumber())
  401.         terminate;
  402.  
  403.     int repeat_timer = 0;
  404.     bool last_conv_active = false;
  405.     bool last_use_active = true; // we sometimes get the dialogue as the result of pressing use.
  406.                                   // and we don't want that use to be understood as the "conversation" use.
  407.    
  408.     while (true)
  409.     {
  410.         int pib = GetPlayerInput(-1, INPUT_BUTTONS);
  411.         int pim = GetPlayerInput(-1, INPUT_FORWARDMOVE);
  412.        
  413.         SetHudSize(800, 600, true);
  414.        
  415.         if (ConvInternal_Active)
  416.         {
  417.             if (!last_conv_active)
  418.             {
  419.                 // make the player immobile.
  420.                 SetPlayerProperty(0, 1, PROP_TOTALLYFROZEN);
  421.             }
  422.             last_conv_active = true;
  423.            
  424.             if (!(pib & BT_USE)) last_use_active = false;
  425.            
  426.             // draw all items. active item = gold, inactive item = gray, unselectable item = dark gray
  427.             int offsetx = 32.1;
  428.             int offsety = 600.1 - ConvInternal_Count * 16.0 - 16.0;
  429.             for (int i = 0; i < ConvInternal_Count; i++)
  430.             {
  431.                 int color = CR_BLACK;
  432.                 if (Conversation_CheckActiveChoice(i))
  433.                 {
  434.                     if (i == ConvInternal_CurrentItem)
  435.                         color = CR_GOLD;
  436.                     else color = CR_GRAY;
  437.                 }
  438.                
  439.                 SetFont("BIGFONT");
  440.                 HudMessage(s:ConvInternal_Strings[i]; HUDMSG_PLAIN, 1200+i, color, offsetx, offsety, 0.03);
  441.                
  442.                 if (color == CR_GOLD && (Timer()%16 < 8)) // mark selected active item!
  443.                 {
  444.                     HudMessage(c:'>'; HUDMSG_PLAIN, 1198, CR_GOLD, offsetx-16.0, offsety, 0.03);
  445.                 }
  446.                
  447.                 offsety += 16.0;
  448.             }
  449.            
  450.             // draw actual text
  451.             HudMessage(s:ConvInternal_Text; HUDMSG_PLAIN, 1199, CR_RED, offsetx, 600.2 - ConvInternal_Count * 16.0 - 24.0, 0.03);
  452.            
  453.             // action processing (item selection, item activation)
  454.             // up button
  455.             if (pim != 0) // positive
  456.             {
  457.                 if (Timer()-repeat_timer > 5) // if we hold forward/backward keys, don't allow us to change too quickly
  458.                 {
  459.                     int change_to = -1;
  460.                    
  461.                     if (pim < 0) // down
  462.                     {
  463.                         // don't allow inactive choices
  464.                         for (int j = ConvInternal_CurrentItem+1; j < ConvInternal_Count; j++)
  465.                         {
  466.                             if (Conversation_CheckActiveChoice(j))
  467.                             {
  468.                                 change_to = j;
  469.                                 break;
  470.                             }
  471.                         }
  472.                     }
  473.                     else // up
  474.                     {
  475.                         // active item can be -1. for down its handled naturally (-1+1=0), but not here.
  476.                         int kstart;
  477.                         if (ConvInternal_CurrentItem < 0) kstart = ConvInternal_Count-1;
  478.                         else kstart = ConvInternal_CurrentItem-1;
  479.                         for (int k = kstart; k >= 0; k--)
  480.                         {
  481.                             if (Conversation_CheckActiveChoice(k))
  482.                             {
  483.                                 change_to = k;
  484.                                 break;
  485.                             }
  486.                         }
  487.                     }
  488.                    
  489.                     if (change_to >= 0)
  490.                         ConvInternal_CurrentItem = change_to;
  491.                    
  492.                     repeat_timer = Timer();
  493.                 }
  494.             }
  495.             else if (pib & BT_USE && !last_use_active)
  496.             {
  497.                 if (Timer()-repeat_timer > 5)
  498.                 {
  499.                     // try to activate current item
  500.                     if (Conversation_CheckActiveChoice(ConvInternal_CurrentItem))
  501.                     {
  502.                         // deactivate conversation
  503.                         ConvInternal_Active = false;
  504.                         ConvInternal_CallScript(ZZCONV_TARGET, ConvInternal_CurrentItem);
  505.                     }
  506.                     repeat_timer = Timer();
  507.                 }
  508.             }
  509.         }
  510.         else
  511.         {
  512.             if (last_conv_active)
  513.             {
  514.                 // make the player mobile.
  515.                 SetPlayerProperty(0, 0, PROP_TOTALLYFROZEN);
  516.                 last_use_active = true;
  517.             }
  518.             last_conv_active = false;
  519.         }
  520.        
  521.         Delay(1);
  522.     }
  523. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement