-static int getSpecialActionElement(int element, int number, int base_element)
-{
- return (element != EL_EMPTY ? element :
- number != -1 ? base_element + number - 1 :
- EL_EMPTY);
-}
-
-static int getModifiedActionNumber(int value_old, int operator, int operand,
- int value_min, int value_max)
-{
- int value_new = (operator == CA_MODE_SET ? operand :
- operator == CA_MODE_ADD ? value_old + operand :
- operator == CA_MODE_SUBTRACT ? value_old - operand :
- operator == CA_MODE_MULTIPLY ? value_old * operand :
- operator == CA_MODE_DIVIDE ? value_old / MAX(1, operand) :
- operator == CA_MODE_MODULO ? value_old % MAX(1, operand) :
- value_old);
-
- return (value_new < value_min ? value_min :
- value_new > value_max ? value_max :
- value_new);
-}
-
-static void ExecuteCustomElementAction(int x, int y, int element, int page)
-{
- struct ElementInfo *ei = &element_info[element];
- struct ElementChangeInfo *change = &ei->change_page[page];
- int action_type = change->action_type;
- int action_mode = change->action_mode;
- int action_arg = change->action_arg;
- int i;
-
- if (!change->has_action)
- return;
-
- /* ---------- determine action paramater values -------------------------- */
-
- int level_time_value =
- (level.time > 0 ? TimeLeft :
- TimePlayed);
-
- int action_arg_element =
- (action_arg == CA_ARG_PLAYER_TRIGGER ? change->actual_trigger_player :
- action_arg == CA_ARG_ELEMENT_TRIGGER ? change->actual_trigger_element :
- action_arg == CA_ARG_ELEMENT_TARGET ? change->target_element :
- EL_EMPTY);
-
- int action_arg_direction =
- (action_arg >= CA_ARG_DIRECTION_LEFT &&
- action_arg <= CA_ARG_DIRECTION_DOWN ? action_arg - CA_ARG_DIRECTION :
- action_arg == CA_ARG_DIRECTION_TRIGGER ?
- change->actual_trigger_side :
- action_arg == CA_ARG_DIRECTION_TRIGGER_BACK ?
- MV_DIR_OPPOSITE(change->actual_trigger_side) :
- MV_NONE);
-
- int action_arg_number_min =
- (action_type == CA_SET_PLAYER_SPEED ? MOVE_STEPSIZE_MIN :
- CA_ARG_MIN);
-
- int action_arg_number_max =
- (action_type == CA_SET_PLAYER_SPEED ? MOVE_STEPSIZE_MAX :
- action_type == CA_SET_LEVEL_GEMS ? 999 :
- action_type == CA_SET_LEVEL_TIME ? 9999 :
- action_type == CA_SET_LEVEL_SCORE ? 99999 :
- action_type == CA_SET_CE_SCORE ? 9999 :
- action_type == CA_SET_CE_VALUE ? 9999 :
- CA_ARG_MAX);
-
- int action_arg_number_reset =
- (action_type == CA_SET_PLAYER_SPEED ? TILEX/game.initial_move_delay_value :
- action_type == CA_SET_LEVEL_GEMS ? level.gems_needed :
- action_type == CA_SET_LEVEL_TIME ? level.time :
- action_type == CA_SET_LEVEL_SCORE ? 0 :
- action_type == CA_SET_CE_SCORE ? 0 :
-#if 1
- action_type == CA_SET_CE_VALUE ? GET_NEW_CUSTOM_VALUE(element) :
-#else
- action_type == CA_SET_CE_VALUE ? ei->custom_value_initial :
-#endif
- 0);
-
- int action_arg_number =
- (action_arg <= CA_ARG_MAX ? action_arg :
- action_arg >= CA_ARG_SPEED_NOT_MOVING &&
- action_arg <= CA_ARG_SPEED_EVEN_FASTER ? (action_arg - CA_ARG_SPEED) :
- action_arg == CA_ARG_SPEED_RESET ? action_arg_number_reset :
- action_arg == CA_ARG_NUMBER_MIN ? action_arg_number_min :
- action_arg == CA_ARG_NUMBER_MAX ? action_arg_number_max :
- action_arg == CA_ARG_NUMBER_RESET ? action_arg_number_reset :
- action_arg == CA_ARG_NUMBER_CE_SCORE ? ei->collect_score :
-#if USE_NEW_CUSTOM_VALUE
- action_arg == CA_ARG_NUMBER_CE_VALUE ? CustomValue[x][y] :
-#else
- action_arg == CA_ARG_NUMBER_CE_VALUE ? ei->custom_value_initial :
-#endif
- action_arg == CA_ARG_NUMBER_CE_DELAY ? GET_CE_DELAY_VALUE(change) :
- action_arg == CA_ARG_NUMBER_LEVEL_TIME ? level_time_value :
- action_arg == CA_ARG_NUMBER_LEVEL_GEMS ? local_player->gems_still_needed :
- action_arg == CA_ARG_NUMBER_LEVEL_SCORE ? local_player->score :
- action_arg == CA_ARG_ELEMENT_TARGET ? GET_NEW_CUSTOM_VALUE(change->target_element) :
- action_arg == CA_ARG_ELEMENT_TRIGGER ? change->actual_trigger_ce_value :
- -1);
-
- int action_arg_number_old =
- (action_type == CA_SET_LEVEL_GEMS ? local_player->gems_still_needed :
- action_type == CA_SET_LEVEL_TIME ? TimeLeft :
- action_type == CA_SET_LEVEL_SCORE ? local_player->score :
- action_type == CA_SET_CE_SCORE ? ei->collect_score :
- action_type == CA_SET_CE_VALUE ? CustomValue[x][y] :
- 0);
-
- int action_arg_number_new =
- getModifiedActionNumber(action_arg_number_old,
- action_mode, action_arg_number,
- action_arg_number_min, action_arg_number_max);
-
- int trigger_player_bits =
- (change->actual_trigger_player >= EL_PLAYER_1 &&
- change->actual_trigger_player <= EL_PLAYER_4 ?
- (1 << (change->actual_trigger_player - EL_PLAYER_1)) :
- PLAYER_BITS_ANY);
-
- int action_arg_player_bits =
- (action_arg >= CA_ARG_PLAYER_1 &&
- action_arg <= CA_ARG_PLAYER_4 ? action_arg - CA_ARG_PLAYER :
- action_arg == CA_ARG_PLAYER_TRIGGER ? trigger_player_bits :
- PLAYER_BITS_ANY);
-
- /* ---------- execute action -------------------------------------------- */
-
- switch(action_type)
- {
- case CA_NO_ACTION:
- {
- return;
- }
-
- /* ---------- level actions ------------------------------------------- */
-
- case CA_RESTART_LEVEL:
- {
- game.restart_level = TRUE;
-
- break;
- }
-
- case CA_SHOW_ENVELOPE:
- {
- int element = getSpecialActionElement(action_arg_element,
- action_arg_number, EL_ENVELOPE_1);
-
- if (IS_ENVELOPE(element))
- local_player->show_envelope = element;
-
- break;
- }
-
- case CA_SET_LEVEL_TIME:
- {
- if (level.time > 0) /* only modify limited time value */
- {
- TimeLeft = action_arg_number_new;
-
- DrawGameValue_Time(TimeLeft);
-
- if (!TimeLeft && setup.time_limit)
- for (i = 0; i < MAX_PLAYERS; i++)
- KillPlayer(&stored_player[i]);
- }
-
- break;
- }
-
- case CA_SET_LEVEL_SCORE:
- {
- local_player->score = action_arg_number_new;
-
- DrawGameValue_Score(local_player->score);
-
- break;
- }
-
- case CA_SET_LEVEL_GEMS:
- {
- local_player->gems_still_needed = action_arg_number_new;
-
- DrawGameValue_Emeralds(local_player->gems_still_needed);
-
- break;
- }
-
- case CA_SET_LEVEL_GRAVITY:
- {
- game.gravity = (action_arg == CA_ARG_GRAVITY_OFF ? FALSE :
- action_arg == CA_ARG_GRAVITY_ON ? TRUE :
- action_arg == CA_ARG_GRAVITY_TOGGLE ? !game.gravity :
- game.gravity);
- break;
- }
-
- case CA_SET_LEVEL_WIND:
- {
- game.wind_direction = action_arg_direction;
-
- break;
- }
-
- /* ---------- player actions ------------------------------------------ */
-
- case CA_MOVE_PLAYER:
- {
- /* automatically move to the next field in specified direction */
- for (i = 0; i < MAX_PLAYERS; i++)
- if (trigger_player_bits & (1 << i))
- stored_player[i].programmed_action = action_arg_direction;
-
- break;
- }
-
- case CA_EXIT_PLAYER:
- {
- for (i = 0; i < MAX_PLAYERS; i++)
- if (action_arg_player_bits & (1 << i))
- stored_player[i].LevelSolved = stored_player[i].GameOver = TRUE;
-
- break;
- }
-
- case CA_KILL_PLAYER:
- {
- for (i = 0; i < MAX_PLAYERS; i++)
- if (action_arg_player_bits & (1 << i))
- KillPlayer(&stored_player[i]);
-
- break;
- }
-
- case CA_SET_PLAYER_KEYS:
- {
- int key_state = (action_mode == CA_MODE_ADD ? TRUE : FALSE);
- int element = getSpecialActionElement(action_arg_element,
- action_arg_number, EL_KEY_1);
-
- if (IS_KEY(element))
- {
- for (i = 0; i < MAX_PLAYERS; i++)
- {
- if (trigger_player_bits & (1 << i))
- {
- stored_player[i].key[KEY_NR(element)] = key_state;
-
- DrawGameValue_Keys(stored_player[i].key);
-
- redraw_mask |= REDRAW_DOOR_1;
- }
- }
- }
-
- break;
- }
-
- case CA_SET_PLAYER_SPEED:
- {
- for (i = 0; i < MAX_PLAYERS; i++)
- {
- if (trigger_player_bits & (1 << i))
- {
- int move_stepsize = TILEX / stored_player[i].move_delay_value;
-
- if (action_arg == CA_ARG_SPEED_SLOWER ||
- action_arg == CA_ARG_SPEED_FASTER)
- {
- action_arg_number = 2;
- action_mode = (action_arg == CA_ARG_SPEED_SLOWER ? CA_MODE_DIVIDE :
- CA_MODE_MULTIPLY);
- }
-
- move_stepsize =
- getModifiedActionNumber(move_stepsize,
- action_mode,
- action_arg_number,
- action_arg_number_min,
- action_arg_number_max);
-
- /* make sure that value is power of 2 */
- move_stepsize = (1 << log_2(move_stepsize));
-
- /* do no immediately change -- the player might just be moving */
- stored_player[i].move_delay_value_next = TILEX / move_stepsize;
-
- stored_player[i].cannot_move =
- (action_arg == CA_ARG_SPEED_NOT_MOVING ? TRUE : FALSE);
- }
- }
-
- break;
- }
-
- case CA_SET_PLAYER_SHIELD:
- {
- for (i = 0; i < MAX_PLAYERS; i++)
- {
- if (trigger_player_bits & (1 << i))
- {
- if (action_arg == CA_ARG_SHIELD_OFF)
- {
- stored_player[i].shield_normal_time_left = 0;
- stored_player[i].shield_deadly_time_left = 0;
- }
- else if (action_arg == CA_ARG_SHIELD_NORMAL)
- {
- stored_player[i].shield_normal_time_left = 999999;
- }
- else if (action_arg == CA_ARG_SHIELD_DEADLY)
- {
- stored_player[i].shield_normal_time_left = 999999;
- stored_player[i].shield_deadly_time_left = 999999;
- }
- }
- }
-
- break;
- }
-
- case CA_SET_PLAYER_ARTWORK:
- {
- for (i = 0; i < MAX_PLAYERS; i++)
- {
- if (trigger_player_bits & (1 << i))
- {
- int artwork_element = action_arg_element;
-
- if (action_arg == CA_ARG_ELEMENT_RESET)
- artwork_element =
- (level.use_artwork_element[i] ? level.artwork_element[i] :
- stored_player[i].element_nr);
-
- stored_player[i].artwork_element = artwork_element;
-
- SetPlayerWaiting(&stored_player[i], FALSE);
-
- /* set number of special actions for bored and sleeping animation */
- stored_player[i].num_special_action_bored =
- get_num_special_action(artwork_element,
- ACTION_BORING_1, ACTION_BORING_LAST);
- stored_player[i].num_special_action_sleeping =
- get_num_special_action(artwork_element,
- ACTION_SLEEPING_1, ACTION_SLEEPING_LAST);
- }
- }
-
- break;
- }
-
- /* ---------- CE actions ---------------------------------------------- */
-
- case CA_SET_CE_SCORE:
- {
- ei->collect_score = action_arg_number_new;
-
- break;
- }
-
- case CA_SET_CE_VALUE:
- {
-#if USE_NEW_CUSTOM_VALUE
- int last_custom_value = CustomValue[x][y];
-
- CustomValue[x][y] = action_arg_number_new;
-
-#if 0
- printf("::: Count == %d\n", CustomValue[x][y]);
-#endif
-
- if (CustomValue[x][y] == 0 && last_custom_value > 0)
- {
-#if 0
- printf("::: CE_VALUE_GETS_ZERO\n");
-#endif
-
- CheckElementChange(x, y, element, EL_UNDEFINED, CE_VALUE_GETS_ZERO);
- CheckTriggeredElementChange(x, y, element, CE_VALUE_GETS_ZERO_OF_X);
- }
-#endif
-
- break;
- }
-
- /* ---------- engine actions ------------------------------------------ */
-
- case CA_SET_ENGINE_SCAN_MODE:
- {
- InitPlayfieldScanMode(action_arg);
-
- break;
- }
-
- default:
- break;
- }
-}
-
-static void CreateFieldExt(int x, int y, int element, boolean is_change)