Author Topic: Quasar4x - An early look at an Aurora4x clone in the works  (Read 72479 times)

0 Members and 1 Guest are viewing this topic.

Offline Droll

  • Captain
  • **********
  • D
  • Posts: 404
  • Thanked: 80 times
Re: Quasar4x - An early look at an Aurora4x clone in the works
« Reply #330 on: April 17, 2020, 11:15:17 AM »
Its going to be interesting to see people start modding in C# features into this. From what I understand the original aim of quasar4x is to modernize VB6, which is cool - but I wanna see C# aurora with this snazzy new UI.
 

Offline Agm-114

  • Pulsar 4x Dev
  • Registered
  • Chief Petty Officer
  • ***
  • Posts: 31
  • Thanked: 11 times
  • Discord Username: AGM-114#7218
Re: Quasar4x - An early look at an Aurora4x clone in the works
« Reply #331 on: April 17, 2020, 02:47:20 PM »
Btw I think this topic should be pinned XD
 

Offline Kyle (OP)

  • Moderator
  • Lt. Commander
  • *****
  • K
  • Posts: 242
  • Thanked: 540 times
  • Quasar4x dev
Re: Quasar4x - An early look at an Aurora4x clone in the works
« Reply #332 on: April 18, 2020, 01:21:54 AM »
Wouldn't it make sense to change sub pulse length into a dropdown menu to right of increment time or somewhere like that.

Go for it, if that's what you want. :)  That's the glorious thing about supporting mods.  The modders can deal with all the suggestions! :)
 

Offline Kyle (OP)

  • Moderator
  • Lt. Commander
  • *****
  • K
  • Posts: 242
  • Thanked: 540 times
  • Quasar4x dev
Re: Quasar4x - An early look at an Aurora4x clone in the works
« Reply #333 on: April 18, 2020, 01:33:21 AM »
Progress update 2020-04-18:

Boring but important update.  This fixes a crash that was occurring whenever speed was calculated for a fleet containing a ship or shipyard linked by STS tractor.

I also added a LOT of new functions to the API!  This is pretty much a dump of all the functions I have in my common code.  Even though they look useful, many of them may never be used because they are already automatically called by higher level functions.  But these are important if a modder ever comes along and wants to do something that isn't already possible via the UI and isn't done automatically during end-of-turn.  Rather than executing SQL against the database directly, that modder should use these functions instead, because almost everything you do has lots of side effects that you need to account for.

Here's the list of functions I added to the API:
Off-Topic: show
abandon_ship(ship_id)
add_a_trait(commander_id)
add_colony(body_id, race_id = NONE, species_id = NONE)
add_commander_history(commander_id, history_String)
add_debug_dot(dot_color, dot_label, x, y)
add_default_fleet_created_history(fleet_id)
add_new_commander(population_id, commander_type = null)
add_parasites_to_list(ship_id_list)
add_race_tech(tech_id, race_id, pop_id = NONE, enable_scientist_logging = false)
add_route(fleet_id, race_id, from_system_id, to_system_id, current_initiative, jump_gates_optional = false, use_lagrange_points = true)
add_ship_history(ship_id, history_text)
add_spy_points(spy_points, attacker_race_id, defender_race_id, team_id = NONE)
add_tech_points(pop_id, race_id, rp_gained, tech_id)
add_wealth_data(use_id, amount, race_id, update_race_wealth_too = false)
age_str(career_start_seconds)
allocate_commander_xp(commander_id, bonus_type, amount)
apply_bonuses_to_load_time(load_time_minutes, fleet_id)
apply_damage(ship_id, apply_damage_amount, step_height)
auto_assign_commanders(race_id)
backup_db()
bombard(pop_id, damage, attacker_race_id, is_collateral, radiation_damage = 0, dust_damage = -1)
bombardment_results(is_collateral = false)
breathable_atmosphere(systembody_id, race_id)
calc_colony_cost(systembody_id, species_id, race_id)
calc_current_thermal(ship_id)
calc_fleet_max_speed(fleet_id)
calc_intercept_point(ax, ay, vx, vy, bx, by, s, q, z)
calc_pop_colony_cost(pop_id)
calc_speed(size, engine_power, dust_density, armor_thickness)
calc_surface_temp(base_temp, gh_factor, albedo, dust_level)
check_espionage(spying_race_id, target_race_id, team_id = NONE)
clean_float_string(string)
clear_debug_graphics()
clear_galmap_cache()
column_to_array(rows, col_name)
column_to_distinct_list(rows, col_name)
comma_format(number)
complete_jp_survey(system_id, race_id)
copy_class_to_another_race(source_class_id, other_race_id)
create_fleet(pop_id, task_force_id = null, new_fleet_name = null, append_body_name = false)
create_missiles(pop_id, missile_id, amount)
create_race_sys_survey(race_id, system_id, game_id)
create_sector(pop)
create_ship_components(pop_id, component_id, amount)
create_shipping_line(race_id)
create_wreck(race_id, system_id, ship_class_id, xcor, ycor)
damage_gu_or_pop(pop_id, damage, attacker_race_id, target_type, hits = 1, rad_damage = 0)
damage_political_modifier(damage, attacker_race_id, defender_race_id)
damage_random_shipyard(pop_id, damage)
damage_shipyard(shipyard_id, damage)
date_str(game_id, seconds, show_hhmm = true, show_ss = false)
days_hours_minutes_long(minutes)
deduct_start_build_points(race_id, ship_class_id)
delete_divisions(div_ids)
delete_excess_gf_training(pop_id)
delete_fleet_if_empty(fleet_id)
delete_fleets(id_list)
delete_salvo(salvo_id)
delete_ship(ship_id)
delete_ship_contact(ship_id)
deploy_escorts(parent_fleet_id)
destroy_ship(ship_id)
detach_ship(ship_id, parent_fleet_id, is_escort = false, new_task_force_id = NONE)
duration_to_string(hours)
ensure_all_races_have_capital()
finish_commander_transfer(old_race_id, new_race_id)
fix_seniorities(race_id)
fix_ship_links(race_id)
fleet_is_in_nebula(fleet_id)
generate_class_design_summary(ship_class_id, range_band_10k = 1, target_speed_1k = 1)
generate_commander_name(race_id)
generate_design_summary(ship_id, target_speed = 1, range_band = 1)
generate_random_company_name(race_id, research_category_id)
get_activity_time(fleet, fleet_move)
get_actual_ppv(pop_id)
get_alien_class_id(ship_id, view_race_id)
get_annual_fincen_wealth(race_id, pop_id = null)
get_annual_pop_wealth(race_id, pop_id = null):
get_annual_wealth(race_id, pop_id = null)
get_avg_fleet_training(fleet_id)
get_best_tech_info(tech_type_id, race_id)
get_capital_pop_id(race_id)
get_chance_to_penetrate_missile_armor(armor, damage)
get_class_cost(shipclass_id)
get_class_loadout(ship_id)
get_class_name(shipclass_id)
get_comm_status(spy_race_id, race_id)
get_comma()
get_commander(commander_id)
get_commander_assignment_string(commander)
get_commander_name_and_rank(commander_id)
get_commander_of_ship(ship_id)
get_commander_population_id(commander)
get_contact_name(system_id, race_id, target_type, target_id, name_cache, cache_one_system_and_race_only = true)
get_contacts(system_id, race_id, include_lost = false, active_only = false)
get_crew_cth_mod(ship)
get_current_loadout(ship_id)
get_damage_step_height(component_type)
get_default_species_id(race_id)
get_default_task_force_id(pop_id)
get_effective_size(ship_class_id)
get_eligible_additional_classes(ship_class)
get_factory_info(pop_id, pop_data)
get_fc_assignment(ship_id, fc_component_id, fc_num, name_cache = {}): # cache is specific to system and race of detector
get_fc_max_range(fire_control_value)
get_fire_control_cth(fc_component_value, target_distance)
get_first_fleet_move(fleet_id)
get_fleet(fleet_id)
get_fleet_id(ship_id)
get_game_time()
get_geo_points(body)
get_govt_bonus(field_name, pop_id)
get_grade_points(ship)
get_homeworld_pop_id(commander_id)
get_jump_point_name(race_id, warp_point_id)
get_jump_points(race_id, system_id)
get_lagrange_points(system_id)
get_load_time_minutes(ship_class_id, cargo_handling_multiplier = null)
get_lowest_unresearched_tech(race_id, tech_id)
get_max_number_of_systems(game_id)
get_missile(missile_id)
get_missile_fc_max_range(max_sensor_range, resolution, target_size)
get_non_fc_get_weapon_max_range(weapon)
get_nth(number)
get_num_berths(planned_deployment, crew_quarters_hs)
get_or_create_oh_fleet(pop_id)
get_or_create_pdc_fleet(pop_id)
get_orbital_pop_annual_growth_rate(population, orbital_capacity)
get_police_strength(pop_id)
get_pop(pop_id, refresh_sigs = false)
get_pop_admin_rating_required(pop_id)
get_pop_annual_growth_rate(population, col_cost, orbital_capacity)
get_pop_data(pop_id, col_cost)
get_pop_surrender_data(pop_id)
get_pop_surrender_resistance(data)
get_pop_surrender_strength(data)
get_population_distribution(col_cost, population, orbital_capacity = 0)
get_pos(input)
get_promotion_score(commander_id)
get_race_body_name(pop_id)
get_rank_name(commander)
get_refit_cost(from_class_id, to_class_id)
get_refit_mineral_breakdown(from_class_id, to_class_id)
get_requested_ppv(pop)
get_required_occupation_strength(pop)
get_second_stage_text(missile)
get_ship(ship_id)
get_ship_class(ship_class_id)
get_ship_delay_mod(ship, task_force_delay_mod = null):
get_species_surrender_data(species_id)
get_system_map_race_id()
get_systembody(systembody_id)
get_target_data(system_id, target_type, target_id)
get_task_force_delay_modifier(fleet_id)
get_time_and_distance(fleet, fleet_move, include_activity = false)
get_time_and_distance_str(fleet, fleet_move)
get_tracking_speed_penalty(tracking_speed, target_speed)
get_weapon_damage(weapon, fire_control, range_km)
get_weapon_max_range(weapon, fire_control)
get_weapon_max_tracking_speed(weapon, fire_control)
grant_team_xp(team_id)
hash_column_to_array(hashed_fetch, col_name)
hash_column_to_list(hashed_fetch, col_name)
hostiles_in_system(fleet_id)
hydro_id_to_string(hydro_id)
incorporate_sub_fleets(fleet_id)
industry_active(industry_type, pop_id)
insert_lagrange_move_if_possible(system_id, fleet_id, dest_xcor, dest_ycor)
is_fleet_jump_capable(fleet_id)
is_sm_race(race_id)
kill_commander(commander, message = null)
launch_missiles(fleet_id, ship_id = 0)
load_into_strikegroup(fighter_id)
make_dac(class_id, return_a_string)
make_hash(array_of_dict, key_field_name)
make_turret_name(barrel_count, beam_name)
mark_target_lost(missile_salvo_id)
mass_to_string(n)
max_precision(number, precision)
mine_system_body(amount_mined, orig_amount, body_class, mineral_deposit_id)
orbital_distance_to_string(orbital_distance, body_class = 0, in_au_units = false)
pick_alien_class_name(detect_race_id, alien_race_id, theme_id, class_id)
pick_alien_theme_id(race_id)
pick_random_commander_type()
pick_random_empire_name_and_title()
pick_random_empire_suffix()
pick_random_last_name(race_id)
pick_random_shipyard_name(race_id)
promote_commander(orig_rank, new_rank, commander_type)
promote_commanders(race_id, commander_type)
recalc_fleet_speed(fleet_id)
refit_ship(ship_id, class_id, pop_id, opt = {})
refresh_galactic_map()
refresh_system_map()
refresh_task_force_bonuses(task_force_id)
reload_from_colony(fleet_id, pop_id, ship_id = NONE)
reload_from_ships(reload_ships, ammo_ships, override_loadout = null)
roman_numeral(x)
sbgas_atm_changed(systembody_id)
scrap_ship(ship_id, pop_id, race_id)
shields_active(ship_id)
ship_is_in_nebula(ship_id)
show_industry_tab()
show_research_tab()
show_shipyards_tab()
split_fleet(fleet_id, new_fleet_name = null, is_detach = false, is_escort = false, copy_fleet_moves = true, new_task_force_id = NONE)
string_multiply(string, times, delimiter = "")
sum_column(rows, col_name)
sum_of_products(rows, col_name, col_name_2)
today_plus_days_str(days_Integer)
transfer_commanders(where, new_race_id)
transfer_knowledge(from_race_id, to_race_id, include_body_surveys = true, include_jp_data = true, system_id = null)
transfer_ordnance(src_fleet_id, dest_fleet_id, dest_ship_id = NONE, src_ship_id = NONE)
transfer_population(pop_id, new_race_id, new_political_status)
transfer_ship(ship_id, alien_race_id, include_commander)
unassign_commander(commander, logging = true)
update_atmosphere(systembody_id)
update_pop_signatures(pop_id = null)
update_promotion_scores(commander_id = null)
update_ship_stats_in_db(ship_id)
valid_fleet_id(fleet_id, must_be_located_at_pop_id = NONE)
valid_ship_id(ship_id)
valid_systembody_id(systembody_id)
zoom_to_body_on_map(systembody_id, raise_window = false)
zoom_to_class(class_id, raise_window = false)
zoom_to_commander(commander_id, raise_window = false)
zoom_to_contact(contact_id, raise_window = false)
zoom_to_coordinates_on_map(coordinates, raise_window = false)
zoom_to_fleet(fleet_id, raise_window = false)
zoom_to_fleet_on_galactic_map(fleet_id)
zoom_to_fleet_on_map(fleet_id, raise_window = false)
zoom_to_pop(pop_id, raise_window = false, id_type = IDType.None)
zoom_to_ship(ship_id, raise_window = false)
zoom_to_star_on_map(star_d, raise_window = false)
zoom_to_system(system_id, raise_window = false)
zoom_to_system_on_galactic_map(system_id)
zoom_to_system_on_map(system_id, raise_window = false)


And here's another batch of functions I added to the default mod library: (so their implementations can be seen)
Off-Topic: show
add_title_to_commander_name(commander)
bell_rng(median, max_deviation)
calc_velocity(pos_x, pos_y, prev_pos_x, prev_pos_y, speed)
clamp_int(value, least, greatest)
clean_max_num_systems(txt)
clean_prod_time(txt)
colony_cost_to_string(col_cost)
color_to_int(c)
copy(from_dict, to_dict)
cth_int(zero_to_100)
days_hours_minutes(minutes)
default_blank(dict, key)
default_zero(dict, key)
distance_squared_xy(x1, y1, x2, y2)
distance_str(dist, additional_precision = 0)
enforce_newlines(string)
float_percent(a_float)
get_armor_value_from_msp(msp)
get_bearing(v)
get_energy_weapon_rate_of_fire(power_requirement, capacitor_recharge_rate)
get_fuel_consumption_per_eph(engine_power)
get_missile_fuel_consumption(engine_size)
get_name_and_rank(commander)
get_nice_text_color(bg_color)
greatest(a, b)
he_or_she(commander)
him_or_her(commander)
his_or_her(commander)
hours_minutes_seconds(seconds)
int_ceil(f)
int_floor(f)
int_percent(a_float)
int_round(f)
int_to_color(n)
intervals(array)
is_gas_body_type(body_type)
is_true(dict, key)
join(delimiter, arr)
least(a, b)
length(x, y)
length_squared(x, y)
make_hash_of_values(array_of_dict, key_field_name, value_field_name)
orbital_distance_to_km(orbital_distance, body_class)
pick_middle_of_three_rolls(num)
polar_distance(a, b)
radius_to_area(radius)
random_flag_pic()
random_loyalty()
random_race_pic()
ratio_to_cth_int(ratio)
roundf(f, precision)
safe_add(dict, key, amount)
safe_get(dict, key)
ship_class_unlocked(class_id)
to_xcor(distance_au, bearing_deg)
to_ycor(distance_au, bearing_deg)
volume_to_area(volume)
volume_to_radius(volume)


These are all documented in the script files.  I have not advanced the API version number because this doesn't break mods.  In general I am going to do my best not to break mods, and instead resolve any future issues in the API layer on my side.

This pretty much brings the API up to the point where it's now connected to every general purpose function I have conveniently lying around.  It needs a lot more higher-level functions useful to AI code that are much more directly related to what a human can do via the UI.  I'll be trying to finally write some precursor combat AI at the same time so I can get those finished up.

Right, so as I was saying in my last update, updates will come out much more slowly (I swear I mean it this time) as I am in an experimental phase of the project and also have C# to chew on.
 
The following users thanked this post: iceball3, El Pip, joansam, Lava

Offline Agm-114

  • Pulsar 4x Dev
  • Registered
  • Chief Petty Officer
  • ***
  • Posts: 31
  • Thanked: 11 times
  • Discord Username: AGM-114#7218
Re: Quasar4x - An early look at an Aurora4x clone in the works
« Reply #334 on: April 18, 2020, 02:34:26 AM »
Very cool.

This stuff will be great for my mp game.
 

Offline iceball3

  • Captain
  • **********
  • Posts: 424
  • Thanked: 38 times
Re: Quasar4x - An early look at an Aurora4x clone in the works
« Reply #335 on: April 18, 2020, 01:00:31 PM »
Hey Kyle, a request.
Would it be possible to have a UI element that launches when launching Quasar, perhaps running in it's own window in it's own thread outside of the game, to allow us to toggle autoturns? For example, whenever a turn completes, Quasar makes a check to see if the other window (or a text file it's responsible for or whatever) changed it's state to "stop the presses", and automatically stops auto-turns instead of continuing in an uninterruptible state? Even if it isn't even it's own UI, just a 1 line text file that can be edited by the user and is read every turn.
Quasar seems much harder, if not impossible to find the frame to disable auto-turns than vb6, and with the decreased stability, i'm worried about killing the game and corrupting the database in the process.
Edit: Actually, I'll take a look myself real quick and see if the modding API as is will allow for it as an addon.
« Last Edit: April 18, 2020, 01:02:23 PM by iceball3 »
 

Offline Kyle (OP)

  • Moderator
  • Lt. Commander
  • *****
  • K
  • Posts: 242
  • Thanked: 540 times
  • Quasar4x dev
Re: Quasar4x - An early look at an Aurora4x clone in the works
« Reply #336 on: April 18, 2020, 03:36:02 PM »
It's interruptable, you can click the Autoturns checkbox and it will become unchecked when the pulse completes
 

Offline iceball3

  • Captain
  • **********
  • Posts: 424
  • Thanked: 38 times
Re: Quasar4x - An early look at an Aurora4x clone in the works
« Reply #337 on: April 18, 2020, 04:52:50 PM »
It's interruptable, you can click the Autoturns checkbox and it will become unchecked when the pulse completes
The problem is that when turns take long enough, the entire full-game window becomes unresponsive, and it is not clear to the user side when the game will respect any clicks coming through.
VB6 Aurora had this issue too, but you could slip a click in just because the GUI would unfreeze for just enough frames between increments. But it definitely exacerbates as the increment times get longer. I suppose the hugely overloaded example game wasn't helping things, but for 30 second ticks, they take REALLY long.
 
The following users thanked this post: Kyle

Offline Kyle (OP)

  • Moderator
  • Lt. Commander
  • *****
  • K
  • Posts: 242
  • Thanked: 540 times
  • Quasar4x dev
Re: Quasar4x - An early look at an Aurora4x clone in the works
« Reply #338 on: April 18, 2020, 08:09:58 PM »
Ah, I haven't checked a game that size in awhile.  Yeah, it's gotten unacceptably slow.  I'll have to do an optimization pass.
 

Offline Kyle (OP)

  • Moderator
  • Lt. Commander
  • *****
  • K
  • Posts: 242
  • Thanked: 540 times
  • Quasar4x dev
Re: Quasar4x - An early look at an Aurora4x clone in the works
« Reply #339 on: April 22, 2020, 10:46:42 PM »
Progress update 2020-04-22:

Another boring but important update. Version 110 is up, and includes optimizations that greatly speed up turn processing times.  On my computer, the example game took 10.328 seconds to process a 2 minute turn.  Granted, the example game is deceptively overloaded.  It includes 2 NPRs each with many Civilian ships.  NPRs / Civilians aren't implemented, but they all have move orders left over from the import from my VB6 game, and they all still have detection.

Nevertheless I was able to bring the processing time on the same snapshot down from 10328 milliseconds to 892 milliseconds.  A 91% reduction in processing time!  Migrating the core of the movement phase to C++ accounted for about 4 seconds of this speed boost.  I saved another 3-4 seconds by changing detection to query the most common signature and detector types for all systems at once instead of doing them one system at a time, and sorting them by system only after the initial query.  I bought another 1-2 seconds from fixing a nasty bug with NPR default orders.  And the remainder was from a few miscellaneous improvements. 

What's nice is I still have significant room for more optimization.  I have yet to add any code that would skip sensor checks in systems for which there is only one race present, for example.  I prefer to leave those kinds of optimizations for last so they don't hide the more subtle problems.  And I saw many other areas that could use optimization whenever I want to invest my time into working on them.  But I'm super happy with a 91% turn time reduction at this phase of the project, so it's time to move on!

As an aside, the game engine does support "yielding" meaning at some point down the road I can add a progress bar and eliminate window lockups.

This version also fixes instability that was occurring when the the auto-backup setting was enabled, as well as a crash-on-start issue on Linux.  Unless something else comes up, precursor moving and shooting (via API) is back at the top of the list!

Kyle

 
The following users thanked this post: froggiest1982, Demonides, MinuteMan, iceball3, El Pip, tws029, joansam, Lava

Offline joansam

  • Petty Officer
  • **
  • j
  • Posts: 18
  • Thanked: 18 times
Re: Quasar4x - An early look at an Aurora4x clone in the works
« Reply #340 on: April 23, 2020, 11:42:45 AM »
Very exciting! Glad there’s still room for optimization, and really looking forward to NPR behaviors.
 
The following users thanked this post: Kyle

Offline froggiest1982

  • Captain
  • **********
  • f
  • Posts: 499
  • Thanked: 122 times
Re: Quasar4x - An early look at an Aurora4x clone in the works
« Reply #341 on: May 11, 2020, 07:35:29 PM »
Progress update 2020-04-22:

Another boring but important update. Version 110 is up, and includes optimizations that greatly speed up turn processing times.  On my computer, the example game took 10.328 seconds to process a 2 minute turn.  Granted, the example game is deceptively overloaded.  It includes 2 NPRs each with many Civilian ships.  NPRs / Civilians aren't implemented, but they all have move orders left over from the import from my VB6 game, and they all still have detection.

Nevertheless I was able to bring the processing time on the same snapshot down from 10328 milliseconds to 892 milliseconds.  A 91% reduction in processing time!  Migrating the core of the movement phase to C++ accounted for about 4 seconds of this speed boost.  I saved another 3-4 seconds by changing detection to query the most common signature and detector types for all systems at once instead of doing them one system at a time, and sorting them by system only after the initial query.  I bought another 1-2 seconds from fixing a nasty bug with NPR default orders.  And the remainder was from a few miscellaneous improvements. 

What's nice is I still have significant room for more optimization.  I have yet to add any code that would skip sensor checks in systems for which there is only one race present, for example.  I prefer to leave those kinds of optimizations for last so they don't hide the more subtle problems.  And I saw many other areas that could use optimization whenever I want to invest my time into working on them.  But I'm super happy with a 91% turn time reduction at this phase of the project, so it's time to move on!

As an aside, the game engine does support "yielding" meaning at some point down the road I can add a progress bar and eliminate window lockups.

This version also fixes instability that was occurring when the the auto-backup setting was enabled, as well as a crash-on-start issue on Linux.  Unless something else comes up, precursor moving and shooting (via API) is back at the top of the list!

Kyle

keep up the good work Kyle!

Offline TMaekler

  • Commodore
  • **********
  • Posts: 704
  • Thanked: 131 times
Re: Quasar4x - An early look at an Aurora4x clone in the works
« Reply #342 on: July 10, 2020, 12:04:54 AM »
Hi Kyle, you have immersed yourself into C# Aurora or are using the time to silently finish Quasar?  ;)

I have seen that there is also a version for Mac; though a bit old... you plan to update that at some point?
« Last Edit: July 10, 2020, 12:06:25 AM by TMaekler »
 
The following users thanked this post: Gabrote42

Offline Kyle (OP)

  • Moderator
  • Lt. Commander
  • *****
  • K
  • Posts: 242
  • Thanked: 540 times
  • Quasar4x dev
Re: Quasar4x - An early look at an Aurora4x clone in the works
« Reply #343 on: July 16, 2020, 10:49:29 PM »
Neither.. I started on C# a couple times but each time learned of a game breaking bug that made my run useless. After that, I honestly just lost interest in playing it.  And now that C# is out and people have that to chew on if they want an aurora-like game to play, myself included, I lost enthusiasm for Quasar.  It's still the programming project on my "hobby table" though -- I do plan to start back in on it at some point.

And yes, it can easily be built for Mac, I was just skipping mac builds to save time.
 

 

Sitemap 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72