Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "zcommon.acs"
- #library "ZZCONV"
- #define CONV_MAX_PLAYERS 64
- #define CONV_MAX_ITEMS 64
- bool ConvInternal_Active[CONV_MAX_PLAYERS];
- int ConvInternal_Count[CONV_MAX_PLAYERS];
- str ConvInternal_Text[CONV_MAX_PLAYERS];
- str ConvInternal_Strings[CONV_MAX_PLAYERS][CONV_MAX_ITEMS];
- int ConvInternal_Visible[CONV_MAX_PLAYERS][CONV_MAX_ITEMS];
- int ConvInternal_CanActivate[CONV_MAX_PLAYERS][CONV_MAX_ITEMS];
- int ConvInternal_Target[CONV_MAX_PLAYERS][CONV_MAX_ITEMS];
- int ConvInternal_VisibleArgs[CONV_MAX_PLAYERS][CONV_MAX_ITEMS*3];
- int ConvInternal_CanActivateArgs[CONV_MAX_PLAYERS][CONV_MAX_ITEMS*3];
- int ConvInternal_TargetArgs[CONV_MAX_PLAYERS][CONV_MAX_ITEMS*3];
- int ConvInternal_VisibleNamed[CONV_MAX_PLAYERS][CONV_MAX_ITEMS];
- int ConvInternal_CanActivateNamed[CONV_MAX_PLAYERS][CONV_MAX_ITEMS];
- int ConvInternal_TargetNamed[CONV_MAX_PLAYERS][CONV_MAX_ITEMS];
- int ConvInternal_CurrentItem[CONV_MAX_PLAYERS];
- script "zzconv_initializer" OPEN
- {
- for (int i = 0; i < CONV_MAX_PLAYERS; i++)
- {
- ConvInternal_CurrentItem[i] = -1;
- ConvInternal_Text[i] = "";
- ConvInternal_Count[i] = 0;
- ConvInternal_Active[i] = false;
- }
- }
- // access to 2d arrays:
- // PlayerNumber() * CONV_MAX_PLAYERS + item
- // access to 3d arrays:
- // PlayerNumber() * CONV_MAX_PLAYERS3 + item * 3 + arg
- #define ZZCONV_VISIBLE 0
- #define ZZCONV_CAN_ACTIVATE 1
- #define ZZCONV_TARGET 2
- int ciargs[3]; // this is to support old zdoom
- function void ConvInternal_CallScript(int where, int num)
- {
- int j;
- int scr;
- str named_scr;
- switch(where)
- {
- case ZZCONV_VISIBLE:
- scr = ConvInternal_Visible[PlayerNumber()][num];
- named_scr = ConvInternal_VisibleNamed[PlayerNumber()][num];
- for (j = 0; j < 3; j++)
- ciargs[j] = ConvInternal_VisibleArgs[PlayerNumber()][num*3+j];
- break;
- case ZZCONV_CAN_ACTIVATE:
- scr = ConvInternal_CanActivate[PlayerNumber()][num];
- named_scr = ConvInternal_CanActivateNamed[PlayerNumber()][num];
- for (j = 0; j < 3; j++)
- ciargs[j] = ConvInternal_CanActivateArgs[PlayerNumber()][num*3+j];
- break;
- case ZZCONV_TARGET:
- scr = ConvInternal_Target[PlayerNumber()][num];
- named_scr = ConvInternal_TargetNamed[PlayerNumber()][num];
- for (j = 0; j < 3; j++)
- ciargs[j] = ConvInternal_TargetArgs[PlayerNumber()][num*3+j];
- break;
- default:
- return;
- }
- if (scr) ACS_ExecuteAlways(scr, 0, ciargs[0], ciargs[1], ciargs[2]);
- else if (strlen(named_scr)) ACS_NamedExecuteAlways(named_scr, 0, ciargs[0], ciargs[1], ciargs[2]);
- }
- function int ConvInternal_CallScriptResult(int where, int num, int def)
- {
- int j;
- int scr;
- str named_scr;
- switch(where)
- {
- case ZZCONV_VISIBLE:
- scr = ConvInternal_Visible[PlayerNumber()][num];
- named_scr = ConvInternal_VisibleNamed[PlayerNumber()][num];
- for (j = 0; j < 3; j++)
- ciargs[j] = ConvInternal_VisibleArgs[PlayerNumber()][num*3+j];
- break;
- case ZZCONV_CAN_ACTIVATE:
- scr = ConvInternal_CanActivate[PlayerNumber()][num];
- named_scr = ConvInternal_CanActivateNamed[PlayerNumber()][num];
- for (j = 0; j < 3; j++)
- ciargs[j] = ConvInternal_CanActivateArgs[PlayerNumber()][num*3+j];
- break;
- case ZZCONV_TARGET:
- scr = ConvInternal_Target[PlayerNumber()][num];
- named_scr = ConvInternal_TargetNamed[PlayerNumber()][num];
- for (j = 0; j < 3; j++)
- ciargs[j] = ConvInternal_TargetArgs[PlayerNumber()][num*3+j];
- break;
- default:
- return def;
- }
- if (scr) return ACS_ExecuteWithResult(scr, ciargs[0], ciargs[1], ciargs[2]);
- else if (strlen(named_scr)) ACS_NamedExecuteWithResult(named_scr, ciargs[0], ciargs[1], ciargs[2], 0);
- return def;
- }
- function int ConvInternal_StrToInt(str string)
- {
- int integer = 0;
- int string_len = strlen(string);
- int mul = 1;
- for (int i = string_len-1; i >= 0; i--)
- {
- int ch_raw = getchar(string, i);
- if (ch_raw < '0' || ch_raw > '9')
- {
- if (ch_raw == '-' && i == 0) // this should be the last (oops, I mean first) character
- {
- return -integer;
- }
- else
- {
- return 0;
- }
- }
- ch_raw -= '0';
- integer += ch_raw * mul;
- mul *= 10;
- }
- return integer;
- }
- function bool Conversation_CheckActiveChoice(int num)
- {
- if (num < 0 || num >= ConvInternal_Count[PlayerNumber()])
- return false;
- return !!ConvInternal_CallScriptResult(ZZCONV_CAN_ACTIVATE, num, 1);
- }
- function str ConvInternal_ParseScriptArgs(str sc, int where, int num)
- {
- // returns new str.
- str out_sc = "";
- bool in_args = false;
- int argc = 0;
- str arg = "";
- for (int i = 0; i < strlen(sc); i++)
- {
- int ch = getchar(sc, i);
- if (in_args)
- {
- if (ch == ')' || ch == ',')
- {
- if (ch == ')')
- {
- in_args = false;
- break;
- }
- // arg = current arg.
- ciargs[argc] = ConvInternal_StrToInt(arg);
- argc++;
- arg = "";
- if (argc >= 3)
- {
- in_args = false; // more than 3 args isn't supported
- break;
- }
- continue;
- }
- arg = strparam(s:arg, c:ch);
- continue;
- }
- else
- {
- if (ch == '(')
- {
- in_args = true;
- continue;
- }
- }
- out_sc = strparam(s:out_sc, c:ch);
- }
- // argv should contain args now.
- // argc should contain arg count, although we'll copy all 3 anyway
- int j;
- switch(where)
- {
- case ZZCONV_VISIBLE:
- for (j = 0; j < 3; j++)
- ConvInternal_VisibleArgs[PlayerNumber()][num*3+j] = ciargs[j];
- break;
- case ZZCONV_CAN_ACTIVATE:
- for (j = 0; j < 3; j++)
- ConvInternal_CanActivateArgs[PlayerNumber()][num*3+j] = ciargs[j];
- break;
- case ZZCONV_TARGET:
- for (j = 0; j < 3; j++)
- ConvInternal_TargetArgs[PlayerNumber()][num*3+j] = ciargs[j];
- break;
- default:
- break;
- }
- return out_sc;
- }
- function bool Conversation_Init(str format)
- {
- if (ConvInternal_Active[PlayerNumber()]) // you must deactivate the current conversation EXPLICITLY to switch a conversation screen.
- return false;
- format = strparam(s:format, c:'\n');
- // format is as follows:
- // <anything>[parameter=value,parameter=value]
- // example:
- // Hi[visible=10,target=11]
- int current_item = 0;
- int format_len = strlen(format);
- // now item-local declarations
- bool reading_text = true;
- bool reading_metadata = false; // after [
- bool reading_parameter = false;
- bool reading_value = false;
- bool reading_args = false;
- str current_parameter = "";
- str current_value = "";
- str current_string = "";
- int current_can_activate = 0;
- str current_can_activate_named = "";
- int current_target = 0;
- str current_target_named = "";
- int current_visible = 0;
- str current_visible_named = "";
- bool current_default = false;
- ConvInternal_Count[PlayerNumber()] = 0;
- ConvInternal_CurrentItem[PlayerNumber()] = -1; // current active item is -1, means no item is selected.
- ConvInternal_Active[PlayerNumber()] = true; // activate the conversation
- for (int i = 0; i <= format_len; i++)
- {
- int ch = getchar(format, i);
- // if not reading metadata, this is either start of metadata or actual string.
- if (!reading_metadata)
- {
- if (ch == '\n') // save.
- {
- if (reading_text)
- {
- ConvInternal_Text[PlayerNumber()] = current_string;
- reading_text = false;
- current_string = "";
- }
- else
- {
- // test logging
- /*
- print(s:"string = ", s:current_string, c:'\n',
- s:"can_activate = ", d:current_can_activate, c:'\n',
- s:"can_activate_named = ", s:current_can_activate_named, c:'\n',
- s:"target = ", d:current_target, c:'\n',
- s:"target_named = ", s:current_target_named, c:'\n',
- s:"visible = ", d:current_visible, c:'\n',
- s:"visible_named = ", s:current_visible_named);*/
- // make sure that this line is visible.
- ConvInternal_Strings[PlayerNumber()][current_item] = current_string;
- ConvInternal_Visible[PlayerNumber()][current_item] = current_visible;
- ConvInternal_VisibleNamed[PlayerNumber()][current_item] = current_visible_named;
- ConvInternal_CanActivate[PlayerNumber()][current_item] = current_can_activate;
- ConvInternal_CanActivateNamed[PlayerNumber()][current_item] = current_can_activate_named;
- ConvInternal_Target[PlayerNumber()][current_item] = current_target;
- ConvInternal_TargetNamed[PlayerNumber()][current_item] = current_target_named;
- if (ConvInternal_CallScriptResult(ZZCONV_VISIBLE, current_item, 1))
- {
- if (current_default)
- ConvInternal_CurrentItem[PlayerNumber()] = ConvInternal_Count[PlayerNumber()];
- ConvInternal_Count[PlayerNumber()]++;
- current_item++;
- }
- // nullify the temporary data
- current_string = "";
- current_can_activate = 0;
- current_can_activate_named = "";
- current_target = 0;
- current_target_named = "";
- current_visible = 0;
- current_visible_named = "";
- current_default = false;
- }
- }
- else if (!reading_text && ch == '[')
- {
- reading_metadata = true;
- reading_parameter = true;
- reading_value = false;
- current_parameter = "";
- current_value = "";
- }
- else
- {
- if (reading_text && ch == '\\') // we can use \\n to have multiple lines in the conversation header
- {
- if (getchar(format, i+1) == 'n')
- {
- current_string = strparam(s:current_string, c:'\n');
- i++;
- continue;
- }
- }
- current_string = strparam(s:current_string, c:ch);
- }
- }
- else
- {
- // if reading parameter, append to parameter (if not = or ] or ,)
- // if reading value, append to value (if not ] or ,)
- if (!reading_args && (ch == ',' || ch == ']')) // end of current parameter
- {
- // current_parameter = name, current_value = value.
- if (ch == ']')
- {
- reading_metadata = false;
- reading_parameter = false;
- }
- else // ,
- {
- reading_parameter = true;
- }
- reading_value = false;
- // parse parameter and value here
- //print(s:current_parameter);
- //print(s:current_value);
- // ZDoom 2.7.x promises that we can compare strings with ==
- if (!strcmp(current_parameter, "visible"))
- {
- current_visible = ConvInternal_StrToInt(ConvInternal_ParseScriptArgs(current_value, 0, current_item));
- current_visible_named = "";
- }
- else if (!strcmp(current_parameter, "visible_named"))
- {
- current_visible = 0;
- current_visible_named = ConvInternal_ParseScriptArgs(current_value, 0, current_item);
- }
- else if (!strcmp(current_parameter, "can_activate"))
- {
- current_can_activate = ConvInternal_StrToInt(ConvInternal_ParseScriptArgs(current_value, 1, current_item));
- current_can_activate_named = "";
- }
- else if (!strcmp(current_parameter, "can_activate_named"))
- {
- current_can_activate = 0;
- current_can_activate_named = ConvInternal_ParseScriptArgs(current_value, 1, current_item);
- }
- else if (!strcmp(current_parameter, "target"))
- {
- current_target = ConvInternal_StrToInt(ConvInternal_ParseScriptArgs(current_value, 2, current_item));
- current_target_named = "";
- }
- else if (!strcmp(current_parameter, "target_named"))
- {
- current_target = 0;
- current_target_named = ConvInternal_ParseScriptArgs(current_value, 2, current_item);
- }
- else if (!strcmp(current_parameter, "default"))
- {
- current_default = true;
- }
- current_parameter = "";
- current_value = "";
- }
- else if (reading_parameter)
- {
- if (ch == '=')
- {
- reading_value = true;
- reading_parameter = false;
- }
- else
- {
- current_parameter = strparam(s:current_parameter, c:ch);
- }
- }
- else if (reading_value)
- {
- if (ch == '(')
- {
- reading_args = true;
- }
- else if (ch == ')')
- {
- reading_args = false;
- }
- current_value = strparam(s:current_value, c:ch);
- }
- }
- }
- return true;
- }
- function int Clamp(int what, int min, int max)
- {
- if (what < min) return min;
- if (what > max) return max;
- return what;
- }
- function int GetCVarFixed(str name)
- {
- str c = GetCVarString(name);
- // [-|+][123123123][.123123123]
- int part_integer = 0;
- int part_fractional = 0;
- // first, get the location of the dot
- int i;
- int dot = 0;
- for (i = 0; i < StrLen(c); i++)
- {
- if (GetChar(c, i) == '.')
- break;
- }
- dot = i;
- bool negative = false;
- for (i = 0; i < dot; i++)
- {
- if (i == 0 && (GetChar(c, i) == '-'))
- {
- negative = true;
- }
- else
- {
- int ch = GetChar(c, i);
- ch -= 0x30;
- int countOr = dot-i-1;
- for (int j = 0; j < countOr; j++)
- ch *= 10;
- part_integer += ch;
- }
- }
- for (i = dot+1; i < StrLen(c); i++)
- {
- ch = GetChar(c, i);
- ch -= 0x30;
- ch <<= 16;
- countOr = i-dot;
- for (j = 0; j < countOr; j++)
- ch /= 10;
- part_fractional += ch;
- }
- return ((part_integer & 0xFFFF) << 16) | (part_fractional & 0xFFFF);
- }
- script "zzconv_gui" ENTER
- {
- // I have literally NO IDEA if this will compile with non-Zandronum headers.
- //if (PlayerNumber() != ConsolePlayerNumber())
- // terminate;
- int repeat_timer = 0;
- bool last_conv_active = false;
- bool last_use_active = true; // we sometimes get the dialogue as the result of pressing use.
- // and we don't want that use to be understood as the "conversation" use.
- int disp_width = 800;
- int disp_height = 600;
- int mouse_x = (disp_width / 2) << 16;
- int mouse_y = (disp_height / 2) << 16;
- int hmt; // for cycles
- bool MouseWasDown = false;
- bool MouseDown = false;
- bool UseMouse = false;
- while (true)
- {
- int pib = GetPlayerInput(-1, INPUT_BUTTONS);
- int pim = GetPlayerInput(-1, INPUT_FORWARDMOVE);
- bool buse = (pib & BT_ATTACK) || (pib & BT_USE);
- bool buse2 = (pib & BT_ATTACK); // attack is only for mouse
- if (ConvInternal_Active[PlayerNumber()])
- {
- // move the mouse.
- // the following code is copypasted from my relatively old MouseInGZDoom.wad
- int DeltaX = -GetPlayerInput(-1, INPUT_YAW);
- int DeltaY = -GetPlayerInput(-1, INPUT_PITCH);
- if (DeltaX != 0 || DeltaY != 0 || buse2) // either coordinate change or left click
- {
- UseMouse = true;
- int m_yaw = GetCVarFixed("m_yaw");
- int m_pitch = GetCVarFixed("m_pitch");
- int mouse_sensitivity = GetCVarFixed("mouse_sensitivity"); // ok lets not touch this part
- DeltaX = FixedDiv(DeltaX, m_yaw);
- DeltaY = FixedDiv(DeltaY, m_pitch);
- if (!StrCmp(GetCVarString("invertmouse"), "true", 4))
- DeltaY = -DeltaY;
- // еÑли вÑÑ Ñавно нÑжно mouse_sensitivity ÑÑиÑÑваÑÑ, ÑаÑкомменÑиваем
- DeltaX = FixedDiv(DeltaX, mouse_sensitivity);
- DeltaY = FixedDiv(DeltaY, mouse_sensitivity);
- mouse_x += DeltaX*0.05;
- mouse_y += DeltaY*0.05;
- mouse_x = Clamp(mouse_x, 0, disp_width<<16);
- mouse_y = Clamp(mouse_y, 0, disp_height<<16);
- // debug message
- //SetFont("SMALLFONT");
- //HudMessage(f:mouse_x, c:'\n', f:mouse_y, c:'\n', c:'\n', f:DeltaX, c:'\n', f:DeltaY; HUDMSG_PLAIN, 0, CR_GOLD, 0.1, 0.1, 1.0);
- MouseWasDown = MouseDown;
- MouseDown = buse; // attack is typically mouse1, which is buse
- }
- if (pim != 0) // keyboard was used
- {
- MouseWasDown = false;
- MouseDown = false;
- UseMouse = false;
- }
- // PROCESS MOUSE
- // check if mouse was moved actively.
- if (UseMouse)
- {
- int moffsetx = 32.0;
- int moffsetx2 = (disp_width << 16) - 32.0;
- int moffsety = (disp_height << 16) - ConvInternal_Count[PlayerNumber()] * 16.0 - 16.0;
- ConvInternal_CurrentItem[PlayerNumber()] = -1;
- if (mouse_x >= moffsetx && mouse_x < moffsetx2)
- {
- for (int mi = 0; mi < ConvInternal_Count[PlayerNumber()]; mi++) // god damn the un-scoped variables
- {
- int moffsety2 = moffsety + 16.0;
- if (mouse_y >= moffsety && mouse_y < moffsety2)
- {
- ConvInternal_CurrentItem[PlayerNumber()] = mi; // this line is hovered
- break;
- }
- moffsety += 16.0;
- }
- }
- }
- SetHudSize(disp_width, disp_height, true);
- if (!last_conv_active)
- {
- // make the player immobile.
- SetPlayerProperty(0, 1, PROP_TOTALLYFROZEN);
- }
- last_conv_active = true;
- if (!buse) last_use_active = false;
- // draw all items. active item = gold, inactive item = gray, unselectable item = dark gray
- int offsetx = 32.1;
- int offsety = ((disp_height << 16) + 0.1) - ConvInternal_Count[PlayerNumber()] * 16.0 - 16.0;
- bool anygold = false;
- for (int i = 0; i < ConvInternal_Count[PlayerNumber()]; i++)
- {
- int color = CR_BLACK;
- if (Conversation_CheckActiveChoice(i))
- {
- if (i == ConvInternal_CurrentItem[PlayerNumber()])
- color = CR_GOLD;
- else color = CR_GRAY;
- }
- SetFont("FONT1");
- HudMessage(s:ConvInternal_Strings[PlayerNumber()][i]; HUDMSG_PLAIN, 1200+i, color, offsetx, offsety, 40.0);
- if (color == CR_GOLD && (Timer()%35 < 17)) // mark selected active item!
- {
- HudMessage(s:">"; HUDMSG_PLAIN, 1198, CR_GOLD, offsetx-16.0, offsety, 40.0);
- anygold = true;
- }
- else if (color == CR_GOLD)
- {
- HudMessage(s:""; HUDMSG_PLAIN, 1198, CR_GOLD, offsetx-16.0, offsety, 40.0);
- anygold = true;
- }
- offsety += 16.0;
- }
- if (!anygold)
- HudMessage(s:""; HUDMSG_PLAIN, 1198, CR_GOLD, 0, 0, 0); // remove the cursor if nothing is selected
- // draw actual text
- HudMessage(s:ConvInternal_Text[PlayerNumber()]; HUDMSG_PLAIN, 1199, CR_RED, offsetx, ((disp_height << 16) + 0.2) - ConvInternal_Count[PlayerNumber()] * 16.0 - 24.0, 40.0);
- // action processing (item selection, item activation)
- // up button
- if (pim != 0) // positive
- {
- if (Timer()-repeat_timer > 5) // if we hold forward/backward keys, don't allow us to change too quickly
- {
- int change_to = -1;
- if (pim < 0) // down
- {
- // don't allow inactive choices
- for (int j = ConvInternal_CurrentItem[PlayerNumber()]+1; j < ConvInternal_Count[PlayerNumber()]; j++)
- {
- if (Conversation_CheckActiveChoice(j))
- {
- change_to = j;
- break;
- }
- }
- }
- else // up
- {
- // active item can be -1. for down its handled naturally (-1+1=0), but not here.
- int kstart;
- if (ConvInternal_CurrentItem[PlayerNumber()] < 0) kstart = ConvInternal_Count[PlayerNumber()]-1;
- else kstart = ConvInternal_CurrentItem[PlayerNumber()]-1;
- for (int k = kstart; k >= 0; k--)
- {
- if (Conversation_CheckActiveChoice(k))
- {
- change_to = k;
- break;
- }
- }
- }
- if (change_to >= 0)
- ConvInternal_CurrentItem[PlayerNumber()] = change_to;
- repeat_timer = Timer();
- }
- }
- else if (buse && !last_use_active)
- {
- if (Timer()-repeat_timer > 5)
- {
- // try to activate current item
- if (Conversation_CheckActiveChoice(ConvInternal_CurrentItem[PlayerNumber()]))
- {
- // deactivate conversation
- ConvInternal_Active[PlayerNumber()] = false;
- for (hmt = 1197; hmt < 1200+CONV_MAX_ITEMS; hmt++)
- HudMessage(s:""; HUDMSG_PLAIN, hmt, CR_RED, 0, 0, 0);
- ConvInternal_CallScript(ZZCONV_TARGET, ConvInternal_CurrentItem[PlayerNumber()]);
- }
- repeat_timer = Timer();
- }
- }
- // render mouse
- if (UseMouse)
- {
- SetFont("MOUSE");
- HudMessage(s:"A"; HUDMSG_PLAIN, 1197, CR_UNTRANSLATED, (mouse_x & 0xFFFF0000) + 0.1 - 4.0, (mouse_y & 0xFFFF0000) + 0.1 - 4.0, 40.0);
- }
- else
- {
- HudMessage(s:""; HUDMSG_PLAIN, 1197, CR_UNTRANSLATED, 0, 0, 0);
- }
- }
- else
- {
- if (last_conv_active)
- {
- last_conv_active = false;
- // reset mouse
- mouse_x = ((disp_width / 2) << 16) + 0.1;
- mouse_y = ((disp_height / 2) << 16) + 0.1;
- MouseWasDown = false;
- MouseDown = false;
- UseMouse = false;
- // erase hudmessages
- for (hmt = 1197; hmt < 1200+CONV_MAX_ITEMS; hmt++)
- HudMessage(s:""; HUDMSG_PLAIN, hmt, CR_RED, 0, 0, 0);
- // make the player mobile.
- last_use_active = true;
- Delay(1); // wait for a while. this is to release attack button.
- SetPlayerProperty(0, 0, PROP_TOTALLYFROZEN);
- }
- }
- Delay(1);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement