ai_list.cpp

Go to the documentation of this file.
00001 /* $Id: ai_list.cpp 20563 2010-08-19 15:37:28Z yexo $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "ai_list.hpp"
00013 #include "../../debug.h"
00014 #include "../../script/squirrel.hpp"
00015 
00019 class AIListSorter {
00020 protected:
00021   AIList *list;
00022 
00023 public:
00027   virtual ~AIListSorter() { }
00028 
00032   virtual int32 Begin() = 0;
00033 
00037   virtual void End() = 0;
00038 
00042   virtual int32 Next() = 0;
00043 
00047   virtual bool IsEnd() = 0;
00048 
00052   virtual void Remove(int item) = 0;
00053 };
00054 
00058 class AIListSorterValueAscending : public AIListSorter {
00059 private:
00060   AIList::AIListBucket::iterator bucket_iter;
00061   AIList::AIItemList *bucket_list;
00062   AIList::AIItemList::iterator bucket_list_iter;
00063   bool has_no_more_items;
00064   int32 item_next;
00065 
00066 public:
00067   AIListSorterValueAscending(AIList *list)
00068   {
00069     this->list = list;
00070     this->End();
00071   }
00072 
00073   int32 Begin()
00074   {
00075     if (this->list->buckets.empty()) return 0;
00076     this->has_no_more_items = false;
00077 
00078     this->bucket_iter = this->list->buckets.begin();
00079     this->bucket_list = &(*this->bucket_iter).second;
00080     this->bucket_list_iter = this->bucket_list->begin();
00081     this->item_next = *this->bucket_list_iter;
00082 
00083     int32 item_current = this->item_next;
00084     FindNext();
00085     return item_current;
00086   }
00087 
00088   void End()
00089   {
00090     this->bucket_list = NULL;
00091     this->has_no_more_items = true;
00092     this->item_next = 0;
00093   }
00094 
00095   void FindNext()
00096   {
00097     if (this->bucket_list == NULL) {
00098       this->has_no_more_items = true;
00099       return;
00100     }
00101 
00102     this->bucket_list_iter++;
00103     if (this->bucket_list_iter == this->bucket_list->end()) {
00104       this->bucket_iter++;
00105       if (this->bucket_iter == this->list->buckets.end()) {
00106         this->bucket_list = NULL;
00107         return;
00108       }
00109       this->bucket_list = &(*this->bucket_iter).second;
00110       this->bucket_list_iter = this->bucket_list->begin();
00111     }
00112     this->item_next = *this->bucket_list_iter;
00113   }
00114 
00115   int32 Next()
00116   {
00117     if (this->IsEnd()) return 0;
00118 
00119     int32 item_current = this->item_next;
00120     FindNext();
00121     return item_current;
00122   }
00123 
00124   void Remove(int item)
00125   {
00126     if (this->IsEnd()) return;
00127 
00128     /* If we remove the 'next' item, skip to the next */
00129     if (item == this->item_next) {
00130       FindNext();
00131       return;
00132     }
00133   }
00134 
00135   bool IsEnd()
00136   {
00137     return this->list->buckets.empty() || this->has_no_more_items;
00138   }
00139 };
00140 
00144 class AIListSorterValueDescending : public AIListSorter {
00145 private:
00146   AIList::AIListBucket::iterator bucket_iter;
00147   AIList::AIItemList *bucket_list;
00148   AIList::AIItemList::iterator bucket_list_iter;
00149   bool has_no_more_items;
00150   int32 item_next;
00151 
00152 public:
00153   AIListSorterValueDescending(AIList *list)
00154   {
00155     this->list = list;
00156     this->End();
00157   }
00158 
00159   int32 Begin()
00160   {
00161     if (this->list->buckets.empty()) return 0;
00162     this->has_no_more_items = false;
00163 
00164     /* Go to the end of the bucket-list */
00165     this->bucket_iter = this->list->buckets.begin();
00166     for (size_t i = this->list->buckets.size(); i > 1; i--) this->bucket_iter++;
00167     this->bucket_list = &(*this->bucket_iter).second;
00168 
00169     /* Go to the end of the items in the bucket */
00170     this->bucket_list_iter = this->bucket_list->begin();
00171     for (size_t i = this->bucket_list->size(); i > 1; i--) this->bucket_list_iter++;
00172     this->item_next = *this->bucket_list_iter;
00173 
00174     int32 item_current = this->item_next;
00175     FindNext();
00176     return item_current;
00177   }
00178 
00179   void End()
00180   {
00181     this->bucket_list = NULL;
00182     this->has_no_more_items = true;
00183     this->item_next = 0;
00184   }
00185 
00186   void FindNext()
00187   {
00188     if (this->bucket_list == NULL) {
00189       this->has_no_more_items = true;
00190       return;
00191     }
00192 
00193     if (this->bucket_list_iter == this->bucket_list->begin()) {
00194       if (this->bucket_iter == this->list->buckets.begin()) {
00195         this->bucket_list = NULL;
00196         return;
00197       }
00198       this->bucket_iter--;
00199       this->bucket_list = &(*this->bucket_iter).second;
00200       /* Go to the end of the items in the bucket */
00201       this->bucket_list_iter = this->bucket_list->begin();
00202       for (size_t i = this->bucket_list->size(); i > 1; i--) this->bucket_list_iter++;
00203     } else {
00204       this->bucket_list_iter--;
00205     }
00206     this->item_next = *this->bucket_list_iter;
00207   }
00208 
00209   int32 Next()
00210   {
00211     if (this->IsEnd()) return 0;
00212 
00213     int32 item_current = this->item_next;
00214     FindNext();
00215     return item_current;
00216   }
00217 
00218   void Remove(int item)
00219   {
00220     if (this->IsEnd()) return;
00221 
00222     /* If we remove the 'next' item, skip to the next */
00223     if (item == this->item_next) {
00224       FindNext();
00225       return;
00226     }
00227   }
00228 
00229   bool IsEnd()
00230   {
00231     return this->list->buckets.empty() || this->has_no_more_items;
00232   }
00233 };
00234 
00238 class AIListSorterItemAscending : public AIListSorter {
00239 private:
00240   AIList::AIListMap::iterator item_iter;
00241   bool has_no_more_items;
00242   int32 item_next;
00243 
00244 public:
00245   AIListSorterItemAscending(AIList *list)
00246   {
00247     this->list = list;
00248     this->End();
00249   }
00250 
00251   int32 Begin()
00252   {
00253     if (this->list->items.empty()) return 0;
00254     this->has_no_more_items = false;
00255 
00256     this->item_iter = this->list->items.begin();
00257     this->item_next = (*this->item_iter).first;
00258 
00259     int32 item_current = this->item_next;
00260     FindNext();
00261     return item_current;
00262   }
00263 
00264   void End()
00265   {
00266     this->has_no_more_items = true;
00267   }
00268 
00269   void FindNext()
00270   {
00271     if (this->item_iter == this->list->items.end()) {
00272       this->has_no_more_items = true;
00273       return;
00274     }
00275     this->item_iter++;
00276     if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first;
00277   }
00278 
00279   int32 Next()
00280   {
00281     if (this->IsEnd()) return 0;
00282 
00283     int32 item_current = this->item_next;
00284     FindNext();
00285     return item_current;
00286   }
00287 
00288   void Remove(int item)
00289   {
00290     if (this->IsEnd()) return;
00291 
00292     /* If we remove the 'next' item, skip to the next */
00293     if (item == this->item_next) {
00294       FindNext();
00295       return;
00296     }
00297   }
00298 
00299   bool IsEnd()
00300   {
00301     return this->list->items.empty() || this->has_no_more_items;
00302   }
00303 };
00304 
00308 class AIListSorterItemDescending : public AIListSorter {
00309 private:
00310   AIList::AIListMap::iterator item_iter;
00311   bool has_no_more_items;
00312   int32 item_next;
00313 
00314 public:
00315   AIListSorterItemDescending(AIList *list)
00316   {
00317     this->list = list;
00318     this->End();
00319   }
00320 
00321   int32 Begin()
00322   {
00323     if (this->list->items.empty()) return 0;
00324     this->has_no_more_items = false;
00325 
00326     this->item_iter = this->list->items.begin();
00327     for (size_t i = this->list->items.size(); i > 1; i--) this->item_iter++;
00328     this->item_next = (*this->item_iter).first;
00329 
00330     int32 item_current = this->item_next;
00331     FindNext();
00332     return item_current;
00333   }
00334 
00335   void End()
00336   {
00337     this->has_no_more_items = true;
00338   }
00339 
00340   void FindNext()
00341   {
00342     if (this->item_iter == this->list->items.end()) {
00343       this->has_no_more_items = true;
00344       return;
00345     }
00346     this->item_iter--;
00347     if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first;
00348   }
00349 
00350   int32 Next()
00351   {
00352     if (this->IsEnd()) return 0;
00353 
00354     int32 item_current = this->item_next;
00355     FindNext();
00356     return item_current;
00357   }
00358 
00359   void Remove(int item)
00360   {
00361     if (this->IsEnd()) return;
00362 
00363     /* If we remove the 'next' item, skip to the next */
00364     if (item == this->item_next) {
00365       FindNext();
00366       return;
00367     }
00368   }
00369 
00370   bool IsEnd()
00371   {
00372     return this->list->items.empty() || this->has_no_more_items;
00373   }
00374 };
00375 
00376 
00377 
00378 AIList::AIList()
00379 {
00380   /* Default sorter */
00381   this->sorter         = new AIListSorterValueDescending(this);
00382   this->sorter_type    = SORT_BY_VALUE;
00383   this->sort_ascending = false;
00384   this->initialized    = false;
00385   this->modifications  = 0;
00386 }
00387 
00388 AIList::~AIList()
00389 {
00390   delete this->sorter;
00391 }
00392 
00393 bool AIList::HasItem(int32 item)
00394 {
00395   return this->items.count(item) == 1;
00396 }
00397 
00398 void AIList::Clear()
00399 {
00400   this->modifications++;
00401 
00402   this->items.clear();
00403   this->buckets.clear();
00404   this->sorter->End();
00405 }
00406 
00407 void AIList::AddItem(int32 item, int32 value)
00408 {
00409   this->modifications++;
00410 
00411   if (this->HasItem(item)) return;
00412 
00413   this->items[item] = 0;
00414   this->buckets[0].insert(item);
00415 
00416   this->SetValue(item, value);
00417 }
00418 
00419 void AIList::RemoveItem(int32 item)
00420 {
00421   this->modifications++;
00422 
00423   if (!this->HasItem(item)) return;
00424 
00425   int32 value = this->GetValue(item);
00426 
00427   this->sorter->Remove(item);
00428   this->buckets[value].erase(item);
00429   if (this->buckets[value].empty()) this->buckets.erase(value);
00430   this->items.erase(item);
00431 }
00432 
00433 int32 AIList::Begin()
00434 {
00435   this->initialized = true;
00436   return this->sorter->Begin();
00437 }
00438 
00439 int32 AIList::Next()
00440 {
00441   if (this->initialized == false) {
00442     DEBUG(ai, 0, "Next() is invalid as Begin() is never called");
00443     return 0;
00444   }
00445   return this->sorter->Next();
00446 }
00447 
00448 bool AIList::IsEmpty()
00449 {
00450   return this->items.empty();
00451 }
00452 
00453 bool AIList::IsEnd()
00454 {
00455   if (this->initialized == false) {
00456     DEBUG(ai, 0, "IsEnd() is invalid as Begin() is never called");
00457     return true;
00458   }
00459   return this->sorter->IsEnd();
00460 }
00461 
00462 int32 AIList::Count()
00463 {
00464   return (int32)this->items.size();
00465 }
00466 
00467 int32 AIList::GetValue(int32 item)
00468 {
00469   if (!this->HasItem(item)) return 0;
00470 
00471   return this->items[item];
00472 }
00473 
00474 bool AIList::SetValue(int32 item, int32 value)
00475 {
00476   this->modifications++;
00477 
00478   if (!this->HasItem(item)) return false;
00479 
00480   int32 value_old = this->GetValue(item);
00481   if (value_old == value) return true;
00482 
00483   this->sorter->Remove(item);
00484   this->buckets[value_old].erase(item);
00485   if (this->buckets[value_old].empty()) this->buckets.erase(value_old);
00486   this->items[item] = value;
00487   this->buckets[value].insert(item);
00488 
00489   return true;
00490 }
00491 
00492 void AIList::Sort(SorterType sorter, bool ascending)
00493 {
00494   this->modifications++;
00495 
00496   if (sorter != SORT_BY_VALUE && sorter != SORT_BY_ITEM) return;
00497   if (sorter == this->sorter_type && ascending == this->sort_ascending) return;
00498 
00499   delete this->sorter;
00500   switch (sorter) {
00501     case SORT_BY_ITEM:
00502       if (ascending) {
00503         this->sorter = new AIListSorterItemAscending(this);
00504       } else {
00505         this->sorter = new AIListSorterItemDescending(this);
00506       }
00507       break;
00508 
00509     case SORT_BY_VALUE:
00510       if (ascending) {
00511         this->sorter = new AIListSorterValueAscending(this);
00512       } else {
00513         this->sorter = new AIListSorterValueDescending(this);
00514       }
00515       break;
00516 
00517     default:
00518       this->Sort(SORT_BY_ITEM, false);
00519       return;
00520   }
00521   this->sorter_type    = sorter;
00522   this->sort_ascending = ascending;
00523   this->initialized    = false;
00524 }
00525 
00526 void AIList::AddList(AIList *list)
00527 {
00528   AIListMap *list_items = &list->items;
00529   for (AIListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) {
00530     this->AddItem((*iter).first);
00531     this->SetValue((*iter).first, (*iter).second);
00532   }
00533 }
00534 
00535 void AIList::RemoveAboveValue(int32 value)
00536 {
00537   this->modifications++;
00538 
00539   for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
00540     next_iter = iter; next_iter++;
00541     if ((*iter).second > value) this->RemoveItem((*iter).first);
00542   }
00543 }
00544 
00545 void AIList::RemoveBelowValue(int32 value)
00546 {
00547   this->modifications++;
00548 
00549   for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
00550     next_iter = iter; next_iter++;
00551     if ((*iter).second < value) this->RemoveItem((*iter).first);
00552   }
00553 }
00554 
00555 void AIList::RemoveBetweenValue(int32 start, int32 end)
00556 {
00557   this->modifications++;
00558 
00559   for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
00560     next_iter = iter; next_iter++;
00561     if ((*iter).second > start && (*iter).second < end) this->RemoveItem((*iter).first);
00562   }
00563 }
00564 
00565 void AIList::RemoveValue(int32 value)
00566 {
00567   this->modifications++;
00568 
00569   for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
00570     next_iter = iter; next_iter++;
00571     if ((*iter).second == value) this->RemoveItem((*iter).first);
00572   }
00573 }
00574 
00575 void AIList::RemoveTop(int32 count)
00576 {
00577   this->modifications++;
00578 
00579   if (!this->sort_ascending) {
00580     this->Sort(this->sorter_type, !this->sort_ascending);
00581     this->RemoveBottom(count);
00582     this->Sort(this->sorter_type, !this->sort_ascending);
00583     return;
00584   }
00585 
00586   switch (this->sorter_type) {
00587     default: NOT_REACHED();
00588     case SORT_BY_VALUE:
00589       for (AIListBucket::iterator iter = this->buckets.begin(); iter != this->buckets.end(); iter = this->buckets.begin()) {
00590         AIItemList *items = &(*iter).second;
00591         size_t size = items->size();
00592         for (AIItemList::iterator iter = items->begin(); iter != items->end(); iter = items->begin()) {
00593           if (--count < 0) return;
00594           this->RemoveItem(*iter);
00595           /* When the last item is removed from the bucket, the bucket itself is removed.
00596            * This means that the iterators can be invalid after a call to RemoveItem.
00597            */
00598           if (--size == 0) break;
00599         }
00600       }
00601       break;
00602 
00603     case SORT_BY_ITEM:
00604       for (AIListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter = this->items.begin()) {
00605         if (--count < 0) return;
00606         this->RemoveItem((*iter).first);
00607       }
00608       break;
00609   }
00610 }
00611 
00612 void AIList::RemoveBottom(int32 count)
00613 {
00614   this->modifications++;
00615 
00616   if (!this->sort_ascending) {
00617     this->Sort(this->sorter_type, !this->sort_ascending);
00618     this->RemoveTop(count);
00619     this->Sort(this->sorter_type, !this->sort_ascending);
00620     return;
00621   }
00622 
00623   switch (this->sorter_type) {
00624     default: NOT_REACHED();
00625     case SORT_BY_VALUE:
00626       for (AIListBucket::reverse_iterator iter = this->buckets.rbegin(); iter != this->buckets.rend(); iter = this->buckets.rbegin()) {
00627         AIItemList *items = &(*iter).second;
00628         size_t size = items->size();
00629         for (AIItemList::reverse_iterator iter = items->rbegin(); iter != items->rend(); iter = items->rbegin()) {
00630           if (--count < 0) return;
00631           this->RemoveItem(*iter);
00632           /* When the last item is removed from the bucket, the bucket itself is removed.
00633            * This means that the iterators can be invalid after a call to RemoveItem.
00634            */
00635           if (--size == 0) break;
00636         }
00637       }
00638 
00639     case SORT_BY_ITEM:
00640       for (AIListMap::reverse_iterator iter = this->items.rbegin(); iter != this->items.rend(); iter = this->items.rbegin()) {
00641         if (--count < 0) return;
00642         this->RemoveItem((*iter).first);
00643       }
00644       break;
00645   }
00646 }
00647 
00648 void AIList::RemoveList(AIList *list)
00649 {
00650   this->modifications++;
00651 
00652   AIListMap *list_items = &list->items;
00653   for (AIListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) {
00654     this->RemoveItem((*iter).first);
00655   }
00656 }
00657 
00658 void AIList::KeepAboveValue(int32 value)
00659 {
00660   this->modifications++;
00661 
00662   for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
00663     next_iter = iter; next_iter++;
00664     if ((*iter).second <= value) this->RemoveItem((*iter).first);
00665   }
00666 }
00667 
00668 void AIList::KeepBelowValue(int32 value)
00669 {
00670   this->modifications++;
00671 
00672   for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
00673     next_iter = iter; next_iter++;
00674     if ((*iter).second >= value) this->RemoveItem((*iter).first);
00675   }
00676 }
00677 
00678 void AIList::KeepBetweenValue(int32 start, int32 end)
00679 {
00680   this->modifications++;
00681 
00682   for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
00683     next_iter = iter; next_iter++;
00684     if ((*iter).second <= start || (*iter).second >= end) this->RemoveItem((*iter).first);
00685   }
00686 }
00687 
00688 void AIList::KeepValue(int32 value)
00689 {
00690   this->modifications++;
00691 
00692   for (AIListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
00693     next_iter = iter; next_iter++;
00694     if ((*iter).second != value) this->RemoveItem((*iter).first);
00695   }
00696 }
00697 
00698 void AIList::KeepTop(int32 count)
00699 {
00700   this->modifications++;
00701 
00702   this->RemoveBottom(this->Count() - count);
00703 }
00704 
00705 void AIList::KeepBottom(int32 count)
00706 {
00707   this->modifications++;
00708 
00709   this->RemoveTop(this->Count() - count);
00710 }
00711 
00712 void AIList::KeepList(AIList *list)
00713 {
00714   this->modifications++;
00715 
00716   AIList tmp;
00717   for (AIListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) {
00718     tmp.AddItem((*iter).first);
00719     tmp.SetValue((*iter).first, (*iter).second);
00720   }
00721 
00722   tmp.RemoveList(list);
00723   this->RemoveList(&tmp);
00724 }
00725 
00726 SQInteger AIList::_get(HSQUIRRELVM vm)
00727 {
00728   if (sq_gettype(vm, 2) != OT_INTEGER) return SQ_ERROR;
00729 
00730   SQInteger idx;
00731   sq_getinteger(vm, 2, &idx);
00732 
00733   if (!this->HasItem(idx)) return SQ_ERROR;
00734 
00735   sq_pushinteger(vm, this->GetValue(idx));
00736   return 1;
00737 }
00738 
00739 SQInteger AIList::_set(HSQUIRRELVM vm)
00740 {
00741   if (sq_gettype(vm, 2) != OT_INTEGER) return SQ_ERROR;
00742   if (sq_gettype(vm, 3) != OT_INTEGER || sq_gettype(vm, 3) == OT_NULL) {
00743     return sq_throwerror(vm, _SC("you can only assign integers to this list"));
00744   }
00745 
00746   SQInteger idx, val;
00747   sq_getinteger(vm, 2, &idx);
00748   if (sq_gettype(vm, 3) == OT_NULL) {
00749     this->RemoveItem(idx);
00750     return 0;
00751   }
00752 
00753   sq_getinteger(vm, 3, &val);
00754   if (!this->HasItem(idx)) {
00755     this->AddItem(idx, val);
00756     return 0;
00757   }
00758 
00759   this->SetValue(idx, val);
00760   return 0;
00761 }
00762 
00763 SQInteger AIList::_nexti(HSQUIRRELVM vm)
00764 {
00765   if (sq_gettype(vm, 2) == OT_NULL) {
00766     if (this->IsEmpty()) {
00767       sq_pushnull(vm);
00768       return 1;
00769     }
00770     sq_pushinteger(vm, this->Begin());
00771     return 1;
00772   }
00773 
00774   SQInteger idx;
00775   sq_getinteger(vm, 2, &idx);
00776 
00777   int val = this->Next();
00778   if (this->IsEnd()) {
00779     sq_pushnull(vm);
00780     return 1;
00781   }
00782 
00783   sq_pushinteger(vm, val);
00784   return 1;
00785 }
00786 
00787 SQInteger AIList::Valuate(HSQUIRRELVM vm)
00788 {
00789   this->modifications++;
00790 
00791   /* The first parameter is the instance of AIList. */
00792   int nparam = sq_gettop(vm) - 1;
00793 
00794   if (nparam < 1) {
00795     return sq_throwerror(vm, _SC("You need to give a least a Valuator as parameter to AIList::Valuate"));
00796   }
00797 
00798   /* Make sure the valuator function is really a function, and not any
00799    * other type. It's parameter 2 for us, but for the user it's the
00800    * first parameter they give. */
00801   SQObjectType valuator_type = sq_gettype(vm, 2);
00802   if (valuator_type != OT_CLOSURE && valuator_type != OT_NATIVECLOSURE) {
00803     return sq_throwerror(vm, _SC("parameter 1 has an invalid type (expected function)"));
00804   }
00805 
00806   /* Don't allow docommand from a Valuator, as we can't resume in
00807    * mid C++-code. */
00808   bool backup_allow = AIObject::GetAllowDoCommand();
00809   AIObject::SetAllowDoCommand(false);
00810 
00811   /* Push the function to call */
00812   sq_push(vm, 2);
00813 
00814   for (AIListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) {
00815     /* Check for changing of items. */
00816     int previous_modification_count = this->modifications;
00817 
00818     /* Push the root table as instance object, this is what squirrel does for meta-functions. */
00819     sq_pushroottable(vm);
00820     /* Push all arguments for the valuator function. */
00821     sq_pushinteger(vm, (*iter).first);
00822     for (int i = 0; i < nparam - 1; i++) {
00823       sq_push(vm, i + 3);
00824     }
00825 
00826     /* Call the function. Squirrel pops all parameters and pushes the return value. */
00827     if (SQ_FAILED(sq_call(vm, nparam + 1, SQTrue, SQTrue))) {
00828       AIObject::SetAllowDoCommand(backup_allow);
00829       return SQ_ERROR;
00830     }
00831 
00832     /* Retreive the return value */
00833     SQInteger value;
00834     switch (sq_gettype(vm, -1)) {
00835       case OT_INTEGER: {
00836         sq_getinteger(vm, -1, &value);
00837         break;
00838       }
00839 
00840       case OT_BOOL: {
00841         SQBool v;
00842         sq_getbool(vm, -1, &v);
00843         value = v ? 1 : 0;
00844         break;
00845       }
00846 
00847       default: {
00848         /* See below for explanation. The extra pop is the return value. */
00849         sq_pop(vm, nparam + 4);
00850 
00851         AIObject::SetAllowDoCommand(backup_allow);
00852         return sq_throwerror(vm, _SC("return value of valuator is not valid (not integer/bool)"));
00853       }
00854     }
00855 
00856     /* Was something changed? */
00857     if (previous_modification_count != this->modifications) {
00858       /* See below for explanation. The extra pop is the return value. */
00859       sq_pop(vm, nparam + 4);
00860 
00861       AIObject::SetAllowDoCommand(backup_allow);
00862       return sq_throwerror(vm, _SC("modifying valuated list outside of valuator function"));
00863     }
00864 
00865     this->SetValue((*iter).first, value);
00866 
00867     /* Pop the return value. */
00868     sq_poptop(vm);
00869 
00870     Squirrel::DecreaseOps(vm, 5);
00871   }
00872   /* Pop from the squirrel stack:
00873    * 1. The root stable (as instance object).
00874    * 2. The valuator function.
00875    * 3. The parameters given to this function.
00876    * 4. The AIList instance object. */
00877   sq_pop(vm, nparam + 3);
00878 
00879   AIObject::SetAllowDoCommand(backup_allow);
00880   return 0;
00881 }

Generated on Thu Jan 20 22:57:31 2011 for OpenTTD by  doxygen 1.6.1