Update: Translations from eints
[openttd-github.git] / src / script / api / script_list.cpp
blobf774b2a00445f5fe13b79f2eabd29e36adcbe4aa
1 /*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
6 */
8 /** @file script_list.cpp Implementation of ScriptList. */
10 #include "../../stdafx.h"
11 #include "script_list.hpp"
12 #include "../../debug.h"
13 #include "../../script/squirrel.hpp"
15 #include "../../safeguards.h"
17 /**
18 * Base class for any ScriptList sorter.
20 class ScriptListSorter {
21 protected:
22 ScriptList *list; ///< The list that's being sorted.
23 bool has_no_more_items; ///< Whether we have more items to iterate over.
24 SQInteger item_next; ///< The next item we will show.
26 public:
27 /**
28 * Virtual dtor, needed to mute warnings.
30 virtual ~ScriptListSorter() = default;
32 /**
33 * Get the first item of the sorter.
35 virtual SQInteger Begin() = 0;
37 /**
38 * Stop iterating a sorter.
40 virtual void End() = 0;
42 /**
43 * Get the next item of the sorter.
45 virtual SQInteger Next() = 0;
47 /**
48 * See if the sorter has reached the end.
50 bool IsEnd()
52 return this->list->buckets.empty() || this->has_no_more_items;
55 /**
56 * Callback from the list if an item gets removed.
58 virtual void Remove(SQInteger item) = 0;
60 /**
61 * Attach the sorter to a new list. This assumes the content of the old list has been moved to
62 * the new list, too, so that we don't have to invalidate any iterators. Note that std::swap
63 * doesn't invalidate iterators on lists and maps, so that should be safe.
64 * @param target New list to attach to.
66 virtual void Retarget(ScriptList *new_list)
68 this->list = new_list;
72 /**
73 * Sort by value, ascending.
75 class ScriptListSorterValueAscending : public ScriptListSorter {
76 private:
77 ScriptList::ScriptListBucket::iterator bucket_iter; ///< The iterator over the list to find the buckets.
78 ScriptList::ScriptItemList *bucket_list; ///< The current bucket list we're iterator over.
79 ScriptList::ScriptItemList::iterator bucket_list_iter; ///< The iterator over the bucket list.
81 public:
82 /**
83 * Create a new sorter.
84 * @param list The list to sort.
86 ScriptListSorterValueAscending(ScriptList *list)
88 this->list = list;
89 this->End();
92 SQInteger Begin() override
94 if (this->list->buckets.empty()) return 0;
95 this->has_no_more_items = false;
97 this->bucket_iter = this->list->buckets.begin();
98 this->bucket_list = &(*this->bucket_iter).second;
99 this->bucket_list_iter = this->bucket_list->begin();
100 this->item_next = *this->bucket_list_iter;
102 SQInteger item_current = this->item_next;
103 FindNext();
104 return item_current;
107 void End() override
109 this->bucket_list = nullptr;
110 this->has_no_more_items = true;
111 this->item_next = 0;
115 * Find the next item, and store that information.
117 void FindNext()
119 if (this->bucket_list == nullptr) {
120 this->has_no_more_items = true;
121 return;
124 this->bucket_list_iter++;
125 if (this->bucket_list_iter == this->bucket_list->end()) {
126 this->bucket_iter++;
127 if (this->bucket_iter == this->list->buckets.end()) {
128 this->bucket_list = nullptr;
129 return;
131 this->bucket_list = &(*this->bucket_iter).second;
132 this->bucket_list_iter = this->bucket_list->begin();
134 this->item_next = *this->bucket_list_iter;
137 SQInteger Next() override
139 if (this->IsEnd()) return 0;
141 SQInteger item_current = this->item_next;
142 FindNext();
143 return item_current;
146 void Remove(SQInteger item) override
148 if (this->IsEnd()) return;
150 /* If we remove the 'next' item, skip to the next */
151 if (item == this->item_next) {
152 FindNext();
153 return;
159 * Sort by value, descending.
161 class ScriptListSorterValueDescending : public ScriptListSorter {
162 private:
163 /* Note: We cannot use reverse_iterator.
164 * The iterators must only be invalidated when the element they are pointing to is removed.
165 * This only holds for forward iterators. */
166 ScriptList::ScriptListBucket::iterator bucket_iter; ///< The iterator over the list to find the buckets.
167 ScriptList::ScriptItemList *bucket_list; ///< The current bucket list we're iterator over.
168 ScriptList::ScriptItemList::iterator bucket_list_iter; ///< The iterator over the bucket list.
170 public:
172 * Create a new sorter.
173 * @param list The list to sort.
175 ScriptListSorterValueDescending(ScriptList *list)
177 this->list = list;
178 this->End();
181 SQInteger Begin() override
183 if (this->list->buckets.empty()) return 0;
184 this->has_no_more_items = false;
186 /* Go to the end of the bucket-list */
187 this->bucket_iter = this->list->buckets.end();
188 --this->bucket_iter;
189 this->bucket_list = &(*this->bucket_iter).second;
191 /* Go to the end of the items in the bucket */
192 this->bucket_list_iter = this->bucket_list->end();
193 --this->bucket_list_iter;
194 this->item_next = *this->bucket_list_iter;
196 SQInteger item_current = this->item_next;
197 FindNext();
198 return item_current;
201 void End() override
203 this->bucket_list = nullptr;
204 this->has_no_more_items = true;
205 this->item_next = 0;
209 * Find the next item, and store that information.
211 void FindNext()
213 if (this->bucket_list == nullptr) {
214 this->has_no_more_items = true;
215 return;
218 if (this->bucket_list_iter == this->bucket_list->begin()) {
219 if (this->bucket_iter == this->list->buckets.begin()) {
220 this->bucket_list = nullptr;
221 return;
223 this->bucket_iter--;
224 this->bucket_list = &(*this->bucket_iter).second;
225 /* Go to the end of the items in the bucket */
226 this->bucket_list_iter = this->bucket_list->end();
227 --this->bucket_list_iter;
228 } else {
229 this->bucket_list_iter--;
231 this->item_next = *this->bucket_list_iter;
234 SQInteger Next() override
236 if (this->IsEnd()) return 0;
238 SQInteger item_current = this->item_next;
239 FindNext();
240 return item_current;
243 void Remove(SQInteger item) override
245 if (this->IsEnd()) return;
247 /* If we remove the 'next' item, skip to the next */
248 if (item == this->item_next) {
249 FindNext();
250 return;
256 * Sort by item, ascending.
258 class ScriptListSorterItemAscending : public ScriptListSorter {
259 private:
260 ScriptList::ScriptListMap::iterator item_iter; ///< The iterator over the items in the map.
262 public:
264 * Create a new sorter.
265 * @param list The list to sort.
267 ScriptListSorterItemAscending(ScriptList *list)
269 this->list = list;
270 this->End();
273 SQInteger Begin() override
275 if (this->list->items.empty()) return 0;
276 this->has_no_more_items = false;
278 this->item_iter = this->list->items.begin();
279 this->item_next = (*this->item_iter).first;
281 SQInteger item_current = this->item_next;
282 FindNext();
283 return item_current;
286 void End() override
288 this->has_no_more_items = true;
292 * Find the next item, and store that information.
294 void FindNext()
296 if (this->item_iter == this->list->items.end()) {
297 this->has_no_more_items = true;
298 return;
300 this->item_iter++;
301 if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first;
304 SQInteger Next() override
306 if (this->IsEnd()) return 0;
308 SQInteger item_current = this->item_next;
309 FindNext();
310 return item_current;
313 void Remove(SQInteger item) override
315 if (this->IsEnd()) return;
317 /* If we remove the 'next' item, skip to the next */
318 if (item == this->item_next) {
319 FindNext();
320 return;
326 * Sort by item, descending.
328 class ScriptListSorterItemDescending : public ScriptListSorter {
329 private:
330 /* Note: We cannot use reverse_iterator.
331 * The iterators must only be invalidated when the element they are pointing to is removed.
332 * This only holds for forward iterators. */
333 ScriptList::ScriptListMap::iterator item_iter; ///< The iterator over the items in the map.
335 public:
337 * Create a new sorter.
338 * @param list The list to sort.
340 ScriptListSorterItemDescending(ScriptList *list)
342 this->list = list;
343 this->End();
346 SQInteger Begin() override
348 if (this->list->items.empty()) return 0;
349 this->has_no_more_items = false;
351 this->item_iter = this->list->items.end();
352 --this->item_iter;
353 this->item_next = (*this->item_iter).first;
355 SQInteger item_current = this->item_next;
356 FindNext();
357 return item_current;
360 void End() override
362 this->has_no_more_items = true;
366 * Find the next item, and store that information.
368 void FindNext()
370 if (this->item_iter == this->list->items.end()) {
371 this->has_no_more_items = true;
372 return;
374 if (this->item_iter == this->list->items.begin()) {
375 /* Use 'end' as marker for 'beyond begin' */
376 this->item_iter = this->list->items.end();
377 } else {
378 this->item_iter--;
380 if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first;
383 SQInteger Next() override
385 if (this->IsEnd()) return 0;
387 SQInteger item_current = this->item_next;
388 FindNext();
389 return item_current;
392 void Remove(SQInteger item) override
394 if (this->IsEnd()) return;
396 /* If we remove the 'next' item, skip to the next */
397 if (item == this->item_next) {
398 FindNext();
399 return;
406 ScriptList::ScriptList()
408 /* Default sorter */
409 this->sorter = new ScriptListSorterValueDescending(this);
410 this->sorter_type = SORT_BY_VALUE;
411 this->sort_ascending = false;
412 this->initialized = false;
413 this->modifications = 0;
416 ScriptList::~ScriptList()
418 delete this->sorter;
421 bool ScriptList::HasItem(SQInteger item)
423 return this->items.count(item) == 1;
426 void ScriptList::Clear()
428 this->modifications++;
430 this->items.clear();
431 this->buckets.clear();
432 this->sorter->End();
435 void ScriptList::AddItem(SQInteger item, SQInteger value)
437 this->modifications++;
439 if (this->HasItem(item)) return;
441 this->items[item] = value;
442 this->buckets[value].insert(item);
445 void ScriptList::RemoveItem(SQInteger item)
447 this->modifications++;
449 ScriptListMap::iterator item_iter = this->items.find(item);
450 if (item_iter == this->items.end()) return;
452 SQInteger value = item_iter->second;
454 this->sorter->Remove(item);
455 ScriptListBucket::iterator bucket_iter = this->buckets.find(value);
456 assert(bucket_iter != this->buckets.end());
457 bucket_iter->second.erase(item);
458 if (bucket_iter->second.empty()) this->buckets.erase(bucket_iter);
459 this->items.erase(item_iter);
462 SQInteger ScriptList::Begin()
464 this->initialized = true;
465 return this->sorter->Begin();
468 SQInteger ScriptList::Next()
470 if (!this->initialized) {
471 Debug(script, 0, "Next() is invalid as Begin() is never called");
472 return 0;
474 return this->sorter->Next();
477 bool ScriptList::IsEmpty()
479 return this->items.empty();
482 bool ScriptList::IsEnd()
484 if (!this->initialized) {
485 Debug(script, 0, "IsEnd() is invalid as Begin() is never called");
486 return true;
488 return this->sorter->IsEnd();
491 SQInteger ScriptList::Count()
493 return this->items.size();
496 SQInteger ScriptList::GetValue(SQInteger item)
498 ScriptListMap::const_iterator item_iter = this->items.find(item);
499 return item_iter == this->items.end() ? 0 : item_iter->second;
502 bool ScriptList::SetValue(SQInteger item, SQInteger value)
504 this->modifications++;
506 ScriptListMap::iterator item_iter = this->items.find(item);
507 if (item_iter == this->items.end()) return false;
509 SQInteger value_old = item_iter->second;
510 if (value_old == value) return true;
512 this->sorter->Remove(item);
513 ScriptListBucket::iterator bucket_iter = this->buckets.find(value_old);
514 assert(bucket_iter != this->buckets.end());
515 bucket_iter->second.erase(item);
516 if (bucket_iter->second.empty()) this->buckets.erase(bucket_iter);
517 item_iter->second = value;
518 this->buckets[value].insert(item);
520 return true;
523 void ScriptList::Sort(SorterType sorter, bool ascending)
525 this->modifications++;
527 if (sorter != SORT_BY_VALUE && sorter != SORT_BY_ITEM) return;
528 if (sorter == this->sorter_type && ascending == this->sort_ascending) return;
530 delete this->sorter;
531 switch (sorter) {
532 case SORT_BY_ITEM:
533 if (ascending) {
534 this->sorter = new ScriptListSorterItemAscending(this);
535 } else {
536 this->sorter = new ScriptListSorterItemDescending(this);
538 break;
540 case SORT_BY_VALUE:
541 if (ascending) {
542 this->sorter = new ScriptListSorterValueAscending(this);
543 } else {
544 this->sorter = new ScriptListSorterValueDescending(this);
546 break;
548 default: NOT_REACHED();
550 this->sorter_type = sorter;
551 this->sort_ascending = ascending;
552 this->initialized = false;
555 void ScriptList::AddList(ScriptList *list)
557 if (list == this) return;
559 if (this->IsEmpty()) {
560 /* If this is empty, we can just take the items of the other list as is. */
561 this->items = list->items;
562 this->buckets = list->buckets;
563 this->modifications++;
564 } else {
565 ScriptListMap *list_items = &list->items;
566 for (auto &it : *list_items) {
567 this->AddItem(it.first);
568 this->SetValue(it.first, it.second);
573 void ScriptList::SwapList(ScriptList *list)
575 if (list == this) return;
577 this->items.swap(list->items);
578 this->buckets.swap(list->buckets);
579 Swap(this->sorter, list->sorter);
580 Swap(this->sorter_type, list->sorter_type);
581 Swap(this->sort_ascending, list->sort_ascending);
582 Swap(this->initialized, list->initialized);
583 Swap(this->modifications, list->modifications);
584 this->sorter->Retarget(this);
585 list->sorter->Retarget(list);
588 void ScriptList::RemoveAboveValue(SQInteger value)
590 this->modifications++;
592 for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
593 next_iter = iter; next_iter++;
594 if ((*iter).second > value) this->RemoveItem((*iter).first);
598 void ScriptList::RemoveBelowValue(SQInteger value)
600 this->modifications++;
602 for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
603 next_iter = iter; next_iter++;
604 if ((*iter).second < value) this->RemoveItem((*iter).first);
608 void ScriptList::RemoveBetweenValue(SQInteger start, SQInteger end)
610 this->modifications++;
612 for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
613 next_iter = iter; next_iter++;
614 if ((*iter).second > start && (*iter).second < end) this->RemoveItem((*iter).first);
618 void ScriptList::RemoveValue(SQInteger value)
620 this->modifications++;
622 for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
623 next_iter = iter; next_iter++;
624 if ((*iter).second == value) this->RemoveItem((*iter).first);
628 void ScriptList::RemoveTop(SQInteger count)
630 this->modifications++;
632 if (!this->sort_ascending) {
633 this->Sort(this->sorter_type, !this->sort_ascending);
634 this->RemoveBottom(count);
635 this->Sort(this->sorter_type, !this->sort_ascending);
636 return;
639 switch (this->sorter_type) {
640 default: NOT_REACHED();
641 case SORT_BY_VALUE:
642 for (ScriptListBucket::iterator iter = this->buckets.begin(); iter != this->buckets.end(); iter = this->buckets.begin()) {
643 ScriptItemList *items = &(*iter).second;
644 size_t size = items->size();
645 for (ScriptItemList::iterator iter = items->begin(); iter != items->end(); iter = items->begin()) {
646 if (--count < 0) return;
647 this->RemoveItem(*iter);
648 /* When the last item is removed from the bucket, the bucket itself is removed.
649 * This means that the iterators can be invalid after a call to RemoveItem.
651 if (--size == 0) break;
654 break;
656 case SORT_BY_ITEM:
657 for (ScriptListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter = this->items.begin()) {
658 if (--count < 0) return;
659 this->RemoveItem((*iter).first);
661 break;
665 void ScriptList::RemoveBottom(SQInteger count)
667 this->modifications++;
669 if (!this->sort_ascending) {
670 this->Sort(this->sorter_type, !this->sort_ascending);
671 this->RemoveTop(count);
672 this->Sort(this->sorter_type, !this->sort_ascending);
673 return;
676 switch (this->sorter_type) {
677 default: NOT_REACHED();
678 case SORT_BY_VALUE:
679 for (ScriptListBucket::reverse_iterator iter = this->buckets.rbegin(); iter != this->buckets.rend(); iter = this->buckets.rbegin()) {
680 ScriptItemList *items = &(*iter).second;
681 size_t size = items->size();
682 for (ScriptItemList::reverse_iterator iter = items->rbegin(); iter != items->rend(); iter = items->rbegin()) {
683 if (--count < 0) return;
684 this->RemoveItem(*iter);
685 /* When the last item is removed from the bucket, the bucket itself is removed.
686 * This means that the iterators can be invalid after a call to RemoveItem.
688 if (--size == 0) break;
691 break;
693 case SORT_BY_ITEM:
694 for (ScriptListMap::reverse_iterator iter = this->items.rbegin(); iter != this->items.rend(); iter = this->items.rbegin()) {
695 if (--count < 0) return;
696 this->RemoveItem((*iter).first);
698 break;
702 void ScriptList::RemoveList(ScriptList *list)
704 this->modifications++;
706 if (list == this) {
707 Clear();
708 } else {
709 ScriptListMap *list_items = &list->items;
710 for (ScriptListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) {
711 this->RemoveItem((*iter).first);
716 void ScriptList::KeepAboveValue(SQInteger value)
718 this->modifications++;
720 for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
721 next_iter = iter; next_iter++;
722 if ((*iter).second <= value) this->RemoveItem((*iter).first);
726 void ScriptList::KeepBelowValue(SQInteger value)
728 this->modifications++;
730 for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
731 next_iter = iter; next_iter++;
732 if ((*iter).second >= value) this->RemoveItem((*iter).first);
736 void ScriptList::KeepBetweenValue(SQInteger start, SQInteger end)
738 this->modifications++;
740 for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
741 next_iter = iter; next_iter++;
742 if ((*iter).second <= start || (*iter).second >= end) this->RemoveItem((*iter).first);
746 void ScriptList::KeepValue(SQInteger value)
748 this->modifications++;
750 for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
751 next_iter = iter; next_iter++;
752 if ((*iter).second != value) this->RemoveItem((*iter).first);
756 void ScriptList::KeepTop(SQInteger count)
758 this->modifications++;
760 this->RemoveBottom(this->Count() - count);
763 void ScriptList::KeepBottom(SQInteger count)
765 this->modifications++;
767 this->RemoveTop(this->Count() - count);
770 void ScriptList::KeepList(ScriptList *list)
772 if (list == this) return;
774 this->modifications++;
776 ScriptList tmp;
777 tmp.AddList(this);
778 tmp.RemoveList(list);
779 this->RemoveList(&tmp);
782 SQInteger ScriptList::_get(HSQUIRRELVM vm)
784 if (sq_gettype(vm, 2) != OT_INTEGER) return SQ_ERROR;
786 SQInteger idx;
787 sq_getinteger(vm, 2, &idx);
789 ScriptListMap::const_iterator item_iter = this->items.find(idx);
790 if (item_iter == this->items.end()) return SQ_ERROR;
792 sq_pushinteger(vm, item_iter->second);
793 return 1;
796 SQInteger ScriptList::_set(HSQUIRRELVM vm)
798 if (sq_gettype(vm, 2) != OT_INTEGER) return SQ_ERROR;
799 if (sq_gettype(vm, 3) != OT_INTEGER && sq_gettype(vm, 3) != OT_NULL) {
800 return sq_throwerror(vm, "you can only assign integers to this list");
803 SQInteger idx, val;
804 sq_getinteger(vm, 2, &idx);
805 if (sq_gettype(vm, 3) == OT_NULL) {
806 this->RemoveItem(idx);
807 return 0;
810 sq_getinteger(vm, 3, &val);
811 if (!this->HasItem(idx)) {
812 this->AddItem(idx, val);
813 return 0;
816 this->SetValue(idx, val);
817 return 0;
820 SQInteger ScriptList::_nexti(HSQUIRRELVM vm)
822 if (sq_gettype(vm, 2) == OT_NULL) {
823 if (this->IsEmpty()) {
824 sq_pushnull(vm);
825 return 1;
827 sq_pushinteger(vm, this->Begin());
828 return 1;
831 SQInteger idx;
832 sq_getinteger(vm, 2, &idx);
834 SQInteger val = this->Next();
835 if (this->IsEnd()) {
836 sq_pushnull(vm);
837 return 1;
840 sq_pushinteger(vm, val);
841 return 1;
844 SQInteger ScriptList::Valuate(HSQUIRRELVM vm)
846 this->modifications++;
848 /* The first parameter is the instance of ScriptList. */
849 int nparam = sq_gettop(vm) - 1;
851 if (nparam < 1) {
852 return sq_throwerror(vm, "You need to give at least a Valuator as parameter to ScriptList::Valuate");
855 /* Make sure the valuator function is really a function, and not any
856 * other type. It's parameter 2 for us, but for the user it's the
857 * first parameter they give. */
858 SQObjectType valuator_type = sq_gettype(vm, 2);
859 if (valuator_type != OT_CLOSURE && valuator_type != OT_NATIVECLOSURE) {
860 return sq_throwerror(vm, "parameter 1 has an invalid type (expected function)");
863 /* Don't allow docommand from a Valuator, as we can't resume in
864 * mid C++-code. */
865 bool backup_allow = ScriptObject::GetAllowDoCommand();
866 ScriptObject::SetAllowDoCommand(false);
868 /* Limit the total number of ops that can be consumed by a valuate operation */
869 SQOpsLimiter limiter(vm, MAX_VALUATE_OPS, "valuator function");
871 /* Push the function to call */
872 sq_push(vm, 2);
874 for (ScriptListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) {
875 /* Check for changing of items. */
876 int previous_modification_count = this->modifications;
878 /* Push the root table as instance object, this is what squirrel does for meta-functions. */
879 sq_pushroottable(vm);
880 /* Push all arguments for the valuator function. */
881 sq_pushinteger(vm, (*iter).first);
882 for (int i = 0; i < nparam - 1; i++) {
883 sq_push(vm, i + 3);
886 /* Call the function. Squirrel pops all parameters and pushes the return value. */
887 if (SQ_FAILED(sq_call(vm, nparam + 1, SQTrue, SQTrue))) {
888 ScriptObject::SetAllowDoCommand(backup_allow);
889 return SQ_ERROR;
892 /* Retrieve the return value */
893 SQInteger value;
894 switch (sq_gettype(vm, -1)) {
895 case OT_INTEGER: {
896 sq_getinteger(vm, -1, &value);
897 break;
900 case OT_BOOL: {
901 SQBool v;
902 sq_getbool(vm, -1, &v);
903 value = v ? 1 : 0;
904 break;
907 default: {
908 /* See below for explanation. The extra pop is the return value. */
909 sq_pop(vm, nparam + 4);
911 ScriptObject::SetAllowDoCommand(backup_allow);
912 return sq_throwerror(vm, "return value of valuator is not valid (not integer/bool)");
916 /* Was something changed? */
917 if (previous_modification_count != this->modifications) {
918 /* See below for explanation. The extra pop is the return value. */
919 sq_pop(vm, nparam + 4);
921 ScriptObject::SetAllowDoCommand(backup_allow);
922 return sq_throwerror(vm, "modifying valuated list outside of valuator function");
925 this->SetValue((*iter).first, value);
927 /* Pop the return value. */
928 sq_poptop(vm);
930 Squirrel::DecreaseOps(vm, 5);
932 /* Pop from the squirrel stack:
933 * 1. The root stable (as instance object).
934 * 2. The valuator function.
935 * 3. The parameters given to this function.
936 * 4. The ScriptList instance object. */
937 sq_pop(vm, nparam + 3);
939 ScriptObject::SetAllowDoCommand(backup_allow);
940 return 0;