00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "global.hpp"
00016
00017 #include <iostream>
00018 #include <math.h>
00019
00020
00021 #include "callable_objects.hpp"
00022 #include "formula_callable.hpp"
00023 #include "formula_function.hpp"
00024 #include "map.hpp"
00025
00026 #include "SDL.h"
00027
00028 namespace game_logic {
00029
00030 namespace {
00031
00032 class dir_function : public function_expression {
00033 public:
00034 explicit dir_function(const args_list& args)
00035 : function_expression("dir", args, 1, 1)
00036 {}
00037
00038 private:
00039 variant execute(const formula_callable& variables) const {
00040 variant var = args()[0]->evaluate(variables);
00041 const formula_callable* callable = var.as_callable();
00042 std::vector<formula_input> inputs = callable->inputs();
00043 std::vector<variant> res;
00044 for(size_t i=0; i<inputs.size(); ++i) {
00045 const formula_input& input = inputs[i];
00046 res.push_back(variant(input.name));
00047 }
00048
00049 return variant(&res);
00050 }
00051 };
00052
00053 class if_function : public function_expression {
00054 public:
00055 explicit if_function(const args_list& args)
00056 : function_expression("if", args, 3, 3)
00057 {}
00058
00059 private:
00060 variant execute(const formula_callable& variables) const {
00061 const int i = args()[0]->evaluate(variables).as_bool() ? 1 : 2;
00062 return args()[i]->evaluate(variables);
00063 }
00064 };
00065
00066 class switch_function : public function_expression {
00067 public:
00068 explicit switch_function(const args_list& args)
00069 : function_expression("switch", args, 3, -1)
00070 {}
00071
00072 private:
00073 variant execute(const formula_callable& variables) const {
00074 variant var = args()[0]->evaluate(variables);
00075 for(size_t n = 1; n < args().size()-1; n += 2) {
00076 variant val = args()[n]->evaluate(variables);
00077 if(val == var) {
00078 return args()[n+1]->evaluate(variables);
00079 }
00080 }
00081
00082 if((args().size()%2) == 0) {
00083 return args().back()->evaluate(variables);
00084 } else {
00085 return variant();
00086 }
00087 }
00088 };
00089
00090 class rgb_function : public function_expression {
00091 public:
00092 explicit rgb_function(const args_list& args)
00093 : function_expression("rgb", args, 3, 3)
00094 {}
00095
00096 private:
00097 variant execute(const formula_callable& variables) const {
00098 return variant(10000*
00099 std::min<int>(99,std::max<int>(0,args()[0]->evaluate(variables).as_int())) +
00100 std::min<int>(99,std::max<int>(0,args()[1]->evaluate(variables).as_int()))*100+
00101 std::min<int>(99,std::max<int>(0,args()[2]->evaluate(variables).as_int())));
00102 }
00103 };
00104
00105 namespace {
00106 int transition(int begin, int val1, int end, int val2, int value) {
00107 if(value < begin || value > end) {
00108 return 0;
00109 }
00110
00111 if(value == begin) {
00112 return val1;
00113 } else if(value == end) {
00114 return val2;
00115 }
00116
00117 const int comp1 = val1*(end - value);
00118 const int comp2 = val2*(value - begin);
00119 return (comp1 + comp2)/(end - begin);
00120 }
00121 }
00122
00123 class transition_function : public function_expression {
00124 public:
00125 explicit transition_function(const args_list& args)
00126 : function_expression("transition", args, 5, 5)
00127 {}
00128 private:
00129 variant execute(const formula_callable& variables) const {
00130 const int value = args()[0]->evaluate(variables).as_int();
00131 const int begin = args()[1]->evaluate(variables).as_int();
00132 const int end = args()[3]->evaluate(variables).as_int();
00133 if(value < begin || value > end) {
00134 return variant(0);
00135 }
00136 const int val1 = args()[2]->evaluate(variables).as_int();
00137 const int val2 = args()[4]->evaluate(variables).as_int();
00138 return variant(transition(begin, val1, end, val2, value));
00139 }
00140 };
00141
00142 class color_transition_function : public function_expression {
00143 public:
00144 explicit color_transition_function(const args_list& args)
00145 : function_expression("color_transition", args, 5)
00146 {}
00147 private:
00148 variant execute(const formula_callable& variables) const {
00149 const int value = args()[0]->evaluate(variables).as_int();
00150 int begin = args()[1]->evaluate(variables).as_int();
00151 int end = -1;
00152 size_t n = 3;
00153 while(n < args().size()) {
00154 end = args()[n]->evaluate(variables).as_int();
00155 if(value >= begin && value <= end) {
00156 break;
00157 }
00158
00159 begin = end;
00160 n += 2;
00161 }
00162
00163 if(value < begin || value > end) {
00164 return variant(0);
00165 }
00166 const int val1 = args()[n-1]->evaluate(variables).as_int();
00167 const int val2 = args()[n+1 < args().size() ? n+1 : n]->
00168 evaluate(variables).as_int();
00169 const int r1 = (val1/10000)%100;
00170 const int g1 = (val1/100)%100;
00171 const int b1 = (val1)%100;
00172 const int r2 = (val2/10000)%100;
00173 const int g2 = (val2/100)%100;
00174 const int b2 = (val2)%100;
00175
00176 const int r = transition(begin,r1,end,r2,value);
00177 const int g = transition(begin,g1,end,g2,value);
00178 const int b = transition(begin,b1,end,b2,value);
00179 return variant(
00180 std::min<int>(99,std::max<int>(0,r))*100*100 +
00181 std::min<int>(99,std::max<int>(0,g))*100+
00182 std::min<int>(99,std::max<int>(0,b)));
00183 }
00184 };
00185
00186
00187 class abs_function : public function_expression {
00188 public:
00189 explicit abs_function(const args_list& args)
00190 : function_expression("abs", args, 1, 1)
00191 {}
00192
00193 private:
00194 variant execute(const formula_callable& variables) const {
00195 const int n = args()[0]->evaluate(variables).as_int();
00196 return variant(n >= 0 ? n : -n);
00197 }
00198 };
00199
00200 class min_function : public function_expression {
00201 public:
00202 explicit min_function(const args_list& args)
00203 : function_expression("min", args, 1, -1)
00204 {}
00205
00206 private:
00207 variant execute(const formula_callable& variables) const {
00208 bool found = false;
00209 int res = 0;
00210 for(size_t n = 0; n != args().size(); ++n) {
00211 const variant v = args()[n]->evaluate(variables);
00212 if(v.is_list()) {
00213 for(size_t m = 0; m != v.num_elements(); ++m) {
00214 if(!found || v[m].as_int() < res) {
00215 res = v[m].as_int();
00216 found = true;
00217 }
00218 }
00219 } else if(v.is_int()) {
00220 if(!found || v.as_int() < res) {
00221 res = v.as_int();
00222 found = true;
00223 }
00224 }
00225 }
00226
00227 return variant(res);
00228 }
00229 };
00230
00231 class max_function : public function_expression {
00232 public:
00233 explicit max_function(const args_list& args)
00234 : function_expression("max", args, 1, -1)
00235 {}
00236
00237 private:
00238 variant execute(const formula_callable& variables) const {
00239 bool found = false;
00240 int res = 0;
00241 for(size_t n = 0; n != args().size(); ++n) {
00242 const variant v = args()[n]->evaluate(variables);
00243 if(v.is_list()) {
00244 for(size_t m = 0; m != v.num_elements(); ++m) {
00245 if(!found || v[m].as_int() > res) {
00246 res = v[m].as_int();
00247 found = true;
00248 }
00249 }
00250 } else if(v.is_int()) {
00251 if(!found || v.as_int() > res) {
00252 res = v.as_int();
00253 found = true;
00254 }
00255 }
00256 }
00257
00258 return variant(res);
00259 }
00260 };
00261
00262 class keys_function : public function_expression {
00263 public:
00264 explicit keys_function(const args_list& args)
00265 : function_expression("keys", args, 1, 1)
00266 {}
00267
00268 private:
00269 variant execute(const formula_callable& variables) const {
00270 const variant map = args()[0]->evaluate(variables);
00271 return map.get_keys();
00272 }
00273 };
00274
00275 class values_function : public function_expression {
00276 public:
00277 explicit values_function(const args_list& args)
00278 : function_expression("values", args, 1, 1)
00279 {}
00280
00281 private:
00282 variant execute(const formula_callable& variables) const {
00283 const variant map = args()[0]->evaluate(variables);
00284 return map.get_values();
00285 }
00286 };
00287
00288 class choose_function : public function_expression {
00289 public:
00290 explicit choose_function(const args_list& args)
00291 : function_expression("choose", args, 2, 2)
00292 {}
00293
00294 private:
00295 variant execute(const formula_callable& variables) const {
00296 const variant items = args()[0]->evaluate(variables);
00297 int max_index = -1;
00298 variant max_value;
00299 for(size_t n = 0; n != items.num_elements(); ++n) {
00300 const variant val = args()[1]->evaluate(formula_variant_callable_with_backup(items[n], variables));
00301 if(max_index == -1 || val > max_value) {
00302 max_index = n;
00303 max_value = val;
00304 }
00305 }
00306
00307 if(max_index == -1) {
00308 return variant();
00309 } else {
00310 return items[max_index];
00311 }
00312 }
00313 };
00314
00315 class wave_function : public function_expression {
00316 public:
00317 explicit wave_function(const args_list& args)
00318 : function_expression("wave", args, 1, 1)
00319 {}
00320
00321 private:
00322 variant execute(const formula_callable& variables) const {
00323 const int value = args()[0]->evaluate(variables).as_int()%1000;
00324 const double angle = 2.0*3.141592653589*(static_cast<double>(value)/1000.0);
00325 return variant(static_cast<int>(sin(angle)*1000.0));
00326 }
00327 };
00328
00329 namespace {
00330 class variant_comparator : public formula_callable {
00331 expression_ptr expr_;
00332 const formula_callable* fallback_;
00333 mutable variant a_, b_;
00334 variant get_value(const std::string& key) const {
00335 if(key == "a") {
00336 return a_;
00337 } else if(key == "b") {
00338 return b_;
00339 } else {
00340 return fallback_->query_value(key);
00341 }
00342 }
00343
00344 void get_inputs(std::vector<formula_input>* inputs) const {
00345 fallback_->get_inputs(inputs);
00346 }
00347 public:
00348 variant_comparator(const expression_ptr& expr, const formula_callable& fallback) : expr_(expr), fallback_(&fallback)
00349 {}
00350
00351 bool operator()(const variant& a, const variant& b) const {
00352 a_ = a;
00353 b_ = b;
00354 return expr_->evaluate(*this).as_bool();
00355 }
00356 };
00357 }
00358
00359 class sort_function : public function_expression {
00360 public:
00361 explicit sort_function(const args_list& args)
00362 : function_expression("sort", args, 1, 2)
00363 {}
00364
00365 private:
00366 variant execute(const formula_callable& variables) const {
00367 variant list = args()[0]->evaluate(variables);
00368 std::vector<variant> vars;
00369 vars.reserve(list.num_elements());
00370 for(size_t n = 0; n != list.num_elements(); ++n) {
00371 vars.push_back(list[n]);
00372 }
00373
00374 if(args().size() == 1) {
00375 std::sort(vars.begin(), vars.end());
00376 } else {
00377 std::sort(vars.begin(), vars.end(), variant_comparator(args()[1], variables));
00378 }
00379
00380 return variant(&vars);
00381 }
00382 };
00383
00384 class filter_function : public function_expression {
00385 public:
00386 explicit filter_function(const args_list& args)
00387 : function_expression("filter", args, 2, 3)
00388 {}
00389 private:
00390 variant execute(const formula_callable& variables) const {
00391 std::vector<variant> vars;
00392 const variant items = args()[0]->evaluate(variables);
00393 if(args().size() == 2) {
00394 for(size_t n = 0; n != items.num_elements(); ++n) {
00395 const variant val = args()[1]->evaluate(formula_variant_callable_with_backup(items[n], variables));
00396 if(val.as_bool()) {
00397 vars.push_back(items[n]);
00398 }
00399 }
00400 } else {
00401 map_formula_callable self_callable;
00402 const std::string self = args()[1]->evaluate(variables).as_string();
00403 for(size_t n = 0; n != items.num_elements(); ++n) {
00404 self_callable.add(self, items[n]);
00405 const variant val = args()[2]->evaluate(formula_callable_with_backup(self_callable, formula_variant_callable_with_backup(items[n], variables)));
00406 if(val.as_bool()) {
00407 vars.push_back(items[n]);
00408 }
00409 }
00410 }
00411
00412 return variant(&vars);
00413 }
00414 };
00415
00416 class find_function : public function_expression {
00417 public:
00418 explicit find_function(const args_list& args)
00419 : function_expression("find", args, 2, 3)
00420 {}
00421
00422 private:
00423 variant execute(const formula_callable& variables) const {
00424 const variant items = args()[0]->evaluate(variables);
00425
00426 if(args().size() == 2) {
00427 for(size_t n = 0; n != items.num_elements(); ++n) {
00428 const variant val = args()[1]->evaluate(formula_variant_callable_with_backup(items[n], variables));
00429 if(val.as_bool()) {
00430 return items[n];
00431 }
00432 }
00433 } else {
00434 map_formula_callable self_callable;
00435 const std::string self = args()[1]->evaluate(variables).as_string();
00436 for(size_t n = 0; n != items.num_elements(); ++n) {
00437 self_callable.add(self, items[n]);
00438 const variant val = args().back()->evaluate(formula_callable_with_backup(self_callable, formula_variant_callable_with_backup(items[n], variables)));
00439 if(val.as_bool()) {
00440 return items[n];
00441 }
00442 }
00443 }
00444
00445 return variant();
00446 }
00447 };
00448
00449 class map_function : public function_expression {
00450 public:
00451 explicit map_function(const args_list& args)
00452 : function_expression("map", args, 2, 3)
00453 {}
00454 private:
00455 variant execute(const formula_callable& variables) const {
00456 std::vector<variant> vars;
00457 const variant items = args()[0]->evaluate(variables);
00458
00459 if(args().size() == 2) {
00460 for(size_t n = 0; n != items.num_elements(); ++n) {
00461 const variant val = args().back()->evaluate(formula_variant_callable_with_backup(items[n], variables));
00462 vars.push_back(val);
00463 }
00464 } else {
00465 map_formula_callable self_callable;
00466 const std::string self = args()[1]->evaluate(variables).as_string();
00467 for(size_t n = 0; n != items.num_elements(); ++n) {
00468 self_callable.add(self, items[n]);
00469 const variant val = args().back()->evaluate(formula_callable_with_backup(self_callable, formula_variant_callable_with_backup(items[n], variables)));
00470 vars.push_back(val);
00471 }
00472 }
00473
00474 return variant(&vars);
00475 }
00476 };
00477
00478 class sum_function : public function_expression {
00479 public:
00480 explicit sum_function(const args_list& args)
00481 : function_expression("sum", args, 1, 2)
00482 {}
00483 private:
00484 variant execute(const formula_callable& variables) const {
00485 variant res(0);
00486 const variant items = args()[0]->evaluate(variables);
00487 if(args().size() >= 2) {
00488 res = args()[1]->evaluate(variables);
00489 }
00490 for(size_t n = 0; n != items.num_elements(); ++n) {
00491 res = res + items[n];
00492 }
00493
00494 return res;
00495 }
00496 };
00497
00498 class head_function : public function_expression {
00499 public:
00500 explicit head_function(const args_list& args)
00501 : function_expression("head", args, 1, 1)
00502 {}
00503 private:
00504 variant execute(const formula_callable& variables) const {
00505 const variant items = args()[0]->evaluate(variables);
00506 return items[0];
00507 }
00508 };
00509
00510 class size_function : public function_expression {
00511 public:
00512 explicit size_function(const args_list& args)
00513 : function_expression("size", args, 1, 1)
00514 {}
00515 private:
00516 variant execute(const formula_callable& variables) const {
00517 const variant items = args()[0]->evaluate(variables);
00518 return variant(static_cast<int>(items.num_elements()));
00519 }
00520 };
00521
00522 class null_function : public function_expression {
00523 public:
00524 explicit null_function(const args_list& args)
00525 : function_expression("null", args, 0, 0)
00526 {}
00527 private:
00528 variant execute(const formula_callable& ) const {
00529 return variant();
00530 }
00531 };
00532
00533 class refcount_function : public function_expression {
00534 public:
00535 explicit refcount_function(const args_list& args)
00536 : function_expression("refcount", args, 1, 1)
00537 {}
00538 private:
00539 variant execute(const formula_callable& variables) const {
00540 return variant(args()[0]->evaluate(variables).refcount());
00541 }
00542 };
00543
00544 class loc_function : public function_expression {
00545 public:
00546 explicit loc_function(const args_list& args)
00547 : function_expression("loc", args, 2, 2)
00548 {}
00549 private:
00550 variant execute(const formula_callable& variables) const {
00551 return variant(new location_callable(gamemap::location(args()[0]->evaluate(variables).as_int()-1, args()[1]->evaluate(variables).as_int()-1)));
00552 }
00553 };
00554
00555 }
00556
00557 formula_function_expression::formula_function_expression(const std::string& name, const args_list& args, const_formula_ptr formula, const_formula_ptr precondition, const std::vector<std::string>& arg_names)
00558 : function_expression(name, args, arg_names.size(), arg_names.size()),
00559 formula_(formula), precondition_(precondition), arg_names_(arg_names), star_arg_(-1)
00560 {
00561 for(size_t n = 0; n != arg_names_.size(); ++n) {
00562 if(arg_names_.empty() == false && arg_names_[n][arg_names_[n].size()-1] == '*') {
00563 arg_names_[n].resize(arg_names_[n].size()-1);
00564 star_arg_ = n;
00565 break;
00566 }
00567 }
00568 }
00569
00570 variant formula_function_expression::execute(const formula_callable& variables) const
00571 {
00572 static std::string indent;
00573 indent += " ";
00574 std::cerr << indent << "executing '" << formula_->str() << "'\n";
00575 const int begin_time = SDL_GetTicks();
00576 map_formula_callable callable;
00577 for(size_t n = 0; n != arg_names_.size(); ++n) {
00578 variant var = args()[n]->evaluate(variables);
00579 callable.add(arg_names_[n], var);
00580 if(static_cast<int>(n) == star_arg_) {
00581 callable.set_fallback(var.as_callable());
00582 }
00583 }
00584
00585 if(precondition_) {
00586 if(!precondition_->execute(callable).as_bool()) {
00587 std::cerr << "FAILED function precondition for function '" << formula_->str() << "' with arguments: ";
00588 for(size_t n = 0; n != arg_names_.size(); ++n) {
00589 std::cerr << " arg " << (n+1) << ": " << args()[n]->evaluate(variables).to_debug_string() << "\n";
00590 }
00591 }
00592 }
00593
00594 variant res = formula_->execute(callable);
00595 const int taken = SDL_GetTicks() - begin_time;
00596 std::cerr << indent << "returning: " << taken << "\n";
00597 indent.resize(indent.size() - 2);
00598
00599 return res;
00600 }
00601
00602 function_expression_ptr formula_function::generate_function_expression(const std::vector<expression_ptr>& args) const
00603 {
00604 return function_expression_ptr(new formula_function_expression(name_, args, formula_, precondition_, args_));
00605 }
00606
00607 void function_symbol_table::add_formula_function(const std::string& name, const_formula_ptr formula, const_formula_ptr precondition, const std::vector<std::string>& args)
00608 {
00609 custom_formulas_[name] = formula_function(name, formula, precondition, args);
00610 }
00611
00612 expression_ptr function_symbol_table::create_function(const std::string& fn, const std::vector<expression_ptr>& args) const
00613 {
00614 const std::map<std::string, formula_function>::const_iterator i = custom_formulas_.find(fn);
00615 if(i != custom_formulas_.end()) {
00616 return i->second.generate_function_expression(args);
00617 }
00618
00619 return expression_ptr();
00620 }
00621
00622 std::vector<std::string> function_symbol_table::get_function_names() const
00623 {
00624 std::vector<std::string> res;
00625 for(std::map<std::string, formula_function>::const_iterator iter = custom_formulas_.begin(); iter != custom_formulas_.end(); iter++ ) {
00626 res.push_back((*iter).first);
00627 }
00628 return res;
00629 }
00630
00631 namespace {
00632
00633 class base_function_creator {
00634 public:
00635 virtual expression_ptr create_function(const std::vector<expression_ptr>& args) const = 0;
00636 virtual ~base_function_creator() {}
00637 };
00638
00639 template<typename T>
00640 class function_creator : public base_function_creator {
00641 public:
00642 virtual expression_ptr create_function(const std::vector<expression_ptr>& args) const {
00643 return expression_ptr(new T(args));
00644 }
00645 virtual ~function_creator() {}
00646 };
00647
00648 typedef std::map<std::string, base_function_creator*> functions_map;
00649
00650 functions_map& get_functions_map() {
00651
00652 static functions_map functions_table;
00653
00654 if(functions_table.empty()) {
00655 #define FUNCTION(name) functions_table[#name] = new function_creator<name##_function>();
00656 FUNCTION(dir);
00657 FUNCTION(if);
00658 FUNCTION(switch);
00659 FUNCTION(abs);
00660 FUNCTION(min);
00661 FUNCTION(max);
00662 FUNCTION(choose);
00663 FUNCTION(wave);
00664 FUNCTION(sort);
00665 FUNCTION(filter);
00666 FUNCTION(find);
00667 FUNCTION(map);
00668 FUNCTION(sum);
00669 FUNCTION(head);
00670 FUNCTION(rgb);
00671 FUNCTION(transition);
00672 FUNCTION(color_transition);
00673 FUNCTION(size);
00674 FUNCTION(null);
00675 FUNCTION(refcount);
00676 FUNCTION(loc);
00677 FUNCTION(keys);
00678 FUNCTION(values);
00679 #undef FUNCTION
00680 }
00681
00682 return functions_table;
00683 }
00684
00685 }
00686
00687 expression_ptr create_function(const std::string& fn,
00688 const std::vector<expression_ptr>& args,
00689 const function_symbol_table* symbols)
00690 {
00691 if(symbols) {
00692 expression_ptr res(symbols->create_function(fn, args));
00693 if(res) {
00694 return res;
00695 }
00696 }
00697
00698 std::cerr << "FN: '" << fn << "' " << fn.size() << "\n";
00699
00700 functions_map::const_iterator i = get_functions_map().find(fn);
00701 if(i == get_functions_map().end()) {
00702 std::cerr << "no function '" << fn << "'\n";
00703 throw formula_error();
00704 }
00705
00706 return i->second->create_function(args);
00707 }
00708
00709 std::vector<std::string> builtin_function_names()
00710 {
00711 std::vector<std::string> res;
00712 const functions_map& m = get_functions_map();
00713 for(functions_map::const_iterator i = m.begin(); i != m.end(); ++i) {
00714 res.push_back(i->first);
00715 }
00716
00717 return res;
00718 }
00719
00720 }