Beispiel #1
0
/* Parses command line arguments and stores them in a struct */
cc_error_t cc_parse_args(int argc, char* argv[], Options* options) {
    options->buffersize    = DEFAULT_BUFFER_SIZE;
    options->outfile_index = -1;
    options->argc          = argc;
    options->argv          = argv;
    options->mode          = DEFAULT_FILE_PERM;

    int c;
    while ((c = getopt(argc, argv, "+b:m:o:vh")) != -1) {
        switch (c) {
            case 'b':
                if ( !sscanf(optarg, "%u", &options->buffersize) )
                    cc_error(CC_USAGE);
                break;
            case 'm':
                if ( !sscanf(optarg, "%o", &options->mode) )
                    cc_error(CC_USAGE);
                break;
            case 'o':
                options->outfile_index = optind-1;
                break;
            case 'v':
                options->verbose = 1;
                break;
            case 'h':
                cc_error(CC_USAGE);
                break;
            case '?':
                cc_error(CC_USAGE);
                break;
        }
    }

    options->infiles_index = optind;

    return CC_NONE;
}
Beispiel #2
0
int call_function(intptr_t addr, const RuntimeScriptValue *object, int numparm, const RuntimeScriptValue *parms)
{
    if (!addr)
    {
        cc_error("null function pointer in call_function");
        return -1;
    }
    if (numparm > 0 && !parms)
    {
        cc_error("invalid parameters array in call_function");
        return -1;
    }

    intptr_t parm_value[9];
    if (object)
    {
        parm_value[0] = (intptr_t)object->GetPtrWithOffset();
        numparm++;
    }

    for (int ival = object ? 1 : 0, iparm = 0; ival < numparm; ++ival, ++iparm)
    {
        switch (parms[iparm].Type)
        {
        case kScValInteger:
        case kScValFloat:   // AGS passes floats, copying their values into long variable
        case kScValPluginArg:
            parm_value[ival] = (intptr_t)parms[iparm].IValue;
            break;
            break;
        default:
            parm_value[ival] = (intptr_t)parms[iparm].GetPtrWithOffset();
            break;
        }
    }

    //
    // AN IMPORTANT NOTE ON PARAM TYPE
    // of 2012-11-10
    //
    //// NOTE of 2012-12-20:
    //// Everything said below is applicable only for calling
    //// exported plugin functions.
    //
    // Here we are sending parameters of type intptr_t to registered
    // function of unknown kind. Intptr_t is 32-bit for x32 build and
    // 64-bit for x64 build.
    // The exported functions usually have two types of parameters:
    // pointer and 'int' (32-bit). For x32 build those two have the
    // same size, but for x64 build first has 64-bit size while the
    // second remains 32-bit.
    // In formal case that would cause 'overflow' - function will
    // receive more data than needed (written to stack), with some
    // values shifted further by 32 bits.
    //
    // Upon testing, however, it was revealed that AMD64 processor,
    // the only platform we support x64 Linux AGS build on right now,
    // treats all the function parameters pushed to stack as 64-bit
    // values (few first parameters are sent via registers, and hence
    // are least concern anyway). Therefore, no 'overflow' occurs,
    // and 64-bit values are being effectively truncated to 32-bit
    // integers in the callee.
    //
    // Since this is still quite unreliable, this should be
    // reimplemented when there's enough free time available for
    // developers both for coding & testing.
    //
    // Most basic idea is to pass array of RuntimeScriptValue
    // objects (that hold type description) and get same RSV as a
    // return result. Keep in mind, though, that this solution will
    // require fixing ALL exported functions, so a good amount of
    // time and energy should be allocated for this task.
    //

    switch (numparm)
    {
    case 0:
        {
            int (*fparam) ();
            fparam = (int (*)())addr;
            return fparam();
        }
    case 1:
        {
            int (*fparam) (intptr_t);
            fparam = (int (*)(intptr_t))addr;
            return fparam(parm_value[0]);
        }
    case 2:
        {
            int (*fparam) (intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1]);
        }
    case 3:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2]);
        }
    case 4:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2], parm_value[3]);
        }
    case 5:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2], parm_value[3], parm_value[4]);
        }
    case 6:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2], parm_value[3], parm_value[4], parm_value[5]);
        }
    case 7:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2], parm_value[3], parm_value[4], parm_value[5], parm_value[6]);
        }
    case 8:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2], parm_value[3], parm_value[4], parm_value[5], parm_value[6], parm_value[7]);
        }
    case 9:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2], parm_value[3], parm_value[4], parm_value[5], parm_value[6], parm_value[7], parm_value[8]);
        }
    }

    cc_error("too many arguments in call to function");
    return -1;
}
Beispiel #3
0
const char *ScriptSprintf(char *buffer, size_t buf_length, const char *format, const RuntimeScriptValue *args, int32_t argc)
{
    if (!buffer)
    {
        cc_error("internal error in ScriptSprintf: buffer is null");
        return "";
    }
    if (!format)
    {
        cc_error("internal error in ScriptSprintf: format string is null");
        return "";
    }
    if (argc > 0 && !args)
    {
        cc_error("internal error in ScriptSprintf: args pointer is null");
        return "";
    }

    // Expected format character count:
    // percent sign:    1
    // flag:            1
    // field width      10 (an uint32 number)
    // precision sign   1
    // precision        10 (an uint32 number)
    // length modifier  2
    // type             1
    // NOTE: although width and precision will
    // not likely be defined by a 10-digit
    // number, such case is theoretically valid.
    const size_t fmtbuf_size = 27;
    char       fmtbuf[fmtbuf_size];
    char       *fmt_bufptr;
    char       *fmt_bufendptr = &fmtbuf[fmtbuf_size - 1];

    char       *out_ptr    = buffer;
    const char *out_endptr = buffer + buf_length;
    const char *fmt_ptr    = format;
    int32_t    arg_idx     = 0;

    ptrdiff_t  avail_outbuf;
    int        snprintf_res;
    FormatParseResult fmt_done;

    // Parse the format string, looking for argument placeholders
    while (*fmt_ptr && out_ptr != out_endptr)
    {
        // Try to put argument into placeholder
        if (*fmt_ptr == '%' && arg_idx < argc)
        {
            avail_outbuf = out_endptr - out_ptr;
            fmt_bufptr = fmtbuf;
            *(fmt_bufptr++) = '%';
            snprintf_res = 0;
            fmt_done = kFormatParseNone;
            const RuntimeScriptValue &arg = args[arg_idx];

            // Parse placeholder
            while (*(++fmt_ptr) && fmt_done == kFormatParseNone && fmt_bufptr != fmt_bufendptr)
            {
                *(fmt_bufptr++) = *fmt_ptr;
                switch (*fmt_ptr)
                {
                case 'd':
                case 'i':
                case 'o':
                case 'u':
                case 'x':
                case 'X':
                case 'c':
                    // Print integer
                    *fmt_bufptr = 0;
                    snprintf_res = snprintf(out_ptr, avail_outbuf, fmtbuf, arg.IValue);
                    fmt_done = kFormatParseArgument;
                    break;
                case 'e':
                case 'E':
                case 'f':
                case 'F':
                case 'g':
                case 'G':
                case 'a':
                case 'A':
                    // Print float
                    *fmt_bufptr = 0;
                    snprintf_res = snprintf(out_ptr, avail_outbuf, fmtbuf, arg.FValue);
                    fmt_done = kFormatParseArgument;
                    break;
                case 's':
                    if (!arg.Ptr)
                    {
                        if (loaded_game_file_version < kGameVersion_320)
                        {
                            // print "(null)" into the placeholder;
                            // NOTE: the behavior of printf("%s", 0) is undefined (MS version prints "(null)",
                            // but there's no guarantee others will), therefore we shouldn't let snprintf do
                            // all the job here.
                            *fmt_bufptr = 0;
                            strncpy(out_ptr, "(null)", avail_outbuf);
                            snprintf_res = Math::Min<ptrdiff_t>(avail_outbuf, 6);
                            fmt_done = kFormatParseArgument;
                            break;
                        }
                        else
                        {
                            cc_error("ScriptSprintf: argument %d is expected to be a string, but it is null pointer", arg_idx);
                            return "";
                        }
                    }
                    else if (arg.Ptr == buffer)
                    {
                        cc_error("ScriptSprintf: argument %d is a pointer to output buffer", arg_idx);
                        return "";
                    }
                    // fall through intended ---
                case 'p':
                    // Print string, or pointer value
                    *fmt_bufptr = 0;
                    snprintf_res = snprintf(out_ptr, avail_outbuf, fmtbuf, arg.Ptr);
                    fmt_done = kFormatParseArgument;
                    break;
                case '%':
                    // This may be a literal percent sign ('%%')
                    if (fmt_bufptr - fmtbuf == 2)
                    {
                        fmt_done = kFormatParseLiteralPercent;
                    }
                    // ...Otherwise we reached the next placeholder
                    else
                    {
                        fmt_ptr--;
                        fmt_bufptr--;
                        fmt_done = kFormatParseInvalid;
                    }
                    break;
                }
            }

            if (fmt_done == kFormatParseArgument)
            {
                out_ptr += snprintf_res >= 0 ? snprintf_res : avail_outbuf;
                arg_idx++;
            }
            else if (fmt_done == kFormatParseLiteralPercent)
            {
                *(out_ptr++) = '%';
            }
            // If placeholder was not valid, just copy stored format buffer as it is
            else
            {
                size_t copy_len = Math::Min(Math::Min<ptrdiff_t>(fmt_bufptr - fmtbuf, fmtbuf_size - 1), avail_outbuf);
                memcpy(out_ptr, fmtbuf, copy_len);
                out_ptr += copy_len;
            }
        }
        // If there's no placeholder, simply copy the character to output buffer
        else
        {
            *(out_ptr++) = *(fmt_ptr++);
        }
    }

    // Terminate the string
    *out_ptr = 0;
    return buffer;
}
Beispiel #4
0
const char *ScriptVSprintf(char *buffer, size_t buf_length, const char *format, va_list &arg_ptr)
{
    if (!buffer)
    {
        cc_error("internal error in ScriptSprintf: buffer is null");
        return "";
    }
    if (!format)
    {
        cc_error("internal error in ScriptSprintf: format string is null");
        return "";
    }

    const size_t fmtbuf_size = 27;
    char       fmtbuf[fmtbuf_size];
    char       *fmt_bufptr;
    char       *fmt_bufendptr = &fmtbuf[fmtbuf_size - 1];

    char       *out_ptr    = buffer;
    const char *out_endptr = buffer + buf_length;
    const char *fmt_ptr    = format;
    int32_t    arg_idx     = 0;

    ptrdiff_t  avail_outbuf;
    int        snprintf_res;
    FormatParseResult fmt_done;

    union VAR_ARG
    {
        int32_t     IValue;
        float       FValue;
        const char  *Ptr;
    } arg;

    // Parse the format string, looking for argument placeholders
    while (*fmt_ptr && out_ptr != out_endptr)
    {
        // Try to put argument into placeholder
        if (*fmt_ptr == '%')
        {
            avail_outbuf = out_endptr - out_ptr;
            fmt_bufptr = fmtbuf;
            *(fmt_bufptr++) = '%';
            snprintf_res = 0;
            fmt_done = kFormatParseNone;

            // Parse placeholder
            while (*(++fmt_ptr) && fmt_done == kFormatParseNone && fmt_bufptr != fmt_bufendptr)
            {
                *(fmt_bufptr++) = *fmt_ptr;
                switch (*fmt_ptr)
                {
                case 'd':
                case 'i':
                case 'o':
                case 'u':
                case 'x':
                case 'X':
                case 'c':
                    // Print integer
                    arg = va_arg(arg_ptr, VAR_ARG);
                    *fmt_bufptr = 0;
                    snprintf_res = snprintf(out_ptr, avail_outbuf, fmtbuf, arg.IValue);
                    fmt_done = kFormatParseArgument;
                    break;
                case 'e':
                case 'E':
                case 'f':
                case 'F':
                case 'g':
                case 'G':
                case 'a':
                case 'A':
                    // Print float
                    arg = va_arg(arg_ptr, VAR_ARG);
                    *fmt_bufptr = 0;
                    snprintf_res = snprintf(out_ptr, avail_outbuf, fmtbuf, arg.FValue);
                    fmt_done = kFormatParseArgument;
                    break;
                case 's':
                    arg = va_arg(arg_ptr, VAR_ARG);
                    if (!arg.Ptr)
                    {
                        if (loaded_game_file_version < kGameVersion_320)
                        {
                            *fmt_bufptr = 0;
                            strncpy(out_ptr, "(null)", avail_outbuf);
                            snprintf_res = Math::Min<ptrdiff_t>(avail_outbuf, 6);
                            fmt_done = kFormatParseArgument;
                            break;
                        }
                        else
                        {
                            cc_error("ScriptSprintf: argument %d is expected to be a string, but it is null pointer", arg_idx);
                            return "";
                        }
                    }
                    else if (arg.Ptr == buffer)
                    {
                        cc_error("ScriptSprintf: argument %d is a pointer to output buffer", arg_idx);
                        return "";
                    }
                    // fall through intended ---
                case 'p':
                    // Print string, or pointer value
                    *fmt_bufptr = 0;
                    snprintf_res = snprintf(out_ptr, avail_outbuf, fmtbuf, arg.Ptr);
                    fmt_done = kFormatParseArgument;
                    break;
                case '%':
                    // This may be a literal percent sign ('%%')
                    if (fmt_bufptr - fmtbuf == 2)
                    {
                        fmt_done = kFormatParseLiteralPercent;
                    }
                    // ...Otherwise we reached the next placeholder
                    else
                    {
                        fmt_ptr--;
                        fmt_bufptr--;
                        fmt_done = kFormatParseInvalid;
                    }
                    break;
                }
            }

            if (fmt_done == kFormatParseArgument)
            {
                out_ptr += snprintf_res >= 0 ? snprintf_res : avail_outbuf;
                arg_idx++;
            }
            else if (fmt_done == kFormatParseLiteralPercent)
            {
                *(out_ptr++) = '%';
            }
            // If placeholder was not valid, just copy stored format buffer as it is
            else
            {
                size_t copy_len = Math::Min(Math::Min<ptrdiff_t>(fmt_bufptr - fmtbuf, fmtbuf_size - 1), avail_outbuf);
                memcpy(out_ptr, fmtbuf, copy_len);
                out_ptr += copy_len;
            }
        }
        // If there's no placeholder, simply copy the character to output buffer
        else
        {
            *(out_ptr++) = *(fmt_ptr++);
        }
    }

    // Terminate the string
    *out_ptr = 0;
    return buffer;
}
Beispiel #5
0
int32_t StaticGame::ReadInt32(const char *address, intptr_t offset)
{
    int index = offset / sizeof(int32_t);
    if (index >= 5 && index < 5 + MAXGLOBALVARS)
        return play.globalvars[index - 5];

    switch (index)
    {
    case 0: return play.score;
    case 1: return play.usedmode;
    case 2: return play.disabled_user_interface;
    case 3: return play.gscript_timer;
    case 4: return play.debug_mode;
        // 5 -> 54: play.globalvars
    case 55: return play.messagetime;
    case 56: return play.usedinv;
    case 57: return play.inv_top;
    case 58: return play.inv_numdisp;
    case 59: return play.obsolete_inv_numorder;
    case 60: return play.inv_numinline;
    case 61: return play.text_speed;
    case 62: return play.sierra_inv_color;
    case 63: return play.talkanim_speed;
    case 64: return play.inv_item_wid;
    case 65: return play.inv_item_hit;
    case 66: return play.speech_text_shadow;
    case 67: return play.swap_portrait_side;
    case 68: return play.speech_textwindow_gui;
    case 69: return play.follow_change_room_timer;
    case 70: return play.totalscore;
    case 71: return play.skip_display;
    case 72: return play.no_multiloop_repeat;
    case 73: return play.roomscript_finished;
    case 74: return play.used_inv_on;
    case 75: return play.no_textbg_when_voice;
    case 76: return play.max_dialogoption_width;
    case 77: return play.no_hicolor_fadein;
    case 78: return play.bgspeech_game_speed;
    case 79: return play.bgspeech_stay_on_display;
    case 80: return play.unfactor_speech_from_textlength;
    case 81: return play.mp3_loop_before_end;
    case 82: return play.speech_music_drop;
    case 83: return play.in_cutscene;
    case 84: return play.fast_forward;
    case 85: return play.room_width;
    case 86: return play.room_height;
    case 87: return play.game_speed_modifier;
    case 88: return play.score_sound;
    case 89: return play.takeover_data;
    case 90: return play.replay_hotkey;
    case 91: return play.dialog_options_x;
    case 92: return play.dialog_options_y;
    case 93: return play.narrator_speech;
    case 94: return play.ambient_sounds_persist;
    case 95: return play.lipsync_speed;
    case 96: return play.close_mouth_speech_time;
    case 97: return play.disable_antialiasing;
    case 98: return play.text_speed_modifier;
    case 99: return play.text_align;
    case 100: return play.speech_bubble_width;
    case 101: return play.min_dialogoption_width;
    case 102: return play.disable_dialog_parser;
    case 103: return play.anim_background_speed;
    case 104: return play.top_bar_backcolor;
    case 105: return play.top_bar_textcolor;
    case 106: return play.top_bar_bordercolor;
    case 107: return play.top_bar_borderwidth;
    case 108: return play.top_bar_ypos;
    case 109: return play.screenshot_width;
    case 110: return play.screenshot_height;
    case 111: return play.top_bar_font;
    case 112: return play.speech_text_align;
    case 113: return play.auto_use_walkto_points;
    case 114: return play.inventory_greys_out;
    case 115: return play.skip_speech_specific_key;
    case 116: return play.abort_key;
    case 117: return play.fade_to_red;
    case 118: return play.fade_to_green;
    case 119: return play.fade_to_blue;
    case 120: return play.show_single_dialog_option;
    case 121: return play.keep_screen_during_instant_transition;
    case 122: return play.read_dialog_option_colour;
    case 123: return play.stop_dialog_at_end;
    case 124: return play.speech_portrait_placement;
    case 125: return play.speech_portrait_x;
    case 126: return play.speech_portrait_y;
    case 127: return play.speech_display_post_time_ms;
    case 128: return play.dialog_options_highlight_color;
    }
    cc_error("StaticGame: unsupported variable offset %d", offset);
    return 0;
}
Beispiel #6
0
void StaticGame::WriteInt32(const char *address, intptr_t offset, int32_t val)
{
    int index = offset / sizeof(int32_t);
    if (index >= 5 && index < 5 + MAXGLOBALVARS)
    {
        play.globalvars[index - 5] = val;
        return;
    }

    switch (index)
    {
    case 0:  play.score = val; break;
    case 1:  play.usedmode = val; break;
    case 2:  play.disabled_user_interface = val; break;
    case 3:  play.gscript_timer = val; break;
    case 4:  set_debug_mode(val != 0); break; // play.debug_mode
        // 5 -> 54: play.globalvars
    case 55:  play.messagetime = val; break;
    case 56:  play.usedinv = val; break;
    case 57:  play.inv_top = val; break;
    case 58:  play.inv_numdisp = val; break;
    case 59:  play.obsolete_inv_numorder = val; break;
    case 60:  play.inv_numinline = val; break;
    case 61:  play.text_speed = val; break;
    case 62:  play.sierra_inv_color = val; break;
    case 63:  play.talkanim_speed = val; break;
    case 64:  play.inv_item_wid = val; break;
    case 65:  play.inv_item_hit = val; break;
    case 66:  play.speech_text_shadow = val; break;
    case 67:  play.swap_portrait_side = val; break;
    case 68:  play.speech_textwindow_gui = val; break;
    case 69:  play.follow_change_room_timer = val; break;
    case 70:  play.totalscore = val; break;
    case 71:  play.skip_display = val; break;
    case 72:  play.no_multiloop_repeat = val; break;
    case 73:  play.roomscript_finished = val; break;
    case 74:  play.used_inv_on = val; break;
    case 75:  play.no_textbg_when_voice = val; break;
    case 76:  play.max_dialogoption_width = val; break;
    case 77:  play.no_hicolor_fadein = val; break;
    case 78:  play.bgspeech_game_speed = val; break;
    case 79:  play.bgspeech_stay_on_display = val; break;
    case 80:  play.unfactor_speech_from_textlength = val; break;
    case 81:  play.mp3_loop_before_end = val; break;
    case 82:  play.speech_music_drop = val; break;
    case 83:
    case 84:
    case 85:
    case 86:
        cc_error("StaticGame: attempt to write readonly variable at offset %d", offset);
        break;
    case 87:  play.game_speed_modifier = val; break;
    case 88:  play.score_sound = val; break;
    case 89:  play.takeover_data = val; break;
    case 90:  play.replay_hotkey = val; break;
    case 91:  play.dialog_options_x = val; break;
    case 92:  play.dialog_options_y = val; break;
    case 93:  play.narrator_speech = val; break;
    case 94:  play.ambient_sounds_persist = val; break;
    case 95:  play.lipsync_speed = val; break;
    case 96:  play.close_mouth_speech_time = val; break;
    case 97:  play.disable_antialiasing = val; break;
    case 98:  play.text_speed_modifier = val; break;
    case 99:  play.text_align = ReadScriptAlignment(val); break;
    case 100:  play.speech_bubble_width = val; break;
    case 101:  play.min_dialogoption_width = val; break;
    case 102:  play.disable_dialog_parser = val; break;
    case 103:  play.anim_background_speed = val; break;
    case 104:  play.top_bar_backcolor = val; break;
    case 105:  play.top_bar_textcolor = val; break;
    case 106:  play.top_bar_bordercolor = val; break;
    case 107:  play.top_bar_borderwidth = val; break;
    case 108:  play.top_bar_ypos = val; break;
    case 109:  play.screenshot_width = val; break;
    case 110:  play.screenshot_height = val; break;
    case 111:  play.top_bar_font = val; break;
    case 112:  play.speech_text_align = ReadScriptAlignment(val); break;
    case 113:  play.auto_use_walkto_points = val; break;
    case 114:  play.inventory_greys_out = val; break;
    case 115:  play.skip_speech_specific_key = val; break;
    case 116:  play.abort_key = val; break;
    case 117:
    case 118:
    case 119:
        cc_error("StaticGame: attempt to write readonly variable at offset %d", offset);
        break;
    case 120:  play.show_single_dialog_option = val; break;
    case 121:  play.keep_screen_during_instant_transition = val; break;
    case 122:  play.read_dialog_option_colour = val; break;
    case 123:  play.stop_dialog_at_end = val; break;
    case 124:  play.speech_portrait_placement = val; break;
    case 125:  play.speech_portrait_x = val; break;
    case 126:  play.speech_portrait_y = val; break;
    case 127:  play.speech_display_post_time_ms = val; break;
    case 128:  play.dialog_options_highlight_color = val; break;
    default:
        cc_error("StaticGame: unsupported variable offset %d", offset);
    }
}