BlendEquation::BlendEquation(const variant& node) : rgb_(BlendEquationConstants::BE_ADD), alpha_(BlendEquationConstants::BE_ADD) { if(node.is_map()) { if(node.has_key("rgba")) { rgb_ = alpha_ = convert_string_to_equation(node["rgba"].as_string()); } if(node.has_key("rgb")) { rgb_ = convert_string_to_equation(node["rgb"].as_string()); } if(node.has_key("alpha")) { alpha_ = convert_string_to_equation(node["alpha"].as_string()); } if(node.has_key("a")) { alpha_ = convert_string_to_equation(node["a"].as_string()); } } else if(node.is_list()) { ASSERT_LOG(node.num_elements() > 0, "When using a list for blend equation must give at least one element"); if(node.num_elements() == 1) { rgb_ = alpha_ = convert_string_to_equation(node[0].as_string()); } else { rgb_ = convert_string_to_equation(node[0].as_string()); alpha_ = convert_string_to_equation(node[1].as_string()); } } else if(node.is_string()) { // simply setting the rgb/alpha values that same, from string rgb_ = alpha_ = convert_string_to_equation(node.as_string()); } else { ASSERT_LOG(false, "Unrecognised type for blend equation: " << node.to_debug_string()); } }
void BlendMode::set(const variant& node) { if(node.is_string()) { const std::string& blend = node.as_string(); if(blend == "add") { set(BlendModeConstants::BM_ONE, BlendModeConstants::BM_ONE); } else if(blend == "alpha_blend") { set(BlendModeConstants::BM_SRC_ALPHA, BlendModeConstants::BM_ONE_MINUS_SRC_ALPHA); } else if(blend == "colour_blend" || blend == "color_blend") { set(BlendModeConstants::BM_SRC_COLOR, BlendModeConstants::BM_ONE_MINUS_SRC_COLOR); } else if(blend == "modulate") { set(BlendModeConstants::BM_DST_COLOR, BlendModeConstants::BM_ZERO); } else if(blend == "src_colour one" || blend == "src_color one") { set(BlendModeConstants::BM_SRC_COLOR, BlendModeConstants::BM_ONE); } else if(blend == "src_colour zero" || blend == "src_color zero") { set(BlendModeConstants::BM_SRC_COLOR, BlendModeConstants::BM_ZERO); } else if(blend == "src_colour dest_colour" || blend == "src_color dest_color") { set(BlendModeConstants::BM_SRC_COLOR, BlendModeConstants::BM_DST_COLOR); } else if(blend == "dest_colour one" || blend == "dest_color one") { set(BlendModeConstants::BM_DST_COLOR, BlendModeConstants::BM_ONE); } else if(blend == "dest_colour src_colour" || blend == "dest_color src_color") { set(BlendModeConstants::BM_DST_COLOR, BlendModeConstants::BM_SRC_COLOR); } else { ASSERT_LOG(false, "BlendMode: Unrecognised scene_blend mode " << blend); } } else if(node.is_list() && node.num_elements() >= 2) { ASSERT_LOG(node[0].is_string() && node[1].is_string(), "BlendMode: Blend mode must be specified by a list of two strings."); set(parse_blend_string(node[0].as_string()), parse_blend_string(node[1].as_string())); } else { ASSERT_LOG(false, "BlendMode: Setting blend requires either a string or a list of greater than two elements." << node.to_debug_string()); } }
void luaW_pushfaivariant(lua_State* L, variant val) { if(val.is_int()) { lua_pushinteger(L, val.as_int()); } else if(val.is_decimal()) { lua_pushnumber(L, val.as_decimal() / 1000.0); } else if(val.is_string()) { const std::string result_string = val.as_string(); lua_pushlstring(L, result_string.c_str(), result_string.size()); } else if(val.is_list()) { lua_newtable(L); for(const variant& v : val.as_list()) { lua_pushinteger(L, lua_rawlen(L, -1) + 1); luaW_pushfaivariant(L, v); lua_settable(L, -3); } } else if(val.is_map()) { typedef std::map<variant,variant>::value_type kv_type; lua_newtable(L); for(const kv_type& v : val.as_map()) { luaW_pushfaivariant(L, v.first); luaW_pushfaivariant(L, v.second); lua_settable(L, -3); } } else if(val.is_callable()) { // First try a few special cases if(unit_callable* u_ref = val.try_convert<unit_callable>()) { const unit& u = u_ref->get_unit(); unit_map::iterator un_it = resources::gameboard->units().find(u.get_location()); if(&*un_it == &u) { luaW_pushunit(L, u.underlying_id()); } else { luaW_pushunit(L, u.side(), u.underlying_id()); } } else if(location_callable* loc_ref = val.try_convert<location_callable>()) { luaW_pushlocation(L, loc_ref->loc()); } else { // If those fail, convert generically to a map const formula_callable* obj = val.as_callable(); std::vector<formula_input> inputs; obj->get_inputs(&inputs); lua_newtable(L); for(const formula_input& attr : inputs) { if(attr.access == FORMULA_WRITE_ONLY) { continue; } lua_pushstring(L, attr.name.c_str()); luaW_pushfaivariant(L, obj->query_value(attr.name)); lua_settable(L, -3); } } } else if(val.is_null()) { lua_pushnil(L); } }
void arrow_primitive::set_points(const variant& points) { ASSERT_LOG(points.is_list(), "arrow points is not a list: " << points.debug_location()); points_.clear(); for(int n = 0; n != points.num_elements(); ++n) { variant p = points[n]; ASSERT_LOG(p.is_list() && p.num_elements() == 2, "arrow points in invalid format: " << points.debug_location() << " : " << p.write_json()); FPoint point; point[0] = p[0].as_int(); point[1] = p[1].as_int(); points_.push_back(point); } }
void playable_custom_object::set_player_value_by_slot(int slot, const variant& value) { switch(slot) { case CUSTOM_OBJECT_PLAYER_DIFFICULTY: difficulty_ = value.as_int(); break; case CUSTOM_OBJECT_PLAYER_CAN_INTERACT: can_interact_ = value.as_int(); break; case CUSTOM_OBJECT_PLAYER_UNDERWATER_CONTROLS: underwater_controls_ = value.as_bool(); break; case CUSTOM_OBJECT_PLAYER_VERTICAL_LOOK: vertical_look_ = value.as_int(); break; case CUSTOM_OBJECT_PLAYER_CONTROL_LOCK: if(value.is_null()) { control_lock_.reset(); } else if(value.is_list()) { unsigned char state = 0; for(int n = 0; n != value.num_elements(); ++n) { ASSERT_LOG(value[n].is_string(), "MEMBER OF control_lock LIST NOT A STRING"); const std::string& str = value[n].as_string(); int control_key = -1; for(int m = 0; m != sizeof(ctrl)/sizeof(*ctrl); ++m) { if(ctrl[m] == str) { control_key = m; break; } } ASSERT_LOG(control_key != -1, "ILLEGAL STRING SET FOR control_lock: '" << str << "' LEGAL KEYS ARE ctrl_(up|down|left|right|attack|jump)"); state |= 1 << control_key; } //destroy the old one before creating a new control_lock, //since control_lock objects must be constructed and destroyed //in FIFO order. control_lock_.reset(); control_lock_.reset(new controls::local_controls_lock(state)); } else { ASSERT_LOG(false, "BAD VALUE WHEN SETTING control_lock KEY. A LIST OR NULL IS REQUIRED: " << value.to_debug_string()); } break; } }
//commandline=true when we evaluate formula from commandline, false otherwise (default) variant formula_ai::execute_variant(const variant& var, ai_context &ai_, bool commandline) { std::stack<variant> vars; if(var.is_list()) { for(size_t n = 1; n <= var.num_elements() ; ++n) { vars.push(var[ var.num_elements() - n ]); } } else { vars.push(var); } std::vector<variant> made_moves; variant error; unit_map& units = *resources::units; while( !vars.empty() ) { if(vars.top().is_null()) { vars.pop(); continue; } variant action = vars.top(); vars.pop(); game_logic::safe_call_callable* safe_call = try_convert_variant<game_logic::safe_call_callable>(action); if(safe_call) { action = safe_call->get_main(); } const move_callable* move = try_convert_variant<move_callable>(action); const move_partial_callable* move_partial = try_convert_variant<move_partial_callable>(action); const attack_callable* attack = try_convert_variant<attack_callable>(action); const attack_analysis* _attack_analysis = try_convert_variant<attack_analysis>(action); const recruit_callable* recruit_command = try_convert_variant<recruit_callable>(action); const recall_callable* recall_command = try_convert_variant<recall_callable>(action); const set_var_callable* set_var_command = try_convert_variant<set_var_callable>(action); const set_unit_var_callable* set_unit_var_command = try_convert_variant<set_unit_var_callable>(action); const fallback_callable* fallback_command = try_convert_variant<fallback_callable>(action); if( move || move_partial ) { move_result_ptr move_result; if(move) move_result = ai_.execute_move_action(move->src(), move->dst(), true); else move_result = ai_.execute_move_action(move_partial->src(), move_partial->dst(), false); if ( !move_result->is_ok() ) { if( move ) { LOG_AI << "ERROR #" << move_result->get_status() << " while executing 'move' formula function\n" << std::endl; if(safe_call) { //safe_call was called, prepare error information error = variant(new safe_call_result(move, move_result->get_status(), move_result->get_unit_location())); } } else { LOG_AI << "ERROR #" << move_result->get_status() << " while executing 'move_partial' formula function\n" << std::endl; if(safe_call) { //safe_call was called, prepare error information error = variant(new safe_call_result(move_partial, move_result->get_status(), move_result->get_unit_location())); } } } if( move_result->is_gamestate_changed() ) made_moves.push_back(action); } else if(attack) { bool gamestate_changed = false; move_result_ptr move_result; if( attack->move_from() != attack->src() ) { move_result = ai_.execute_move_action(attack->move_from(), attack->src(), false); gamestate_changed |= move_result->is_gamestate_changed(); if (!move_result->is_ok()) { //move part failed LOG_AI << "ERROR #" << move_result->get_status() << " while executing 'attack' formula function\n" << std::endl; if(safe_call) { //safe_call was called, prepare error information error = variant(new safe_call_result(attack, move_result->get_status(), move_result->get_unit_location())); } } } if (!move_result || move_result->is_ok() ) { //if move wasn't done at all or was done successfully attack_result_ptr attack_result = ai_.execute_attack_action(attack->src(), attack->dst(), attack->weapon() ); gamestate_changed |= attack_result->is_gamestate_changed(); if (!attack_result->is_ok()) { //attack failed LOG_AI << "ERROR #" << attack_result->get_status() << " while executing 'attack' formula function\n" << std::endl; if(safe_call) { //safe_call was called, prepare error information error = variant(new safe_call_result(attack, attack_result->get_status())); } } } if (gamestate_changed) { made_moves.push_back(action); } } else if(_attack_analysis) { //If we get an attack analysis back we will do the first attack. //Then the AI can get run again and re-choose. assert(_attack_analysis->movements.empty() == false); //make sure that unit which has to attack is at given position and is able to attack unit_map::const_iterator unit = units.find(_attack_analysis->movements.front().first); if (!unit.valid() || unit->attacks_left() == 0) continue; const map_location& move_from = _attack_analysis->movements.front().first; const map_location& att_src = _attack_analysis->movements.front().second; const map_location& att_dst = _attack_analysis->target; //check if target is still valid unit = units.find(att_dst); if ( unit == units.end() ) continue; //check if we need to move if( move_from != att_src ) { //now check if location to which we want to move is still unoccupied unit = units.find(att_src); if ( unit != units.end() ) { continue; } ai_.execute_move_action(move_from, att_src); } if(units.count(att_src)) { ai_.execute_attack_action(_attack_analysis->movements.front().second,_attack_analysis->target,-1); } made_moves.push_back(action); } else if(recall_command) { recall_result_ptr recall_result = ai_.check_recall_action(recall_command->id(), recall_command->loc()); if( recall_result->is_ok() ) { recall_result->execute(); } if (!recall_result->is_ok()) { if(safe_call) { //safe call was called, prepare error information error = variant(new safe_call_result(recall_command, recall_result->get_status())); LOG_AI << "ERROR #" <<recall_result->get_status() << " while executing 'recall' formula function\n"<<std::endl; } else { ERR_AI << "ERROR #" <<recall_result->get_status() << " while executing 'recall' formula function\n"<<std::endl; } } if( recall_result->is_gamestate_changed() ) { made_moves.push_back(action); } } else if(recruit_command) { recruit_result_ptr recruit_result = ai_.check_recruit_action(recruit_command->type(), recruit_command->loc()); //is_ok()==true means that the action is successful (eg. no unexpected events) //is_ok() must be checked or the code will complain :) if( recruit_result->is_ok() ) recruit_result->execute(); if (!recruit_result->is_ok()) { if(safe_call) { //safe call was called, prepare error information error = variant(new safe_call_result(recruit_command, recruit_result->get_status())); LOG_AI << "ERROR #" <<recruit_result->get_status() << " while executing 'recruit' formula function\n"<<std::endl; } else { ERR_AI << "ERROR #" <<recruit_result->get_status() << " while executing 'recruit' formula function\n"<<std::endl; } } //is_gamestate_changed()==true means that the game state was somehow changed by action. //it is believed that during a turn, a game state can change only a finite number of times if( recruit_result->is_gamestate_changed() ) made_moves.push_back(action); } else if(set_var_command) { if( infinite_loop_guardian_.set_var_check() ) { LOG_AI << "Setting variable: " << set_var_command->key() << " -> " << set_var_command->value().to_debug_string() << "\n"; vars_.add(set_var_command->key(), set_var_command->value()); made_moves.push_back(action); } else { //too many calls in a row - possible infinite loop ERR_AI << "ERROR #" << 5001 << " while executing 'set_var' formula function" << std::endl; if( safe_call ) error = variant(new safe_call_result(set_var_command, 5001)); } } else if(set_unit_var_command) { int status = 0; unit_map::iterator unit; if( !infinite_loop_guardian_.set_unit_var_check() ) { status = 5001; //exceeded nmber of calls in a row - possible infinite loop } else if( (unit = units.find(set_unit_var_command->loc())) == units.end() ) { status = 5002; //unit not found } else if (unit->side() != get_side()) { status = 5003;//unit does not belong to our side } if( status == 0 ){ LOG_AI << "Setting unit variable: " << set_unit_var_command->key() << " -> " << set_unit_var_command->value().to_debug_string() << "\n"; unit->formula_manager().add_formula_var(set_unit_var_command->key(), set_unit_var_command->value()); made_moves.push_back(action); } else { ERR_AI << "ERROR #" << status << " while executing 'set_unit_var' formula function" << std::endl; if(safe_call) error = variant(new safe_call_result(set_unit_var_command, status)); } } else if( action.is_string() && action.as_string() == "recruit") { stage_ptr r = get_recruitment(ai_); if (r) { if (r->play_stage()) { made_moves.push_back(action); } } } else if( action.is_string() && action.as_string() == "continue") { if( infinite_loop_guardian_.continue_check() ) { made_moves.push_back(action); } else { //too many calls in a row - possible infinite loop ERR_AI << "ERROR #" << 5001 << " while executing 'continue' formula keyword" << std::endl; if( safe_call ) error = variant(new safe_call_result(NULL, 5001)); } } else if( action.is_string() && (action.as_string() == "end_turn" || action.as_string() == "end" ) ) { return variant(); } else if(fallback_command) { if(get_recursion_count()<recursion_counter::MAX_COUNTER_VALUE) { if(fallback_command->key() == "human") { //we want give control of the side to human for the rest of this turn throw fallback_ai_to_human_exception(); } else { LOG_AI << "Explicit fallback to: " << fallback_command->key() << std::endl; ai_ptr fallback( manager::create_transient_ai(fallback_command->key(), config(), &ai_)); if(fallback) { fallback->play_turn(); } } } return variant(); } else { //this information is unneded when evaluating formulas form commandline if (!commandline) { ERR_AI << "UNRECOGNIZED MOVE: " << action.to_debug_string() << std::endl; } } if( safe_call && (error != variant() || made_moves.empty() || made_moves.back() != action) ){ /*if we have safe_call formula and either error occurred, or current action *was not reckognized, then evaluate backup formula from safe_call and execute it *during the next loop */ game_logic::map_formula_callable callable(this); callable.add_ref(); if(error != variant()) callable.add("error", error); variant backup_result = safe_call->get_backup()->evaluate(callable); if(backup_result.is_list()) { for(size_t n = 1; n <= backup_result.num_elements() ; ++n) { vars.push(backup_result[ backup_result.num_elements() - n ]); } } else { vars.push(backup_result); } //store the result in safe_call_callable case we would like to display it to the user //for example if this formula was executed from commandline safe_call->set_backup_result(backup_result); error = variant(); } } return variant(&made_moves); }