Merge branch 'samual/weapons' into Mario/weapons
authorMario <zacjardine@y7mail.com>
Thu, 6 Nov 2014 06:55:52 +0000 (17:55 +1100)
committerMario <zacjardine@y7mail.com>
Thu, 6 Nov 2014 06:55:52 +0000 (17:55 +1100)
1  2 
qcsrc/client/autocvars.qh
qcsrc/client/hud.qc
qcsrc/client/miscfunctions.qc
qcsrc/server/t_items.qc
qcsrc/server/t_items.qh

@@@ -269,6 -269,7 +269,7 @@@ float autocvar_hud_panel_notify_fadetim
  float autocvar_hud_panel_notify_flip;
  float autocvar_hud_panel_notify_fontsize;
  float autocvar_hud_panel_notify_time;
+ float autocvar_hud_panel_notify_icon_aspect;
  float autocvar_hud_panel_physics;
  float autocvar_hud_panel_physics_acceleration_progressbar_mode;
  float autocvar_hud_panel_physics_acceleration_progressbar_scale;
@@@ -322,7 -323,6 +323,7 @@@ float autocvar_hud_panel_weapons_ammo
  float autocvar_hud_panel_weapons_ammo_alpha;
  string autocvar_hud_panel_weapons_ammo_color;
  float autocvar_hud_panel_weapons_ammo_full_cells;
 +float autocvar_hud_panel_weapons_ammo_full_plasma;
  float autocvar_hud_panel_weapons_ammo_full_fuel;
  float autocvar_hud_panel_weapons_ammo_full_nails;
  float autocvar_hud_panel_weapons_ammo_full_rockets;
diff --combined qcsrc/client/hud.qc
@@@ -762,7 -762,6 +762,7 @@@ void HUD_Weapons(void
                                                case ammo_nails:   ammo_full = autocvar_hud_panel_weapons_ammo_full_nails;   break;
                                                case ammo_rockets: ammo_full = autocvar_hud_panel_weapons_ammo_full_rockets; break;
                                                case ammo_cells:   ammo_full = autocvar_hud_panel_weapons_ammo_full_cells;   break;
 +                                              case ammo_plasma:  ammo_full = autocvar_hud_panel_weapons_ammo_full_plasma;  break;
                                                case ammo_fuel:    ammo_full = autocvar_hud_panel_weapons_ammo_full_fuel;    break;
                                                default: ammo_full = 60;
                                        }
@@@ -925,7 -924,7 +925,7 @@@ void HUD_Ammo(void
                mySize -= '2 2 0' * panel_bg_padding;
        }
  
 -      const float AMMO_COUNT = 4;
 +      const float AMMO_COUNT = 5;
        float rows = 0, columns, row, column;
        vector ammo_size;
        if(autocvar_hud_panel_ammo_onlycurrent)
@@@ -1562,148 -1561,154 +1562,154 @@@ void HUD_HealthArmor(void
  
  void HUD_Notify_Push(string icon, string attacker, string victim)
  {
-       if(icon != "")
-       {
-               --kn_index;
-               if (kn_index == -1) { kn_index = KN_MAX_ENTRIES-1; }
-               notify_times[kn_index] = time;
+       if (icon == "")
+               return;
+       ++notify_count;
+       --notify_index;
+       if (notify_index == -1)
+               notify_index = NOTIFY_MAX_ENTRIES-1;
+       // Free old strings
+       if (notify_attackers[notify_index])
+               strunzone(notify_attackers[notify_index]);
  
-               // icon
-               if(notify_icon[kn_index]) { strunzone(notify_icon[kn_index]); }
-               notify_icon[kn_index] = strzone(icon);
+       if (notify_victims[notify_index])
+               strunzone(notify_victims[notify_index]);
  
-               // attacker
-               if(notify_attackers[kn_index]) { strunzone(notify_attackers[kn_index]); }
-               notify_attackers[kn_index] = strzone(attacker);
+       if (notify_icons[notify_index])
+               strunzone(notify_icons[notify_index]);
  
-               // victim
-               if(notify_victims[kn_index]) { strunzone(notify_victims[kn_index]); }
-               notify_victims[kn_index] = strzone(victim);
+       // Allocate new strings
+       if (victim != "")
+       {
+               notify_attackers[notify_index] = strzone(attacker);
+               notify_victims[notify_index] = strzone(victim);
        }
+       else
+       {
+               // In case of a notification without a victim, the attacker
+               // is displayed on the victim's side. Instead of special
+               // treatment later on, we can simply switch them here.
+               notify_attackers[notify_index] = string_null;
+               notify_victims[notify_index] = strzone(attacker);
+       }
+       notify_icons[notify_index] = strzone(icon);
+       notify_times[notify_index] = time;
  }
  
  void HUD_Notify(void)
  {
-       if(!autocvar__hud_configure)
-       {
-               if(!autocvar_hud_panel_notify) return;
-       }
+       if (!autocvar__hud_configure)
+               if (!autocvar_hud_panel_notify)
+                       return;
  
        HUD_Panel_UpdateCvars();
-       vector pos, mySize;
-       pos = panel_pos;
-       mySize = panel_size;
        HUD_Panel_DrawBg(1);
-       if(panel_bg_padding)
+       if (!autocvar__hud_configure)
+               if (notify_count == 0)
+                       return;
+       vector pos, size;
+       pos  = panel_pos;
+       size = panel_size;
+       if (panel_bg_padding)
        {
-               pos += '1 1 0' * panel_bg_padding;
-               mySize -= '2 2 0' * panel_bg_padding;
+               pos  += '1 1 0' * panel_bg_padding;
+               size -= '2 2 0' * panel_bg_padding;
        }
  
-       float entries, height;
-       entries = bound(1, floor(KN_MAX_ENTRIES * mySize_y/mySize_x), KN_MAX_ENTRIES);
-       height = mySize_y/entries;
+       float fade_start = max(0, autocvar_hud_panel_notify_time);
+       float fade_time = max(0, autocvar_hud_panel_notify_fadetime);
+       float icon_aspect = max(1, autocvar_hud_panel_notify_icon_aspect);
+       float entry_count = bound(1, floor(NOTIFY_MAX_ENTRIES * size_y / size_x), NOTIFY_MAX_ENTRIES);
+       float entry_height = size_y / entry_count;
  
-       vector fontsize;
-       float fontheight = height * autocvar_hud_panel_notify_fontsize;
-       fontsize = '0.5 0.5 0' * fontheight;
+       float panel_width_half = size_x * 0.5;
+       float icon_width_half = entry_height * icon_aspect / 2;
+       float name_maxwidth = panel_width_half - icon_width_half - size_x * NOTIFY_ICON_MARGIN;
  
-       float a;
-       float when;
-       when = autocvar_hud_panel_notify_time;
-       float fadetime;
-       fadetime = autocvar_hud_panel_notify_fadetime;
+       vector font_size = '0.5 0.5 0' * entry_height * autocvar_hud_panel_notify_fontsize;
+       vector icon_size = (eX * icon_aspect + eY) * entry_height;
+       vector icon_left = eX * (panel_width_half - icon_width_half);
+       vector attacker_right = eX * name_maxwidth;
+       vector victim_left = eX * (size_x - name_maxwidth);
  
-       vector pos_attacker, pos_victim, pos_icon;
-       float width_attacker;
+       vector attacker_pos, victim_pos, icon_pos;
        string attacker, victim, icon;
+       float i, j, count, step, limit, alpha;
  
-       float i, j, step, limit;
-       if(autocvar_hud_panel_notify_flip) //order items from the top down
+       if (autocvar_hud_panel_notify_flip)
        {
+               // Order items from the top down
                i = 0;
                step = +1;
-               limit = entries;
+               limit = entry_count;
        }
-       else //order items from the bottom up
+       else
        {
-               i = entries - 1;
+               // Order items from the bottom up
+               i = entry_count - 1;
                step = -1;
                limit = -1;
        }
  
-       for(j = kn_index;  i != limit;  i += step, ++j)
+       for (j = notify_index, count = 0; i != limit; i += step, ++j, ++count)
        {
                if(autocvar__hud_configure)
                {
-                       if (step == +1)
-                               a = i;
-                       else // inverse order
-                               a = entries - 1 - i;
-                       attacker = textShortenToWidth(sprintf(_("Player %d"), a+1), 0.48 * mySize_x - height, fontsize, stringwidth_colors);
-                       victim = textShortenToWidth(sprintf(_("Player %d"), a+2), 0.48 * mySize_x - height, fontsize, stringwidth_colors);
-                       icon = get_weaponinfo(WEP_FIRST + mod(floor(a*2.4), WEP_LAST)).model2;
-                       a = bound(0, (when - a) / 4, 1);
-                       goto hud_config_notifyprint;
+                       attacker = sprintf(_("Player %d"), count + 1);
+                       victim = sprintf(_("Player %d"), count + 2);
+                       icon = get_weaponinfo(min(WEP_FIRST + count * 2, WEP_LAST)).model2;
+                       alpha = bound(0, 1.2 - count / entry_count, 1);
                }
                else
                {
-                       if (j == KN_MAX_ENTRIES)
+                       if (j == NOTIFY_MAX_ENTRIES)
                                j = 0;
  
-                       if(notify_times[j] + when > time)
-                               a = 1;
-                       else if(fadetime)
+                       if (notify_times[j] + fade_start > time)
+                               alpha = 1;
+                       else if (fade_time != 0)
                        {
-                               a = bound(0, (notify_times[j] + when + fadetime - time) / fadetime, 1);
-                               if(!a)
-                               {
+                               alpha = bound(0, (notify_times[j] + fade_start + fade_time - time) / fade_time, 1);
+                               if (alpha == 0)
                                        break;
-                               }
                        }
                        else
-                       {
                                break;
-                       }
  
                        attacker = notify_attackers[j];
                        victim = notify_victims[j];
-                       icon = notify_icon[j];
+                       icon = notify_icons[j];
                }
  
-               //type = notify_deathtype[j];
-               //w = DEATH_WEAPONOF(type);
-               if(icon != "")
+               if (icon != "" && victim != "")
                {
-                       if((attacker != "") && (victim == ""))
-                       {
-                               // Y [used by] X
-                               attacker = textShortenToWidth(attacker, 0.73 * mySize_x - height, fontsize, stringwidth_colors);
-                               pos_attacker = pos + eX * (0.27 * mySize_x + height) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight)));
-                               pos_icon = pos + eX * 0.25 * mySize_x - eX * height + eY * i * height;
+                       vector name_top = eY * (i * entry_height + 0.5 * (entry_height - font_size_y));
  
-                               drawpic_aspect_skin(pos_icon, icon, '2 1 0' * height, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
-                               drawcolorcodedstring(pos_attacker, attacker, fontsize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
-                       }
-                       else if((attacker != "") && (victim != ""))
+                       icon_pos = pos + icon_left + eY * i * entry_height;
+                       drawpic_aspect_skin(icon_pos, icon, icon_size, '1 1 1', panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
+                       victim = textShortenToWidth(victim, name_maxwidth, font_size, stringwidth_colors);
+                       victim_pos = pos + victim_left + name_top;
+                       drawcolorcodedstring(victim_pos, victim, font_size, panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
+                       if (attacker != "")
                        {
-                               // X [did action to] Y
-                               attacker = textShortenToWidth(attacker, 0.48 * mySize_x - height, fontsize, stringwidth_colors);
-                               victim = textShortenToWidth(victim, 0.48 * mySize_x - height, fontsize, stringwidth_colors);
- :hud_config_notifyprint
-                               width_attacker = stringwidth(attacker, TRUE, fontsize);
-                               pos_attacker = pos + eX * (0.48 * mySize_x - height - width_attacker) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight)));
-                               pos_victim = pos + eX * (0.52 * mySize_x + height) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight)));
-                               pos_icon = pos + eX * 0.5 * mySize_x - eX * height + eY * i * height;
-                               drawpic_aspect_skin(pos_icon, icon, '2 1 0' * height, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
-                               drawcolorcodedstring(pos_attacker, attacker, fontsize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
-                               drawcolorcodedstring(pos_victim, victim, fontsize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+                               attacker = textShortenToWidth(attacker, name_maxwidth, font_size, stringwidth_colors);
+                               attacker_pos = pos + attacker_right - eX * stringwidth(attacker, TRUE, font_size) + name_top;
+                               drawcolorcodedstring(attacker_pos, attacker, font_size, panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
                        }
                }
        }
+       notify_count = count;
  }
  
  // Timer (#5)
@@@ -578,6 -578,20 +578,6 @@@ vector getplayerorigin(float pl
        return GETPLAYERORIGIN_ERROR;
  }
  
 -vector getcsqcplayercolor(float pl)
 -{
 -      entity e;
 -      
 -      e = CSQCModel_server2csqc(pl);
 -      if(e)
 -      {
 -              if(e.colormap > 0)
 -                      return colormapPaletteColor(((e.colormap >= 1024) ? e.colormap : stof(getplayerkeyvalue(e.colormap - 1, "colors"))) & 0x0F, TRUE);
 -      }
 -      
 -      return '1 1 1';
 -}
 -
  float getplayeralpha(float pl)
  {
        entity e;
        return 1;
  }
  
- vector getcsqcplayercolor(float pl)
- {
-       entity e;
-       e = CSQCModel_server2csqc(pl);
-       if(e)
-       {
-               if(e.colormap > 0)
-                       return colormapPaletteColor(((e.colormap >= 1024) ? e.colormap : stof(getplayerkeyvalue(e.colormap - 1, "colors"))) & 0x0F, TRUE);
-       }
-       return '1 1 1';
- }
  float getplayerisdead(float pl)
  {
        entity e;
diff --combined qcsrc/server/t_items.qc
@@@ -137,14 -137,14 +137,14 @@@ void ItemRead(float _IsNew
  
  
  
-             if(fexists(sprintf("%s%s.md3", _fn2, autocvr_cl_simpleitems_postfix)))
-                 self.mdl = strzone(sprintf("%s%s.md3", _fn2, autocvr_cl_simpleitems_postfix));
-             else if(fexists(sprintf("%s%s.dpm", _fn2, autocvr_cl_simpleitems_postfix)))
-                 self.mdl = strzone(sprintf("%s%s.dpm", _fn2, autocvr_cl_simpleitems_postfix));
-             else if(fexists(sprintf("%s%s.iqm", _fn2, autocvr_cl_simpleitems_postfix)))
-                 self.mdl = strzone(sprintf("%s%s.iqm", _fn2, autocvr_cl_simpleitems_postfix));
-             else if(fexists(sprintf("%s%s.obj", _fn2, autocvr_cl_simpleitems_postfix)))
-                 self.mdl = strzone(sprintf("%s%s.obj", _fn2, autocvr_cl_simpleitems_postfix));
+             if(fexists(sprintf("%s%s.md3", _fn2, autocvar_cl_simpleitems_postfix)))
+                 self.mdl = strzone(sprintf("%s%s.md3", _fn2, autocvar_cl_simpleitems_postfix));
+             else if(fexists(sprintf("%s%s.dpm", _fn2, autocvar_cl_simpleitems_postfix)))
+                 self.mdl = strzone(sprintf("%s%s.dpm", _fn2, autocvar_cl_simpleitems_postfix));
+             else if(fexists(sprintf("%s%s.iqm", _fn2, autocvar_cl_simpleitems_postfix)))
+                 self.mdl = strzone(sprintf("%s%s.iqm", _fn2, autocvar_cl_simpleitems_postfix));
+             else if(fexists(sprintf("%s%s.obj", _fn2, autocvar_cl_simpleitems_postfix)))
+                 self.mdl = strzone(sprintf("%s%s.obj", _fn2, autocvar_cl_simpleitems_postfix));
              else
              {
                  self.draw = ItemDraw;
@@@ -573,7 -573,6 +573,7 @@@ float Item_GiveTo(entity item, entity p
        pickedup |= Item_GiveAmmoTo(item, player, ammo_nails, g_pickup_nails_max, ITEM_MODE_NONE);
        pickedup |= Item_GiveAmmoTo(item, player, ammo_rockets, g_pickup_rockets_max, ITEM_MODE_NONE);
        pickedup |= Item_GiveAmmoTo(item, player, ammo_cells, g_pickup_cells_max, ITEM_MODE_NONE);
 +      pickedup |= Item_GiveAmmoTo(item, player, ammo_plasma, g_pickup_plasma_max, ITEM_MODE_NONE);
        pickedup |= Item_GiveAmmoTo(item, player, health, item.max_health, ITEM_MODE_HEALTH);
        pickedup |= Item_GiveAmmoTo(item, player, armorvalue, item.max_armorvalue, ITEM_MODE_ARMOR);
  
@@@ -784,7 -783,7 +784,7 @@@ float weapon_pickupevalfunc(entity play
                // If I can pick it up
                if(!item.spawnshieldtime)
                        c = 0;
 -              else if(player.ammo_cells || player.ammo_shells || player.ammo_nails || player.ammo_rockets)
 +              else if(player.ammo_cells || player.ammo_shells || player.ammo_plasma || player.ammo_nails || player.ammo_rockets)
                {
                        // Skilled bots will grab more
                        c = bound(0, skill / 10, 1) * 0.5;
  float commodity_pickupevalfunc(entity player, entity item)
  {
        float c, i;
 -      float need_shells = FALSE, need_nails = FALSE, need_rockets = FALSE, need_cells = FALSE, need_fuel = FALSE;
 +      float need_shells = FALSE, need_nails = FALSE, need_rockets = FALSE, need_cells = FALSE, need_plasma = FALSE, need_fuel = FALSE;
        entity wi;
        c = 0;
  
                        need_rockets = TRUE;
                else if(wi.items & IT_CELLS)
                        need_cells = TRUE;
 +              else if(wi.items & IT_PLASMA)
 +                      need_plasma = TRUE;
                else if(wi.items & IT_FUEL)
                        need_cells = TRUE;
        }
        if (item.ammo_cells)
        if (player.ammo_cells < g_pickup_cells_max)
                c = c + max(0, 1 - player.ammo_cells / g_pickup_cells_max);
 +      if (need_plasma)
 +      if (item.ammo_plasma)
 +      if (player.ammo_plasma < g_pickup_plasma_max)
 +              c = c + max(0, 1 - player.ammo_plasma / g_pickup_plasma_max);
        if (need_fuel)
        if (item.ammo_fuel)
        if (player.ammo_fuel < g_pickup_fuel_max)
@@@ -1152,15 -1145,6 +1152,15 @@@ void spawnfunc_item_cells (void) 
        StartItem ("models/items/a_cells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "cells", IT_CELLS, 0, 0, commodity_pickupevalfunc, 2000);
  }
  
 +void spawnfunc_item_plasma()
 +{
 +      if(!self.ammo_plasma)
 +              self.ammo_plasma = g_pickup_plasma;
 +      if(!self.pickup_anyway)
 +              self.pickup_anyway = g_pickup_ammo_anyway;
 +      StartItem ("models/items/a_cells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "plasma", IT_PLASMA, 0, 0, commodity_pickupevalfunc, 2000);
 +}
 +
  void spawnfunc_item_shells (void) {
        if(!weaponswapping)
        if(autocvar_sv_q3acompat_machineshotgunswap)
@@@ -1403,7 -1387,6 +1403,7 @@@ void spawnfunc_target_items (void
                if(self.ammo_nails != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_nails), "nails");
                if(self.ammo_rockets != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_rockets), "rockets");
                if(self.ammo_cells != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_cells), "cells");
 +              if(self.ammo_plasma != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_plasma), "plasma");
                if(self.ammo_fuel != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_fuel), "fuel");
                if(self.health != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.health), "health");
                if(self.armorvalue != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.health), "armor");
@@@ -1602,7 -1585,6 +1602,7 @@@ float GiveItems(entity e, float beginar
        PREGIVE(e, superweapons_finished);
        PREGIVE(e, ammo_nails);
        PREGIVE(e, ammo_cells);
 +      PREGIVE(e, ammo_plasma);
        PREGIVE(e, ammo_shells);
        PREGIVE(e, ammo_rockets);
        PREGIVE(e, ammo_fuel);
                                }
                        case "allammo":
                                got += GiveValue(e, ammo_cells, op, val);
 +                              got += GiveValue(e, ammo_plasma, op, val);
                                got += GiveValue(e, ammo_shells, op, val);
                                got += GiveValue(e, ammo_nails, op, val);
                                got += GiveValue(e, ammo_rockets, op, val);
                        case "cells":
                                got += GiveValue(e, ammo_cells, op, val);
                                break;
 +                      case "plasma":
 +                              got += GiveValue(e, ammo_plasma, op, val);
 +                              break;
                        case "shells":
                                got += GiveValue(e, ammo_shells, op, val);
                                break;
        POSTGIVE_VALUE(e, invincible_finished, 1, "misc/powerup_shield.wav", "misc/poweroff.wav");
        POSTGIVE_VALUE(e, ammo_nails, 0, "misc/itempickup.wav", string_null);
        POSTGIVE_VALUE(e, ammo_cells, 0, "misc/itempickup.wav", string_null);
 +      POSTGIVE_VALUE(e, ammo_plasma, 0, "misc/itempickup.wav", string_null);
        POSTGIVE_VALUE(e, ammo_shells, 0, "misc/itempickup.wav", string_null);
        POSTGIVE_VALUE(e, ammo_rockets, 0, "misc/itempickup.wav", string_null);
        POSTGIVE_VALUE_ROT(e, ammo_fuel, 1, pauserotfuel_finished, autocvar_g_balance_pause_fuel_rot, pauseregen_finished, autocvar_g_balance_pause_fuel_regen, "misc/itempickup.wav", string_null);
diff --combined qcsrc/server/t_items.qh
@@@ -16,7 -16,6 +16,7 @@@ const      float IT_SUPERWEAPO
  const      float IT_STRENGTH                  =    8192;
  const      float IT_INVINCIBLE                =   16384;
  const      float IT_HEALTH                    =   32768;
 +const      float IT_PLASMA                    =   65536;
  
  // shared value space (union):
        // for items:
@@@ -37,7 -36,7 +37,7 @@@ const      float IT_ARMOR_SHAR
  const      float IT_ARMOR                     = 4194304;
  
  // item masks
 -const      float IT_AMMO                      =    3968; // IT_FUEL | IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS;
 +const      float IT_AMMO                      =    3968; // IT_FUEL | IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS | IT_PLASMA;
  const      float IT_PICKUPMASK                =      51; // IT_FUEL_REGEN | IT_JETPACK | IT_UNLIMITED_AMMO; // strength and invincible are handled separately
  const      float IT_UNLIMITED_AMMO            =       3; // IT_UNLIMITED_SUPERWEAPONS | IT_UNLIMITED_WEAPON_AMMO;
  
@@@ -70,7 -69,7 +70,7 @@@ var float  autocvar_cl_fullbright_item
  var vector autocvar_cl_weapon_stay_color = '2 0.5 0.5';
  var float  autocvar_cl_weapon_stay_alpha = 0.75;
  var float  autocvar_cl_simple_items = 0;
- var string autocvr_cl_simpleitems_postfix = "_simple";
+ var string autocvar_cl_simpleitems_postfix = "_simple";
  .float  spawntime;
  .float  gravity;
  .vector colormod;