diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/base/tl/algorithms.hpp | 135 | ||||
| -rw-r--r-- | src/base/tl/allocator.hpp | 15 | ||||
| -rw-r--r-- | src/base/tl/array.hpp | 341 | ||||
| -rw-r--r-- | src/base/tl/base.hpp | 15 | ||||
| -rw-r--r-- | src/base/tl/range.hpp | 230 | ||||
| -rw-r--r-- | src/base/tl/sorted_array.hpp | 31 | ||||
| -rw-r--r-- | src/base/tl/string.hpp | 68 | ||||
| -rw-r--r-- | src/game/client/components/menus_browser.cpp | 68 | ||||
| -rw-r--r-- | src/game/client/components/menus_settings.cpp | 4 | ||||
| -rw-r--r-- | src/game/client/gameclient.cpp | 69 | ||||
| -rw-r--r-- | src/game/localization.cpp | 10 | ||||
| -rw-r--r-- | src/game/localization.hpp | 20 |
12 files changed, 962 insertions, 44 deletions
diff --git a/src/base/tl/algorithms.hpp b/src/base/tl/algorithms.hpp new file mode 100644 index 00000000..15e8e8a9 --- /dev/null +++ b/src/base/tl/algorithms.hpp @@ -0,0 +1,135 @@ +#ifndef TL_FILE_ALGORITHMS_HPP +#define TL_FILE_ALGORITHMS_HPP + +#include "range.hpp" + + +/* + insert 4 + v + 1 2 3 4 5 6 + +*/ + + +template<class R, class T> +R partition_linear(R range, T value) +{ + concept_empty::check(range); + concept_forwarditeration::check(range); + concept_sorted::check(range); + + for(; !range.empty(); range.pop_front()) + { + if(!(range.front() < value)) + return range; + } + return range; +} + + +template<class R, class T> +R partition_binary(R range, T value) +{ + concept_empty::check(range); + concept_index::check(range); + concept_size::check(range); + concept_slice::check(range); + concept_sorted::check(range); + + if(range.empty()) + return range; + if(range.back() < value) + return R(); + + while(range.size() > 1) + { + unsigned pivot = (range.size()-1)/2; + if(range.index(pivot) < value) + range = range.slice(pivot+1, range.size()-1); + else + range = range.slice(0, pivot+1); + } + return range; +} + +template<class R, class T> +R find_linear(R range, T value) +{ + concept_empty::check(range); + concept_forwarditeration::check(range); + for(; !range.empty(); range.pop_front()) + if(value < range.front()) + break; + return range; +} + +template<class R, class T> +R find_binary(R range, T value) +{ + range = partition_linear(range, value); + if(range.empty()) return range; + if(range.front() == value) return range; + return R(); +} + + +template<class R> +void sort_bubble(R range) +{ + concept_empty::check(range); + concept_forwarditeration::check(range); + concept_backwarditeration::check(range); + + // slow bubblesort :/ + for(; !range.empty(); range.pop_back()) + { + R section = range; + typename R::type *prev = §ion.front(); + section.pop_front(); + for(; !section.empty(); section.pop_front()) + { + typename R::type *cur = §ion.front(); + if(*cur < *prev) + swap(*cur, *prev); + prev = cur; + } + } +} + +/* +template<class R> +void sort_quick(R range) +{ + concept_index::check(range); +}*/ + + +template<class R> +void sort(R range) +{ + sort_bubble(range); +} + + +template<class R> +bool sort_verify(R range) +{ + concept_empty::check(range); + concept_forwarditeration::check(range); + + typename R::type *prev = &range.front(); + range.pop_front(); + for(; !range.empty(); range.pop_front()) + { + typename R::type *cur = &range.front(); + + if(*cur < *prev) + return false; + prev = cur; + } + + return true; +} + +#endif // TL_FILE_ALGORITHMS_HPP diff --git a/src/base/tl/allocator.hpp b/src/base/tl/allocator.hpp new file mode 100644 index 00000000..3baa1c19 --- /dev/null +++ b/src/base/tl/allocator.hpp @@ -0,0 +1,15 @@ +#ifndef TL_FILE_ALLOCATOR_HPP +#define TL_FILE_ALLOCATOR_HPP + +template <class T> +class allocator_default +{ +public: + static T *alloc() { return new T; } + static void free(T *p) { delete p; } + + static T *alloc_array(int size) { return new T [size]; } + static void free_array(T *p) { delete [] p; } +}; + +#endif // TL_FILE_ALLOCATOR_HPP diff --git a/src/base/tl/array.hpp b/src/base/tl/array.hpp new file mode 100644 index 00000000..7fa4ab1b --- /dev/null +++ b/src/base/tl/array.hpp @@ -0,0 +1,341 @@ +#ifndef TL_FILE_ARRAY_HPP +#define TL_FILE_ARRAY_HPP + +#include "range.hpp" +#include "allocator.hpp" + + +/* + Class: array + Normal dynamic array class + + Remarks: + - Grows 50% each time it needs to fit new items + - Use set_size() if you know how many elements + - Use optimize() to reduce the needed space. +*/ +template <class T, class ALLOCATOR = allocator_default<T> > +class array : private ALLOCATOR +{ + void init() + { + list = 0x0; + clear(); + } + +public: + typedef plain_range<T> range; + + /* + Function: array constructor + */ + array() + { + init(); + } + + /* + Function: array copy constructor + */ + array(const array &other) + { + init(); + set_size(other.size()); + for(int i = 0; i < size(); i++) + (*this)[i] = other[i]; + } + + + /* + Function: array destructor + */ + ~array() + { + ALLOCATOR::free_array(list); + list = 0x0; + } + + + /* + Function: delete_all + + Remarks: + - Invalidates ranges + */ + void delete_all() + { + for(int i = 0; i < size(); i++) + delete list[i]; + clear(); + } + + + /* + Function: clear + + Remarks: + - Invalidates ranges + */ + void clear() + { + ALLOCATOR::free_array(list); + list_size = 1; + list = ALLOCATOR::alloc_array(list_size); + num_elements = 0; + } + + /* + Function: size + */ + int size() const + { + return num_elements; + } + + /* + Function: remove_index_fast + + Remarks: + - Invalidates ranges + */ + void remove_index_fast(int index) + { + list[index] = list[num_elements-1]; + set_size(size()-1); + } + + /* + Function: remove_fast + + Remarks: + - Invalidates ranges + */ + void remove_fast(const T& item) + { + for(int i = 0; i < size(); i++) + if(list[i] == item) + { + remove_index_fast(i); + return; + } + } + + /* + Function: remove_index + + Remarks: + - Invalidates ranges + */ + void remove_index(int index) + { + for(int i = index+1; i < num_elements; i++) + list[i-1] = list[i]; + + set_size(size()-1); + } + + /* + Function: remove + + Remarks: + - Invalidates ranges + */ + bool remove(const T& item) + { + for(int i = 0; i < size(); i++) + if(list[i] == item) + { + remove_index(i); + return true; + } + return false; + } + + /* + Function: add + Adds an item to the array. + + Arguments: + item - Item to add. + + Remarks: + - Invalidates ranges + - See remarks about <array> how the array grows. + */ + int add(const T& item) + { + incsize(); + set_size(size()+1); + list[num_elements-1] = item; + return num_elements-1; + } + + /* + Function: insert + Inserts an item into the array at a specified location. + + Arguments: + item - Item to insert. + r - Range where to insert the item + + Remarks: + - Invalidates ranges + - See remarks about <array> how the array grows. + */ + int insert(const T& item, range r) + { + if(r.empty()) + return add(item); + + int index = (int)(&r.front()-list); + incsize(); + set_size(size()+1); + + for(int i = num_elements-1; i > index; i--) + list[i] = list[i-1]; + + list[index] = item; + + return num_elements-1; + } + + /* + Function: operator[] + */ + T& operator[] (int index) + { + return list[index]; + } + + /* + Function: const operator[] + */ + const T& operator[] (int index) const + { + return list[index]; + } + + /* + Function: base_ptr + */ + T *base_ptr() + { + return list; + } + + /* + Function: base_ptr + */ + const T *base_ptr() const + { + return list; + } + + /* + Function: set_size + Resizes the array to the specified size. + + Arguments: + new_size - The new size for the array. + */ + void set_size(int new_size) + { + alloc(new_size); + num_elements = new_size; + } + + /* + Function: hint_size + Allocates the number of elements wanted but + does not increase the list size. + + Arguments: + hint - Size to allocate. + + Remarks: + - If the hint is smaller then the number of elements, nothing will be done. + - Invalidates ranges + */ + void hint_size(int hint) + { + if(num_elements < hint) + alloc(hint); + } + + + /* + Function: optimize + Removes unnessasary data, returns how many bytes was earned. + + Remarks: + - Invalidates ranges + */ + int optimize() + { + int before = memusage(); + alloc(num_elements); + return before - memusage(); + } + + /* + Function: memusage + Returns how much memory this dynamic array is using + */ + int memusage() + { + return sizeof(array) + sizeof(T)*size; + } + + /* + Function: operator=(array) + + Remarks: + - Invalidates ranges + */ + array &operator = (const array &other) + { + set_size(other.size()); + for(int i = 0; i < size(); i++) + (*this)[i] = other[i]; + return *this; + } + + /* + Function: all + Returns a range that contains the whole array. + */ + range all() { return range(list, list+num_elements); } +protected: + + void incsize() + { + if(num_elements == list_size) + { + if(list_size < 2) + alloc(list_size+1); + else + alloc(list_size+list_size/2); + } + } + + void alloc(int new_len) + { + list_size = new_len; + T *new_list = ALLOCATOR::alloc_array(list_size); + + int end = num_elements < list_size ? num_elements : list_size; + for(int i = 0; i < end; i++) + new_list[i] = list[i]; + + ALLOCATOR::free_array(list); + + num_elements = num_elements < list_size ? num_elements : list_size; + list = new_list; + } + + T *list; + int list_size; + int num_elements; +}; + +#endif // TL_FILE_ARRAY_HPP diff --git a/src/base/tl/base.hpp b/src/base/tl/base.hpp new file mode 100644 index 00000000..238cfaea --- /dev/null +++ b/src/base/tl/base.hpp @@ -0,0 +1,15 @@ + +#include <base/system.h> + +inline void assert(bool statement) +{ + dbg_assert(statement, "assert!"); +} + +template<class T> +inline void swap(T &a, T &b) +{ + T c = b; + b = a; + a = c; +} diff --git a/src/base/tl/range.hpp b/src/base/tl/range.hpp new file mode 100644 index 00000000..b55f235e --- /dev/null +++ b/src/base/tl/range.hpp @@ -0,0 +1,230 @@ +#ifndef __RANGE_H +#define __RANGE_H + +/* + Group: Range concepts +*/ + +/* + Concept: concept_empty + + template<class T> + struct range + { + bool empty() const; + }; +*/ +struct concept_empty +{ + template<typename T> static void check(T &t) { if(0) t.empty(); }; +}; + +/* + Concept: concept_index + + template<class T> + struct range + { + T &index(size_t); + }; +*/ +struct concept_index +{ + template<typename T> static void check(T &t) { if(0) t.index(0); }; +}; + +/* + Concept: concept_size + + template<class T> + struct range + { + size_t size(); + }; +*/ +struct concept_size +{ + template<typename T> static void check(T &t) { if(0) t.size(); }; +}; + +/* + Concept: concept_slice + + template<class T> + struct range + { + range slice(size_t start, size_t count); + }; +*/ +struct concept_slice +{ + template<typename T> static void check(T &t) { if(0) t.slice(0, 0); }; +}; + +/* + Concept: concept_sorted + + template<class T> + struct range + { + void sorted(); + }; +*/ +struct concept_sorted +{ + template<typename T> static void check(T &t) { if(0) t.sorted(); }; +}; + +/* + Concept: concept_forwarditeration + Checks for the front and pop_front methods + + template<class T> + struct range + { + void pop_front(); + T &front() const; + }; +*/ +struct concept_forwarditeration +{ + template<typename T> static void check(T &t) { if(0) { t.front(); t.pop_front(); } }; +}; + +/* + Concept: concept_backwarditeration + Checks for the back and pop_back methods + + template<class T> + struct range + { + void pop_back(); + T &back() const; + }; +*/ +struct concept_backwarditeration +{ + template<typename T> static void check(T &t) { if(0) { t.back(); t.pop_back(); } }; +}; + + +/* + Group: Range classes +*/ + + +/* + Class: plain_range + + Concepts: + <concept_empty> + <concept_index> + <concept_slice> + <concept_forwardinteration> + <concept_backwardinteration> +*/ +template<class T> +class plain_range +{ +public: + typedef T type; + plain_range() + { + begin = 0x0; + end = 0x0; + } + + plain_range(const plain_range &r) + { + *this = r; + } + + plain_range(T *b, T *e) + { + begin = b; + end = e; + } + + bool empty() const { return begin >= end; } + void pop_front() { assert(!empty()); begin++; } + void pop_back() { assert(!empty()); end--; } + T& front() { assert(!empty()); return *begin; } + T& back() { assert(!empty()); return *(end-1); } + T& index(unsigned i) { assert(i >= 0 && i < (unsigned)(end-begin)); return begin[i]; } + unsigned size() const { return (unsigned)(end-begin); } + plain_range slice(unsigned startindex, unsigned endindex) + { + return plain_range(begin+startindex, begin+endindex); + } + +protected: + T *begin; + T *end; +}; + +/* + Class: plain_range_sorted + + Concepts: + Same as <plain_range> but with these additions: + <concept_sorted> +*/ +template<class T> +class plain_range_sorted : public plain_range<T> +{ + typedef plain_range<T> parent; +public: + /* sorted concept */ + void sorted() const { } + + plain_range_sorted() + {} + + plain_range_sorted(const plain_range_sorted &r) + { + *this = r; + } + + plain_range_sorted(T *b, T *e) + : parent(b, e) + {} + + plain_range_sorted slice(unsigned start, unsigned count) + { + return plain_range_sorted(parent::begin+start, parent::begin+start+count); + } +}; + +template<class R> +class reverse_range +{ +private: + reverse_range() {} +public: + typedef typename R::type type; + + reverse_range(R r) + { + range = r; + } + + reverse_range(const reverse_range &other) { range = other.range; } + + + bool empty() const { return range.empty(); } + void pop_front() { range.pop_back(); } + void pop_back() { range.pop_front(); } + type& front() { return range.back(); } + type& back() { return range.front(); } + + R range; +}; + +template<class R> reverse_range<R> reverse(R range) { + return reverse_range<R>(range); +} +template<class R> R reverse(reverse_range<R> range) { + return range.range; +} + +#endif diff --git a/src/base/tl/sorted_array.hpp b/src/base/tl/sorted_array.hpp new file mode 100644 index 00000000..bb09aba9 --- /dev/null +++ b/src/base/tl/sorted_array.hpp @@ -0,0 +1,31 @@ +#ifndef TL_FILE_SORTED_ARRAY_HPP +#define TL_FILE_SORTED_ARRAY_HPP + +#include "algorithms.hpp" +#include "array.hpp" + +template <class T, class ALLOCATOR = allocator_default<T> > +class sorted_array : public array<T, ALLOCATOR> +{ + typedef array<T, ALLOCATOR> parent; + + // insert and size is not allowed + int insert(const T& item, typename parent::range r) { dbg_break(); return 0; } + int set_size(int new_size) { dbg_break(); return 0; } + +public: + typedef plain_range_sorted<T> range; + + int add(const T& item) + { + return parent::insert(item, partition_binary(all(), item)); + } + + /* + Function: all + Returns a sorted range that contains the whole array. + */ + range all() { return range(parent::list, parent::list+parent::num_elements); } +}; + +#endif // TL_FILE_SORTED_ARRAY_HPP diff --git a/src/base/tl/string.hpp b/src/base/tl/string.hpp new file mode 100644 index 00000000..2b164091 --- /dev/null +++ b/src/base/tl/string.hpp @@ -0,0 +1,68 @@ +#ifndef TL_FILE_STRING_HPP +#define TL_FILE_STRING_HPP + +#include "base.hpp" +#include "allocator.hpp" + +template<class ALLOCATOR > +class string_base : private ALLOCATOR +{ + char *str; + int length; + + void reset() + { + str = 0; length = 0; + } + + void free() + { + ALLOCATOR::free_array(str); + reset(); + } + + void copy(const char *other_str, int other_length) + { + length = other_length; + str = ALLOCATOR::alloc_array(length+1); + mem_copy(str, other_str, length+1); + } + + void copy(const string_base &other) + { + if(!other.str) + return; + copy(other.str, other.length); + } + +public: + string_base() { reset(); } + string_base(const char *other_str) { copy(other_str, str_length(other_str)); } + string_base(const string_base &other) { reset(); copy(other); } + ~string_base() { free(); } + + string_base &operator = (const char *other) + { + free(); + if(other) + copy(other, str_length(other)); + return *this; + } + + string_base &operator = (const string_base &other) + { + free(); + copy(other); + return *this; + } + + bool operator < (const char *other_str) const { return str_comp(str, other_str) < 0; } + operator const char *() const { return str; } + + const char *cstr() const { return str; } +}; + +/* normal allocated string */ +typedef string_base<allocator_default<char> > string; + +#endif // TL_FILE_STRING_HPP diff --git a/src/game/client/components/menus_browser.cpp b/src/game/client/components/menus_browser.cpp index 3d58af93..d86a727c 100644 --- a/src/game/client/components/menus_browser.cpp +++ b/src/game/client/components/menus_browser.cpp @@ -58,12 +58,12 @@ void MENUS::render_serverbrowser_serverlist(RECT view) {COL_FLAG_LOCK, -1, " ", -1, 14.0f, 0, {0}, {0}}, {COL_FLAG_PURE, -1, " ", -1, 14.0f, 0, {0}, {0}}, {COL_FLAG_FAV, -1, " ", -1, 14.0f, 0, {0}, {0}}, - {COL_NAME, BROWSESORT_NAME, "Name", 0, 300.0f, 0, {0}, {0}}, - {COL_GAMETYPE, BROWSESORT_GAMETYPE, "Type", 1, 50.0f, 0, {0}, {0}}, - {COL_MAP, BROWSESORT_MAP, "Map", 1, 100.0f, 0, {0}, {0}}, - {COL_PLAYERS, BROWSESORT_NUMPLAYERS, "Players", 1, 60.0f, 0, {0}, {0}}, + {COL_NAME, BROWSESORT_NAME, localize("Name"), 0, 300.0f, 0, {0}, {0}}, + {COL_GAMETYPE, BROWSESORT_GAMETYPE, localize("Type"), 1, 50.0f, 0, {0}, {0}}, + {COL_MAP, BROWSESORT_MAP, localize("Map"), 1, 100.0f, 0, {0}, {0}}, + {COL_PLAYERS, BROWSESORT_NUMPLAYERS, localize("Players"), 1, 60.0f, 0, {0}, {0}}, {-1, -1, " ", 1, 10.0f, 0, {0}, {0}}, - {COL_PING, BROWSESORT_PING, "Ping", 1, 40.0f, FIXED, {0}, {0}}, + {COL_PING, BROWSESORT_PING, localize("Ping"), 1, 40.0f, FIXED, {0}, {0}}, }; int num_cols = sizeof(cols)/sizeof(column); @@ -128,11 +128,11 @@ void MENUS::render_serverbrowser_serverlist(RECT view) msgbox.y += view.h/3; if(active_page == PAGE_INTERNET && client_serverbrowse_refreshingmasters()) - ui_do_label(&msgbox, "Refreshing master servers", 16.0f, 0); + ui_do_label(&msgbox, localize("Refreshing master servers"), 16.0f, 0); else if(!client_serverbrowse_num()) - ui_do_label(&msgbox, "No servers found", 16.0f, 0); + ui_do_label(&msgbox, localize("No servers found"), 16.0f, 0); else if(client_serverbrowse_num() && !num_servers) - ui_do_label(&msgbox, "No servers match your filter criteria", 16.0f, 0); + ui_do_label(&msgbox, localize("No servers match your filter criteria"), 16.0f, 0); } int num = (int)(view.h/cols[0].rect.h); @@ -330,13 +330,13 @@ void MENUS::render_serverbrowser_serverlist(RECT view) // render quick search RECT quicksearch; ui_vsplit_l(&status, 250.0f, &quicksearch, &status); - ui_do_label(&quicksearch, "Quick search: ", 14.0f, -1); - ui_vsplit_l(&quicksearch, gfx_text_width(0, 14.0f, "Quick search: ", -1), 0, &quicksearch); + ui_do_label(&quicksearch, localize("Quick search:"), 14.0f, -1); + ui_vsplit_l(&quicksearch, gfx_text_width(0, 14.0f, localize("Quick search:"), -1), 0, &quicksearch); ui_do_edit_box(&config.b_filter_string, &quicksearch, config.b_filter_string, sizeof(config.b_filter_string), 14.0f); // render status char buf[128]; - str_format(buf, sizeof(buf), "%d of %d servers, %d players", client_serverbrowse_sorted_num(), client_serverbrowse_num(), num_players); + str_format(buf, sizeof(buf), localize("%d of %d servers, %d players"), client_serverbrowse_sorted_num(), client_serverbrowse_num(), num_players); ui_vsplit_r(&status, gfx_text_width(0, 14.0f, buf, -1), 0, &status); ui_do_label(&status, buf, 14.0f, -1); } @@ -353,32 +353,32 @@ void MENUS::render_serverbrowser_filters(RECT view) // render filters ui_hsplit_t(&view, 20.0f, &button, &view); - if (ui_do_button(&config.b_filter_empty, "Has people playing", config.b_filter_empty, &button, ui_draw_checkbox, 0)) + if (ui_do_button(&config.b_filter_empty, localize("Has people playing"), config.b_filter_empty, &button, ui_draw_checkbox, 0)) config.b_filter_empty ^= 1; ui_hsplit_t(&view, 20.0f, &button, &view); - if (ui_do_button(&config.b_filter_full, "Server not full", config.b_filter_full, &button, ui_draw_checkbox, 0)) + if (ui_do_button(&config.b_filter_full, localize("Server not full"), config.b_filter_full, &button, ui_draw_checkbox, 0)) config.b_filter_full ^= 1; ui_hsplit_t(&view, 20.0f, &button, &view); - if (ui_do_button(&config.b_filter_pw, "No password", config.b_filter_pw, &button, ui_draw_checkbox, 0)) + if (ui_do_button(&config.b_filter_pw, localize("No password"), config.b_filter_pw, &button, ui_draw_checkbox, 0)) config.b_filter_pw ^= 1; ui_hsplit_t(&view, 20.0f, &button, &view); - if (ui_do_button((char *)&config.b_filter_compatversion, "Compatible Version", config.b_filter_compatversion, &button, ui_draw_checkbox, 0)) + if (ui_do_button((char *)&config.b_filter_compatversion, localize("Compatible version"), config.b_filter_compatversion, &button, ui_draw_checkbox, 0)) config.b_filter_compatversion ^= 1; ui_hsplit_t(&view, 20.0f, &button, &view); - if (ui_do_button((char *)&config.b_filter_pure, "Standard gametype", config.b_filter_pure, &button, ui_draw_checkbox, 0)) + if (ui_do_button((char *)&config.b_filter_pure, localize("Standard gametype"), config.b_filter_pure, &button, ui_draw_checkbox, 0)) config.b_filter_pure ^= 1; ui_hsplit_t(&view, 20.0f, &button, &view); /*ui_vsplit_l(&button, 20.0f, 0, &button);*/ - if (ui_do_button((char *)&config.b_filter_pure_map, "Standard map", config.b_filter_pure_map, &button, ui_draw_checkbox, 0)) + if (ui_do_button((char *)&config.b_filter_pure_map, localize("Standard map"), config.b_filter_pure_map, &button, ui_draw_checkbox, 0)) config.b_filter_pure_map ^= 1; ui_hsplit_t(&view, 20.0f, &button, &view); - ui_do_label(&button, "Game types: ", 14.0f, -1); + ui_do_label(&button, localize("Game types:"), 14.0f, -1); ui_vsplit_l(&button, 95.0f, 0, &button); ui_margin(&button, 1.0f, &button); ui_do_edit_box(&config.b_filter_gametype, &button, config.b_filter_gametype, sizeof(config.b_filter_gametype), 14.0f); @@ -394,12 +394,12 @@ void MENUS::render_serverbrowser_filters(RECT view) ui_do_edit_box(&config.b_filter_ping, &editbox, buf, sizeof(buf), 14.0f); config.b_filter_ping = atoi(buf); - ui_do_label(&button, "Maximum ping", 14.0f, -1); + ui_do_label(&button, localize("Maximum ping"), 14.0f, -1); } ui_hsplit_b(&view, button_height, &view, &button); static int clear_button = 0; - if(ui_do_button(&clear_button, "Reset Filter", 0, &button, ui_draw_menu_button, 0)) + if(ui_do_button(&clear_button, localize("Reset filter"), 0, &button, ui_draw_menu_button, 0)) { config.b_filter_full = 0; config.b_filter_empty = 0; @@ -431,7 +431,7 @@ void MENUS::render_serverbrowser_serverdetail(RECT view) ui_draw_rect(&server_header, vec4(1,1,1,0.25f), CORNER_T, 4.0f); ui_draw_rect(&server_details, vec4(0,0,0,0.15f), CORNER_B, 4.0f); ui_vsplit_l(&server_header, 8.0f, 0x0, &server_header); - ui_do_label(&server_header, "Server Details: ", font_size+2.0f, -1); + ui_do_label(&server_header, localize("Server details:"), font_size+2.0f, -1); ui_vsplit_l(&server_details, 5.0f, 0x0, &server_details); @@ -440,7 +440,11 @@ void MENUS::render_serverbrowser_serverdetail(RECT view) if (selected_server) { RECT row; - static const char *labels[] = { "Version:", "Game Type:", "Progression:", "Ping:" }; + static LOC_CONSTSTRING labels[] = { + localize("Version:"), + localize("Game Type:"), + localize("Progression:"), + localize("Ping:")}; RECT left_column; RECT right_column; @@ -450,7 +454,7 @@ void MENUS::render_serverbrowser_serverdetail(RECT view) RECT button; ui_hsplit_b(&server_details, 20.0f, &server_details, &button); static int add_fav_button = 0; - if (ui_do_button(&add_fav_button, "Favorite", selected_server->favorite, &button, ui_draw_checkbox, 0)) + if (ui_do_button(&add_fav_button, localize("Favorite"), selected_server->favorite, &button, ui_draw_checkbox, 0)) { if(selected_server->favorite) client_serverbrowse_removefavorite(selected_server->netaddr); @@ -478,7 +482,7 @@ void MENUS::render_serverbrowser_serverdetail(RECT view) char temp[16]; if(selected_server->progression < 0) - str_format(temp, sizeof(temp), "N/A"); + str_format(temp, sizeof(temp), localize("N/A")); else str_format(temp, sizeof(temp), "%d%%", selected_server->progression); ui_hsplit_t(&right_column, 15.0f, &row, &right_column); @@ -497,7 +501,7 @@ void MENUS::render_serverbrowser_serverdetail(RECT view) ui_draw_rect(&server_header, vec4(1,1,1,0.25f), CORNER_T, 4.0f); ui_draw_rect(&server_scoreboard, vec4(0,0,0,0.15f), CORNER_B, 4.0f); ui_vsplit_l(&server_header, 8.0f, 0x0, &server_header); - ui_do_label(&server_header, "Scoreboard: ", font_size+2.0f, -1); + ui_do_label(&server_header, localize("Scoreboard:"), font_size+2.0f, -1); ui_vsplit_l(&server_scoreboard, 5.0f, 0x0, &server_scoreboard); @@ -588,11 +592,11 @@ void MENUS::render_serverbrowser(RECT main_view) ui_vsplit_l(&tabbutton1, 5.0f, 0, &tabbutton1); static int filters_tab = 0; - if (ui_do_button(&filters_tab, "Filter", toolbox_page==0, &tabbutton0, ui_draw_menu_tab_button, 0)) + if (ui_do_button(&filters_tab, localize("Filter"), toolbox_page==0, &tabbutton0, ui_draw_menu_tab_button, 0)) toolbox_page = 0; static int info_tab = 0; - if (ui_do_button(&info_tab, "Info", toolbox_page==1, &tabbutton1, ui_draw_menu_tab_button, 0)) + if (ui_do_button(&info_tab, localize("Info"), toolbox_page==1, &tabbutton1, ui_draw_menu_tab_button, 0)) toolbox_page = 1; } @@ -613,7 +617,7 @@ void MENUS::render_serverbrowser(RECT main_view) ui_vsplit_r(&status_toolbar, 100.0f, &status_toolbar, &button); ui_vmargin(&button, 2.0f, &button); static int refresh_button = 0; - if(ui_do_button(&refresh_button, "Refresh", 0, &button, ui_draw_menu_button, 0)) + if(ui_do_button(&refresh_button, localize("Refresh"), 0, &button, ui_draw_menu_button, 0)) { if(config.ui_page == PAGE_INTERNET) client_serverbrowse_refresh(BROWSETYPE_INTERNET); @@ -625,9 +629,9 @@ void MENUS::render_serverbrowser(RECT main_view) char buf[512]; if(strcmp(client_latestversion(), "0") != 0) - str_format(buf, sizeof(buf), "Teeworlds %s is out! Download it at www.teeworlds.com!\nCurrent version: %s", client_latestversion(), GAME_VERSION); + str_format(buf, sizeof(buf), localize("Teeworlds %s is out! Download it at www.teeworlds.com!"), client_latestversion()); else - str_format(buf, sizeof(buf), "Current version: %s", GAME_VERSION); + str_format(buf, sizeof(buf), localize("Current version: %s"), GAME_VERSION); ui_do_label(&status_toolbar, buf, 14.0f, -1); } @@ -643,7 +647,7 @@ void MENUS::render_serverbrowser(RECT main_view) ui_vmargin(&button, 2.0f, &button); //ui_vmargin(&button, 2.0f, &button); static int join_button = 0; - if(ui_do_button(&join_button, "Connect", 0, &button, ui_draw_menu_button, 0) || enter_pressed) + if(ui_do_button(&join_button, localize("Connect"), 0, &button, ui_draw_menu_button, 0) || enter_pressed) { client_connect(config.ui_server_address); enter_pressed = false; @@ -653,6 +657,6 @@ void MENUS::render_serverbrowser(RECT main_view) ui_hsplit_b(&button_box, 20.0f, &button_box, &button); ui_do_edit_box(&config.ui_server_address, &button, config.ui_server_address, sizeof(config.ui_server_address), 14.0f); ui_hsplit_b(&button_box, 20.0f, &button_box, &button); - ui_do_label(&button, "Host address:", 14.0f, -1); + ui_do_label(&button, localize("Host address:"), 14.0f, -1); } } diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index 58678b80..60d8d7fc 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -254,7 +254,7 @@ typedef struct int keyid; } KEYINFO; -KEYINFO keys[] = +static KEYINFO keys[] = { // we need to do localize so the scripts can pickup the string { localize("Move Left:"), "+left", 0}, @@ -286,7 +286,7 @@ void MENUS::ui_do_getbuttons(int start, int stop, RECT view) { for (int i = start; i < stop; i++) { - KEYINFO key = keys[i]; + KEYINFO &key = keys[i]; RECT button, label; ui_hsplit_t(&view, 20.0f, &button, &view); ui_vsplit_l(&button, 130.0f, &label, &button); diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index 834aa29b..752af7cd 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -98,8 +98,77 @@ static void con_serverdummy(void *result, void *user_data) dbg_msg("client", "this command is not available on the client"); } +#include <base/tl/sorted_array.hpp> + void GAMECLIENT::on_console_init() { + if(0) + { + int ints[4] = {0,1,2,3}; + for(int s = 1; s < 4; s++) + { + //s = 2; + plain_range_sorted<int> test_sorted_range(ints, ints+s); + plain_range_sorted<int> res1, res2; + + //res2 = partition_binary(test_sorted_range, 1); + + //for(int i = 0; i < 4; i++) + // dbg_assert(partition_linear(test_sorted_range, i).front() == i, "partition linear failed"); + + + dbg_msg("", "size %d", s); + + for(int i = -1; i < 5; i++) + { + res1 = partition_linear(test_sorted_range, i); + dbg_msg("", "\tlin %d == %d", i, res1.empty()?-1:res1.front()); + + res2 = partition_binary(test_sorted_range, i); + dbg_msg("", "\tbin %d == %d", i, res2.empty()?-1:res2.front()); + //dbg_assert(partition_binary(plain_range_sorted<int>(ints, ints+6), i).front() == i+1, "partition binary failed"); + } + } //*/ + + sorted_array<int> test; + test.add(4); + test.add(1); + + for(int i = 0; i < 100; i++) + { + int this_add = rand(); + test.add(this_add); + if(!sort_verify(test.all())) + { + dbg_msg("", "error inserting %d", this_add); + for(sorted_array<int>::range r = test.all(); !r.empty(); r.pop_front()) + dbg_msg("", "%d", r.front()); + exit(-1); + } + }/* + + + test.add(1); + test.add(4); + test.add(3); + test.add(4); + test.add(3); + test.add(2); + //test.insert(1, 1); + for(sorted_array<int>::range r = test.all(); !r.empty(); r.pop_front()) + dbg_msg("", "%d", r.front()); + */ + + sort_verify(test.all()); + /* + for(int i = 0; i < 15; i++) + { + dbg_msg("", "found %d == %d", i, !find_binary(test.all(), i).empty()); + }*/ + + exit(-1); + } + // setup pointers binds = &::binds; console = &::console; diff --git a/src/game/localization.cpp b/src/game/localization.cpp index 58ec539c..110a0f5e 100644 --- a/src/game/localization.cpp +++ b/src/game/localization.cpp @@ -1,5 +1,6 @@ #include "localization.hpp" +#include <base/tl/algorithms.hpp> extern "C" { #include <engine/e_linereader.h> @@ -16,7 +17,6 @@ static unsigned str_hash(const char *str) const char *localize(const char *str) { const char *new_str = localization.find_string(str_hash(str)); - //dbg_msg("", "no localization for '%s'", str); return new_str ? new_str : str; } @@ -86,15 +86,19 @@ bool LOCALIZATIONDATABASE::load(const char *filename) replacement += 3; localization.add_string(line, replacement); } - + current_version++; return true; } const char *LOCALIZATIONDATABASE::find_string(unsigned hash) { - array<STRING>::range r = ::find(strings.all(), hash); + STRING s; + s.hash = hash; + sorted_array<STRING>::range r = ::find_binary(strings.all(), s); if(r.empty()) return 0; return r.front().replacement; } + +LOCALIZATIONDATABASE localization; diff --git a/src/game/localization.hpp b/src/game/localization.hpp index de6849d4..3f79d687 100644 --- a/src/game/localization.hpp +++ b/src/game/localization.hpp @@ -1,4 +1,5 @@ -#include <base/tl/array.hpp> +#include <base/tl/string.hpp> +#include <base/tl/sorted_array.hpp> class LOCALIZATIONDATABASE { @@ -6,13 +7,16 @@ class LOCALIZATIONDATABASE { public: unsigned hash; - string replacement; - - bool operator ==(unsigned h) const { return hash == h; } + // TODO: do this as an const char * and put everything on a incremental heap + string replacement; + + bool operator <(const STRING &other) const { return hash < other.hash; } + bool operator <=(const STRING &other) const { return hash <= other.hash; } + bool operator ==(const STRING &other) const { return hash == other.hash; } }; - array<STRING> strings; + sorted_array<STRING> strings; int current_version; public: @@ -26,8 +30,7 @@ public: const char *find_string(unsigned hash); }; -static LOCALIZATIONDATABASE localization; - +extern LOCALIZATIONDATABASE localization; class LOC_CONSTSTRING { @@ -46,3 +49,6 @@ public: return current_str; } }; + + +extern const char *localize(const char *str); |